Skip to content

Migration guide v6.7.0

Olivier Perrin edited this page May 6, 2025 · 29 revisions

Breaking Change Breaking changes for all users

UCTE

New UCTE naming strategy

If you have a custom UCTE naming strategy (i.e. a class implementing com.powsybl.ucte.converter.NamingStrategy), you should implement the following method:

  • void initializeNetwork(Network network);

By default, the "Default" naming strategy is used when exporting a network in UCTE. If you want to use the new naming strategy, you should define the following property in your configuration:
  • ucte.export.naming-strategy: Counter

CGMES

Replacing CGMES.switchType property

Any access to the CGMES.switchType property should be replaced with CGMES.originalClass property. For instance:

String cgmesSwitchType = network.getSwitch("someSwitchUUID").getProperty("CGMES.switchType");

should be replaced by:

String cgmesSwitchType = network.getSwitch("someSwitchUUID").getProperty(Conversion.PROPERTY_CGMES_ORIGINAL_CLASS);

Similarly, any network saved to a serialized IIDM file should be updated by replacing all occurences of CGMES.switchType with CGMES.originalClass property, in case the network needs to be exported to CGMES and the original CGMES switch types are needed. You could do this with following code:

for (Switch s : network.getSwitches()) {
    String cgmesSwitchType = s.getProperty("CGMES.switchType");
    if (cgmesSwitchType != null) {
        s.setProperty("CGMES.originalClass", cgmesSwitchType);
    }
}

Cgmes control areas

Import

During import, CGMES control areas (objects of class ControlArea) are now mapped directly to PowSyBl objects of type Area. Here is a correspondance table to access to the control area data:

Data Previously Now
Location CgmesControlArea extension IIDM Area of type CgmesNames.CONTROL_AREA_TYPE_KIND_INTERCHANGE
ID extension.getId() area.getId()
Name extension.getName() area.getName()
Net interchange extension.getNetInterchange() area.getInterchangeTarget()
.orElse(Double.NaN)
P tolerance extension.getPTolerance() Double.parseDouble(area.getProperty(CgmesNames.P_TOLERANCE, "NaN")
energyIdentCodeEic extension.getEnergyIdentificationCodeEIC() area.getAliasFromType(CgmesNames.ENERGY_IDENT_CODE_EIC)
.orElse(null)
Terminals extension.getTerminals() area.getAreaBoundaryStream()
.map(AreaBoundary::getTerminal)
.filter(Optional::isPresent)
.map(Optional::get)
.toSet()
Boundaries extension.getBoundaries() area.getAreaBoundaryStream()
.map(AreaBoundary::getBoundary)
.filter(Optional::isPresent)
.map(Optional::get)
.toSet()

Export

Previously, during export, if the CgmesControlArea extension was not present in the exported network, a new one was created and a control area representing the whole network was added to it, with the terminals of all dangling lines defined as its tie flows. As a result, the CGMES export always had a control area of type interchange.

After this PR, no control area is automatically created during export. The export process itself will not add, remove or change the attributes of the objects in the IIDM model.

If the user wants to define a control area interchange based on the whole network, it can do it programmatically using the following line of code:

new CgmesExport().createDefaultControlAreaInterchange(network);

It is located in the CgmesExport exporter because the creation of a default area involves potential access to reference data (boundaries) and using some export parameters that the user may have already configured. The relevant data: the sourcing actor (that determines its region and the corresponding EIC code), the consideration of boundary nodes (and associated tie flows) as AC or DC. Also, the user can provide some of the parameters explicitly, if needed. As an example, including the final call to CGMES export:

Properties exportParams = new Properties();
exportParams.put(CgmesImport.BOUNDARY_LOCATION, "....");
exportParams.put(CgmesExport.NAMING_STRATEGY, NamingStrategyFactory.CGMES);

new CgmesExport().createDefaultControlAreaInterchange(network, exportParams);
network.write("CGMES", exportParams, outputPath);

Mixed topology export

In case of a network with mixed topology, that is with some VoltageLevel in node/breaker topology kind and some other VoltageLevel in bus/breaker topology kind, the CGMES export was always a NODE_BREAKER one in the previous PowSyBl versions.

The export is now a BUS_BRANCH one if the CIM version for export is 16 (default value).

In order to restore a NODE_BREAKER export for a mixed-topology network, one has to set the TOPOLOGY_KIND CgmesExport parameter as follows:

Network network = ...;

// Export to CGMES as node-breaker
Properties exportParameters = new Properties();
exportParameters.put(CgmesExport.TOPOLOGY_KIND, "NODE_BREAKER");
network.write("CGMES", exportParameters, Path.of("cgmes_file")); 

Refactor grouped queries

Methods removed from CgmesModel:

  • Map<String, PropertyBags> groupedTransformerEnds()
  • List<String> ratioTapChangerListForPowerTransformer(String powerTransformerId)
  • PropertyBags ratioTapChangerTable(String tableId)
  • List<String> phaseTapChangerListForPowerTransformer(String powerTransformerId)
  • PropertyBags phaseTapChangerTable(String tableId)
  • PropertyBags nonlinearShuntCompensatorPoints(String shuntId)

Have been replaced by these methodes in Context:

  • public PropertyBags transformerEnds(String transformerId)
  • public PropertyBags ratioTapChangers(String transformerId)
  • public PropertyBags ratioTapChangerTablePoints(String tableId)
  • public PropertyBags phaseTapChangers(String transformerId)
  • public PropertyBags phaseTapChangerTablePoints(String tableId)
  • public PropertyBags nonlinearShuntCompensatorPoints(String shuntId)

Also, in CgmesModel, the following methods have been renamed for more consistency:

  • ratioTapChangerTablesPoints() into ratioTapChangerTablePoints()
  • phaseTapChangerTablesPoints() into phaseTapChangerTablePoints()

CgmesNamespace.Cim interface refactoring

If you are calling one of the following methods of CgmesNamespace.Cim, you must replace it by:

Previously Now
getLimitTypeAttributeName() getLimitTypeAttributeName()
in OperationalLimitTypeEq class
of com.powsybl.cgmes.conversion.export.elements package
getLimitKindClassName() getLimitKindClassName()
in OperationalLimitTypeEq class
of com.powsybl.cgmes.conversion.export.elements package
getLimitValueAttributeName() getLimitValueAttributeName()
in LoadingLimitEq class
of com.powsybl.cgmes.conversion.export.elements package
writeConnectivityNodes() getVersion() == 100
writeGeneratingUnitInitialP() getVersion() == 16
writeLimitInfiniteDuration() getVersion() == 100
writeTculControlMode() getVersion() <= 16

Unit tests refactoring

The following methods of CgmesConformity1ModifiedCatalog, were removed:

  • miniNodeBreakerLoadBreakSwitch()
  • miniNodeBreakerProtectedSwitch()
  • miniNodeBreakerInternalLineZ0()
  • miniNodeBreakerTerminalDisconnected()
  • microGridBaseCaseNLSwitchWithoutName()
  • microGridBaseCaseNLSwitchTypePreserved()
  • miniGridNodeBreakerSwitchTypePreserved()
  • microGridBaseCaseBEUndefinedPatl()
  • microGridBaseCaseBELimits()
  • microGridBaseCaseBEMissingLimitValue()
  • miniNodeBreakerLimitsforEquipment()

They were used for unit testing, but they relied on big CGMES files ; this slowed the tests execution. If you still need to use them, you can retrieve the methods at this URL and the corresponding CGMES files in this directory.

Commons

TreeDataReader

TreeDataReader.skipChildNodes() was renamed into TreeDataReader.skipNode(). It now skip the whole node and not only the children nodes (therefore, attributes are also skipped).

Users which added their own implementation of TreeDataReader (for instance for a custom serialization format) need to rename the skipChildNodes method into skipNode. They also need to take care of skipping the whole node in this method, and not only skipping the children nodes.

Report node V3 for i18n

The third version of the report node API introduces a mechanism for internationalizing messages (i18n).

For all users

When creating a new ReportNode root, the i18n bundles should be loaded. You can either:

  1. Use the new ReportNode.newRootReportNode().withResourceBundles(String... bundleBaseNames) method, if you want to use specific bundles,
  2. Or call ReportNode.newRootReportNode().withAllResourceBundlesFromClasspath(), if you want to use all the bundles present in your classpath.

If you choose to specify the bundle names (first option), you have to use the following names for powsybl-core messages:

  • PowsyblCoreReportResourceBundle.BASE_NAME for the production messages;
  • PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME for the test messages;

To internationalize your project/library's logs

This step is not required for now, but it will be in a future version, when the deprecated withMessageTemplate(key, messageTemplate) will be removed.

First of all, take a look at the user documentation to have a big picture of the functionality and at its good practices.

Then, you can apply the following migration steps:

  • All the message templates (see your calls to ReportNodeBuilder#withMessageTemplate(key, messageTemplate)) should be moved to a single ResourceBundle for each repository. Scripts which help doing the extraction were added to powsybl-dev-tools.
  • Replace calls to withMessageTemplate(key, messageTemplate) with calls to withMessageTemplate(key).
  • To make your resource bundle easily available to the user, please add an implementation of ReportResourceBundle marked as a service (you can take inspiration from the powsybl-core service.
  • If your project use the "maven-resources-plugin" filtering option, you should consider excluding the i18n resource bundle files from its processing, or some of the defined template variables may be replaced by the maven plugin. This can be achieved by defining a specific resource directory for the files which should be processed.
  • Finally, for the other PowSyBl repositories, translation into french is expected - please request for help if needed!

ReportNode timestamp feature

Timestamps can not be automatically added on a whole ReportNode tree. If timestamp is needed on a specific ReportNode, the user has to add it explicitly with a call to withTimestamp() or withTimestamp(pattern), and to refer to it in the message template if it should be displayed to the end user.

The TimestampPattern and the Locale used are specified at the construction of the root ReportNode, but separately. Hence, you need to replace the use of withTimestampPattern(String pattern, Locale locale) with withDefaultTimestampPattern(String pattern).withLocale(Locale locale). Finally, you should replace the use of withTimestampPattern(String pattern) with withDefaultTimestampPattern(String pattern).

Time series

Time series in nanoseconds

The interface TimeSeriesIndex has new methods that you have to implement, should you implement this interface:

  • void writeJson(JsonGenerator generator, TimeSeries.TimeFormat format)
  • String toJson(TimeSeries.TimeFormat format)

Following the change of underlying date-time variable format (from long to Instant), the TimeSeriesIndex.toJson and TimeSeriesIndex.writeJson exported formats have been changed to allow nano-second precision while keeping the backward compatibility, thanks to a new enum TimeSeriesIndex.ExportFormat:

  • Old format that will still be used when timeFormat = TimeSeriesIndex.ExportFormat.MILLISECONDS (default value) for backward compatibility:
{
  "startTime" : 1420070400000,
  "endTime" : 1420074000000,
  "spacing" : 900000
}
  • New format that will be used when timeFormat = TimeSeriesIndex.ExportFormat.NANOSECONDS:
{
  "startInstant" : 1420070400000000000,
  "endInstant" : 1420074000000000000,
  "timeStep" : 900000000000
}

Network modifications

Fixed throwException support

This is not really a breaking change, but the behavior of some NetworkModifications was changed starting from this version. They previously threw an Exception when a problem was encountered in their apply(...) method, even with throwException set to false (which was obviously a mistake). Now they only throw an Exception when throwException is set to true. These network modifications are:

  • every modification extending AbstractTripping (i.e. network modification classes named XxxTripping)
  • CloseSwitch
  • ConnectGenerator
  • OpenSwitch
  • PhaseShifterOptimizeTap
  • PhaseShifterSetAsFixedTap
  • PhaseShifterShiftTap
  • ShuntCompensatorModification

Groovy scripts

GroovyScriptExtension.load change

Classes implementing GroovyScriptExtension have to change their method void load(Binding binding, ComputationManager computationManager) to void load(Binding binding, Map<Class<?>, Object> contextObjects) If the computationManager was used inside, it now has to be found in the map. See for example how the LoadFlowGroovyScriptExtension changes from:

   @Override
    void load(Binding binding, ComputationManager computationManager) {
        binding.loadFlow = { Network network, LoadFlowParameters parameters = this.parameters ->
            LoadFlow.run(network, network.getVariantManager().getWorkingVariantId(), computationManager, parameters)
        }
        binding.loadflow = { Network network, LoadFlowParameters parameters = this.parameters ->
            LoadFlow.run(network, network.getVariantManager().getWorkingVariantId(), computationManager, parameters)
        }
    }

to:

    @Override
    void load(Binding binding, Map<Class<?>, Object> contextObjects) {
        if (contextObjects.keySet().contains(ComputationManager.class)) {
            ComputationManager computationManager = contextObjects.get(ComputationManager.class) as ComputationManager

            binding.loadFlow = { Network network, LoadFlowParameters parameters = this.parameters ->
                LoadFlow.run(network, network.getVariantManager().getWorkingVariantId(), computationManager, parameters)
            }
            binding.loadflow = { Network network, LoadFlowParameters parameters = this.parameters ->
                LoadFlow.run(network, network.getVariantManager().getWorkingVariantId(), computationManager, parameters)
            }
        }
    }

Load flow

LoadFlowProvider parameters

Anyone who created a LoadFlowProvider implementation must add to their implementation a new method that updates an existing specific parameters extension using the information found in the PlatformConfig provided:

void updateSpecificParameters(Extension<LoadFlowParameters> extension, PlatformConfig config)

You can get inspiration from powsybl/powsybl-open-loadflow#1176.

PROPORTIONAL_TO_REMAINING_MARGIN balance type behavior

If you are a load flow model maintainer, you should implement the following change of behavior in your model:

  • In the previous versions, when using PROPORTIONAL_TO_REMAINING_MARGIN balance type, participation factor of a generator was proportional to the difference maxP - tartgetP, even if the power distribution needs to reduce targetP.
  • Starting from this release, the factor depends on the sign of the mismatch that is distributed. If it is positive, behavior stays the same. If it is negative, participation factor is proportional to the difference targetP - minP.

Custom IIDM Impl Notice for custom IIDM implementations maintainers

Initialize an adder with an existing object

Custom IIDM implementation maintainers should add the following methods:

  • in their Network implementations:
    • LineAdder newLine(Line line).
  • in their Substation implementations:
    • TwoWindingsTransformerAdder newTwoWindingsTransformer(TwoWindingsTransformer twoWindingsTransformer).

Inconsistent voltage thresholds in standByAutomaton

Custom IIDM implementation maintainers should allow having inconsistent low/high voltages in the StandbyAutomaton extension (which is an extension on StaticVarCompensator) when "standBy" is false. In this case, setting "standBy" to true should then throw an exception.

Reactive capability curves

ReactiveCapabilityCurve API has been modified, introducing two methods :

  • getMinQ(double p, boolean extrapolateReactiveLimitSlope)
  • getMaxQ(double p, boolean extrapolateReactiveLimitSlope)

(When extrapolateReactiveLimitSlope = false the behavior is the same as existing getMinQ(p) and getMaxQ(p).)

These new methods must be implemented by custom IIDM implementations.

A new utility method, ReactiveCapabilityCurveUtil.extrapolateReactiveLimitsSlope(...), which computes a point outside [minQ ; maxQ], was added to help you to implement the new API methods.


Deprecated Deprecated methods

Report node methods deprecation

The following method is now deprecated: ReportNodeAdderOrBuilder.withMessageTemplate(String key, String messageTemplate).

Consider migrating to ReportNode API V3 and using ReportNodeAdderOrBuilder.withMessageTemplate(String key) instead.

Time series methods deprecation

Since time is now managed by using Instant instead of long variables, a few methods have been deprecated and will be removed in a future release:

Class Deprecated method New method
TimeSeriesIndex and all classes implementing this interface long getTimeAt(int point) Instant getInstantAt(int point)
AbstractPoint and all classes extending this abstract class public long getTime() public Instant getInstant()
IrregularTimeSeriesIndex public IrregularTimeSeriesIndex(long[] times) public IrregularTimeSeriesIndex(Instant[] instants)
RegularTimeSeriesIndex public RegularTimeSeriesIndex(long startTime, long endTime, long spacing) public RegularTimeSeriesIndex(Instant startInstant, Instant endInstant, Duration timeStep)
RegularTimeSeriesIndex public long getStartTime() public Instant getStartInstant()
RegularTimeSeriesIndex public long getEndTime() public Instant getEndInstant()
RegularTimeSeriesIndex public long getSpacing() public Instant getTimeStep()
DoublePoint public DoublePoint(int index, long time, double value) public DoublePoint(int index, Instant instant, double value)
StringPoint public StringPoint(int index, long time, String value) public StringPoint(int index, Instant instant, String value)

CGMES post processors' methods deprecation (v6.7.1)

If you called one of these methods, you should use their new signatures instead (old signatures are now deprecated):

  • CgmesAnalogPostProcessor.process(...)
  • CgmesDiscretePostProcessor.process(...)

They both now take a Map<String, PropertyBag> idToBayBag instead of a PropertyBags bays.

Clone this wiki locally