diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractComplexIdentifiableSerDe.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractComplexIdentifiableSerDe.java
index e723ae538b5..eb4991c2337 100644
--- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractComplexIdentifiableSerDe.java
+++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractComplexIdentifiableSerDe.java
@@ -45,6 +45,27 @@ public final void read(P parent, NetworkDeserializerContext context) {
String id = readIdentifierAttributes(adder, context);
readRootElementAttributes(adder, toApply, context);
readSubElements(id, adder, toApply, context);
+ if (postponeElementCreation()) {
+ context.getEndTasks().add(() -> createElement(adder, toApply));
+ } else {
+ createElement(adder, toApply);
+ }
+ }
+
+ /**
+ *
Should the current element's creation be postponed?
+ * In some specific cases, the element could not be created right after it is read, typically if it references
+ * other network elements which may have not been yet created. (It is better to create the element without the said
+ * references and to fill them in later, but it is not always possible, or at high cost.)
+ * If this method returns true
, the element's creation will be defined as an "end task" and
+ * will be performed after the whole network is read.
+ * @return true
if the creation should be postponed, false
otherwise.
+ */
+ protected boolean postponeElementCreation() {
+ return false;
+ }
+
+ private static , A extends IdentifiableAdder> void createElement(A adder, List> toApply) {
T identifiable = adder.add();
toApply.forEach(consumer -> consumer.accept(identifiable));
}
diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractIdentifiableSerDe.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractIdentifiableSerDe.java
index 40fe44da585..85043270f0b 100644
--- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractIdentifiableSerDe.java
+++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractIdentifiableSerDe.java
@@ -56,11 +56,15 @@ public final void write(T identifiable, P parent, NetworkSerializerContext conte
protected String readIdentifierAttributes(A adder, NetworkDeserializerContext context) {
String id = context.getAnonymizer().deanonymizeString(context.getReader().readStringAttribute("id"));
String name = context.getAnonymizer().deanonymizeString(context.getReader().readStringAttribute("name"));
- adder.setId(id)
- .setName(name);
+ if (adder != null) {
+ adder.setId(id)
+ .setName(name);
+ }
IidmSerDeUtil.runFromMinimumVersion(IidmVersion.V_1_2, context, () -> {
boolean fictitious = context.getReader().readBooleanAttribute("fictitious", false);
- adder.setFictitious(fictitious);
+ if (adder != null) {
+ adder.setFictitious(fictitious);
+ }
});
return id;
}
diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataExporter.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataExporter.java
index 2f548775be4..5ea9d3fbfa8 100644
--- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataExporter.java
+++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataExporter.java
@@ -89,6 +89,11 @@
* version in which files will be generated |
* 1.5 or 1.4 etc |
*
+ *
+ * iidm.export.xml.with-automation-systems |
+ * if true automation systems are exported |
+ * true or false |
+ *
*
*
* @author Geoffroy Jamgotchian {@literal }
@@ -109,6 +114,7 @@ public abstract class AbstractTreeDataExporter implements Exporter {
public static final String EXTENSIONS_LIST = "iidm.export.xml.extensions";
public static final String SORTED = "iidm.export.xml.sorted";
public static final String VERSION = "iidm.export.xml.version";
+ public static final String WITH_AUTOMATION_SYSTEMS = "iidm.export.xml.with-automation-systems";
private static final Parameter INDENT_PARAMETER = new Parameter(INDENT, ParameterType.BOOLEAN, "Indent export output file", Boolean.TRUE);
private static final Parameter WITH_BRANCH_STATE_VARIABLES_PARAMETER = new Parameter(WITH_BRANCH_STATE_VARIABLES, ParameterType.BOOLEAN, "Export network with branch state variables", Boolean.TRUE);
@@ -126,11 +132,12 @@ public abstract class AbstractTreeDataExporter implements Exporter {
private static final Parameter SORTED_PARAMETER = new Parameter(SORTED, ParameterType.BOOLEAN, "Sort export output file", Boolean.FALSE);
private static final Parameter VERSION_PARAMETER = new Parameter(VERSION, ParameterType.STRING, "IIDM version in which files will be generated", IidmSerDeConstants.CURRENT_IIDM_VERSION.toString("."),
Arrays.stream(IidmVersion.values()).map(v -> v.toString(".")).collect(Collectors.toList()));
-
+ private static final Parameter WITH_AUTOMATION_SYSTEMS_PARAMETER = new Parameter(WITH_AUTOMATION_SYSTEMS, ParameterType.BOOLEAN,
+ "Export network with automation systems", Boolean.TRUE);
private static final List STATIC_PARAMETERS = List.of(INDENT_PARAMETER, WITH_BRANCH_STATE_VARIABLES_PARAMETER,
ONLY_MAIN_CC_PARAMETER, ANONYMISED_PARAMETER, IIDM_VERSION_INCOMPATIBILITY_BEHAVIOR_PARAMETER,
TOPOLOGY_LEVEL_PARAMETER, THROW_EXCEPTION_IF_EXTENSION_NOT_FOUND_PARAMETER, EXTENSIONS_LIST_PARAMETER,
- SORTED_PARAMETER, VERSION_PARAMETER);
+ SORTED_PARAMETER, VERSION_PARAMETER, WITH_AUTOMATION_SYSTEMS_PARAMETER);
private final ParameterDefaultValueConfig defaultValueConfig;
@@ -191,7 +198,8 @@ private ExportOptions createExportOptions(Properties parameters) {
.setExtensions(Parameter.readStringList(getFormat(), parameters, EXTENSIONS_LIST_PARAMETER, defaultValueConfig) != null ? new HashSet<>(Parameter.readStringList(getFormat(), parameters, EXTENSIONS_LIST_PARAMETER, defaultValueConfig)) : null)
.setSorted(Parameter.readBoolean(getFormat(), parameters, SORTED_PARAMETER, defaultValueConfig))
.setVersion(Parameter.readString(getFormat(), parameters, VERSION_PARAMETER, defaultValueConfig))
- .setFormat(getTreeDataFormat());
+ .setFormat(getTreeDataFormat())
+ .setWithAutomationSystems(Parameter.readBoolean(getFormat(), parameters, WITH_AUTOMATION_SYSTEMS_PARAMETER, defaultValueConfig));
addExtensionsVersions(parameters, options);
return options;
}
diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataImporter.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataImporter.java
index 2c850181ec6..caddb83a507 100644
--- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataImporter.java
+++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/AbstractTreeDataImporter.java
@@ -50,6 +50,8 @@ public abstract class AbstractTreeDataImporter implements Importer {
public static final String EXTENSIONS_LIST = "iidm.import.xml.extensions";
+ public static final String WITH_AUTOMATION_SYSTEMS = "iidm.import.xml.with-automation-systems";
+
private static final Parameter THROW_EXCEPTION_IF_EXTENSION_NOT_FOUND_PARAMETER
= new Parameter(THROW_EXCEPTION_IF_EXTENSION_NOT_FOUND, ParameterType.BOOLEAN, "Throw exception if extension not found", Boolean.FALSE)
.addAdditionalNames("throwExceptionIfExtensionNotFound");
@@ -58,6 +60,9 @@ public abstract class AbstractTreeDataImporter implements Importer {
= new Parameter(EXTENSIONS_LIST, ParameterType.STRING_LIST, "The list of extension files ", null,
EXTENSIONS_SUPPLIER.get().getProviders().stream().map(ExtensionProvider::getExtensionName).collect(Collectors.toList()));
+ private static final Parameter WITH_AUTOMATION_SYSTEMS_PARAMETER = new Parameter(WITH_AUTOMATION_SYSTEMS, ParameterType.BOOLEAN,
+ "Import network with automation systems", Boolean.TRUE);
+
private final ParameterDefaultValueConfig defaultValueConfig;
static final String SUFFIX_MAPPING = "_mapping";
@@ -72,7 +77,7 @@ protected AbstractTreeDataImporter(PlatformConfig platformConfig) {
@Override
public List getParameters() {
- return List.of(THROW_EXCEPTION_IF_EXTENSION_NOT_FOUND_PARAMETER, EXTENSIONS_LIST_PARAMETER);
+ return List.of(THROW_EXCEPTION_IF_EXTENSION_NOT_FOUND_PARAMETER, EXTENSIONS_LIST_PARAMETER, WITH_AUTOMATION_SYSTEMS_PARAMETER);
}
private String findExtension(ReadOnlyDataSource dataSource) throws IOException {
@@ -150,7 +155,8 @@ public Network importData(ReadOnlyDataSource dataSource, NetworkFactory networkF
protected ImportOptions createImportOptions(Properties parameters) {
return new ImportOptions()
.setThrowExceptionIfExtensionNotFound(Parameter.readBoolean(getFormat(), parameters, THROW_EXCEPTION_IF_EXTENSION_NOT_FOUND_PARAMETER, defaultValueConfig))
- .setExtensions(Parameter.readStringList(getFormat(), parameters, EXTENSIONS_LIST_PARAMETER, defaultValueConfig) != null ? new HashSet<>(Parameter.readStringList(getFormat(), parameters, EXTENSIONS_LIST_PARAMETER, defaultValueConfig)) : null);
+ .setExtensions(Parameter.readStringList(getFormat(), parameters, EXTENSIONS_LIST_PARAMETER, defaultValueConfig) != null ? new HashSet<>(Parameter.readStringList(getFormat(), parameters, EXTENSIONS_LIST_PARAMETER, defaultValueConfig)) : null)
+ .setWithAutomationSystems(Parameter.readBoolean(getFormat(), parameters, WITH_AUTOMATION_SYSTEMS_PARAMETER, defaultValueConfig));
}
}
diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ExportOptions.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ExportOptions.java
index e2bdc644516..fb1e8eb27c6 100644
--- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ExportOptions.java
+++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ExportOptions.java
@@ -62,6 +62,8 @@ public enum IidmVersionIncompatibilityBehavior {
*/
private boolean sorted = false;
+ private boolean withAutomationSystems = true;
+
public ExportOptions() {
}
@@ -233,4 +235,13 @@ public ExportOptions setSorted(boolean sorted) {
this.sorted = sorted;
return this;
}
+
+ public boolean isWithAutomationSystems() {
+ return withAutomationSystems;
+ }
+
+ public ExportOptions setWithAutomationSystems(boolean withAutomationSystems) {
+ this.withAutomationSystems = withAutomationSystems;
+ return this;
+ }
}
diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ImportOptions.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ImportOptions.java
index 0f9901dffc6..a701c8451ee 100644
--- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ImportOptions.java
+++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ImportOptions.java
@@ -17,6 +17,7 @@
public class ImportOptions extends AbstractOptions {
private boolean throwExceptionIfExtensionNotFound = false;
+ private boolean withAutomationSystems = true;
public ImportOptions() {
}
@@ -50,4 +51,13 @@ public ImportOptions addExtension(String extension) {
public boolean isThrowExceptionIfExtensionNotFound() {
return throwExceptionIfExtensionNotFound;
}
+
+ public boolean isWithAutomationSystems() {
+ return withAutomationSystems;
+ }
+
+ public ImportOptions setWithAutomationSystems(boolean withAutomationSystems) {
+ this.withAutomationSystems = withAutomationSystems;
+ return this;
+ }
}
diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/NetworkSerDe.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/NetworkSerDe.java
index 5debecd41b4..1db679a68c7 100644
--- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/NetworkSerDe.java
+++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/NetworkSerDe.java
@@ -553,6 +553,7 @@ private static BiMap createArrayNameSingleNameBiMap(boolean with
Map.entry(LineSerDe.ARRAY_ELEMENT_NAME, LineSerDe.ROOT_ELEMENT_NAME),
Map.entry(LoadSerDe.ARRAY_ELEMENT_NAME, LoadSerDe.ROOT_ELEMENT_NAME),
Map.entry(NodeBreakerViewInternalConnectionSerDe.ARRAY_ELEMENT_NAME, NodeBreakerViewInternalConnectionSerDe.ROOT_ELEMENT_NAME),
+ Map.entry(OverloadManagementSystemSerDe.ARRAY_ELEMENT_NAME, OverloadManagementSystemSerDe.ROOT_ELEMENT_NAME),
Map.entry(PropertiesSerDe.ARRAY_ELEMENT_NAME, PropertiesSerDe.ROOT_ELEMENT_NAME),
Map.entry(ReactiveLimitsSerDe.POINT_ARRAY_ELEMENT_NAME, ReactiveLimitsSerDe.POINT_ROOT_ELEMENT_NAME),
Map.entry(ShuntSerDe.ARRAY_ELEMENT_NAME, ShuntSerDe.ROOT_ELEMENT_NAME),
diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/OverloadManagementSystemSerDe.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/OverloadManagementSystemSerDe.java
new file mode 100644
index 00000000000..d5824bf83a9
--- /dev/null
+++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/OverloadManagementSystemSerDe.java
@@ -0,0 +1,197 @@
+/**
+ * Copyright (c) 2024, RTE (http://www.rte-france.com)
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+package com.powsybl.iidm.serde;
+
+import com.powsybl.commons.PowsyblException;
+import com.powsybl.iidm.network.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * @author Olivier Perrin {@literal }
+ */
+class OverloadManagementSystemSerDe extends AbstractComplexIdentifiableSerDe {
+
+ static final OverloadManagementSystemSerDe INSTANCE = new OverloadManagementSystemSerDe();
+
+ static final String ROOT_ELEMENT_NAME = "overloadManagementSystem";
+ static final String ARRAY_ELEMENT_NAME = "overloadManagementSystems";
+
+ private static final String BRANCH_TRIPPING_TAG = "branchTripping";
+ private static final String SWITCH_TRIPPING_TAG = "switchTripping";
+ private static final String THREE_WINDINGS_TRANSFORMER_TRIPPING_TAG = "threeWindingsTransformerTripping";
+
+ @Override
+ protected String getRootElementName() {
+ return ROOT_ELEMENT_NAME;
+ }
+
+ @Override
+ protected void writeRootElementAttributes(OverloadManagementSystem oms, Substation substation, NetworkSerializerContext context) {
+ context.getWriter().writeBooleanAttribute("enabled", oms.isEnabled());
+ context.getWriter().writeStringAttribute("monitoredElementId", context.getAnonymizer().anonymizeString(oms.getMonitoredElementId()));
+ context.getWriter().writeStringAttribute("side", oms.getMonitoredSide().name());
+ }
+
+ @Override
+ protected void writeSubElements(OverloadManagementSystem oms, Substation substation, NetworkSerializerContext context) {
+ oms.getTrippings().forEach(t -> writeTripping(t, context));
+ }
+
+ private void writeTripping(OverloadManagementSystem.Tripping tripping, NetworkSerializerContext context) {
+ switch (tripping.getType()) {
+ case BRANCH_TRIPPING -> {
+ OverloadManagementSystem.BranchTripping branchTripping = (OverloadManagementSystem.BranchTripping) tripping;
+ context.getWriter().writeStartNode(context.getVersion().getNamespaceURI(context.isValid()), BRANCH_TRIPPING_TAG);
+ writeTrippingCommonAttributes(tripping, context);
+ context.getWriter().writeStringAttribute("branchId",
+ context.getAnonymizer().anonymizeString(branchTripping.getBranchToOperateId()));
+ context.getWriter().writeStringAttribute("side", branchTripping.getSideToOperate().name());
+ context.getWriter().writeEndNode();
+ }
+ case SWITCH_TRIPPING -> {
+ OverloadManagementSystem.SwitchTripping switchTripping = (OverloadManagementSystem.SwitchTripping) tripping;
+ context.getWriter().writeStartNode(context.getVersion().getNamespaceURI(context.isValid()), SWITCH_TRIPPING_TAG);
+ writeTrippingCommonAttributes(tripping, context);
+ context.getWriter().writeStringAttribute("switchId",
+ context.getAnonymizer().anonymizeString(switchTripping.getSwitchToOperateId()));
+ context.getWriter().writeEndNode();
+ }
+ case THREE_WINDINGS_TRANSFORMER_TRIPPING -> {
+ OverloadManagementSystem.ThreeWindingsTransformerTripping twtTripping =
+ (OverloadManagementSystem.ThreeWindingsTransformerTripping) tripping;
+ context.getWriter().writeStartNode(context.getVersion().getNamespaceURI(context.isValid()), THREE_WINDINGS_TRANSFORMER_TRIPPING_TAG);
+ writeTrippingCommonAttributes(tripping, context);
+ context.getWriter().writeStringAttribute("threeWindingsTransformerId",
+ context.getAnonymizer().anonymizeString(twtTripping.getThreeWindingsTransformerToOperateId()));
+ context.getWriter().writeStringAttribute("side", twtTripping.getSideToOperate().name());
+ context.getWriter().writeEndNode();
+ }
+ default -> throw new PowsyblException("Unexpected tripping type: " + tripping.getType());
+ }
+ }
+
+ private void writeTrippingCommonAttributes(OverloadManagementSystem.Tripping tripping, NetworkSerializerContext context) {
+ context.getWriter().writeStringAttribute("key", tripping.getKey());
+ String nameOrKey = tripping.getNameOrKey();
+ if (nameOrKey != null && !nameOrKey.equals(tripping.getKey())) {
+ context.getWriter().writeStringAttribute("name", nameOrKey);
+ }
+ context.getWriter().writeDoubleAttribute("currentLimit", tripping.getCurrentLimit());
+ context.getWriter().writeBooleanAttribute("openAction", tripping.isOpenAction());
+ }
+
+ @Override
+ protected OverloadManagementSystemAdder createAdder(Substation s) {
+ return s.newOverloadManagementSystem();
+ }
+
+ @Override
+ protected void readRootElementAttributes(OverloadManagementSystemAdder adder,
+ List> toApply,
+ NetworkDeserializerContext context) {
+ boolean enabled = context.getReader().readBooleanAttribute("enabled", true);
+ String monitoredElementId = context.getAnonymizer().deanonymizeString(context.getReader().readStringAttribute("monitoredElementId"));
+ String side = context.getReader().readStringAttribute("side");
+ ThreeSides monitoredSide = side == null ? ThreeSides.ONE : ThreeSides.valueOf(side);
+ if (adder != null) {
+ adder.setEnabled(enabled)
+ .setMonitoredElementId(monitoredElementId)
+ .setMonitoredElementSide(monitoredSide);
+ }
+ }
+
+ @Override
+ protected void readSubElements(String id, OverloadManagementSystemAdder adder,
+ List> toApply,
+ NetworkDeserializerContext context) {
+ context.getReader().readChildNodes(elementName -> {
+ String key = context.getReader().readStringAttribute("key");
+ String name = context.getReader().readStringAttribute("name");
+ double currentLimit = context.getReader().readDoubleAttribute("currentLimit");
+ boolean openAction = context.getReader().readBooleanAttribute("openAction");
+
+ switch (elementName) {
+ case BRANCH_TRIPPING_TAG -> readBranchTripping(adder, context, key, name, currentLimit, openAction);
+ case SWITCH_TRIPPING_TAG -> readSwitchTripping(adder, context, key, name, currentLimit, openAction);
+ case THREE_WINDINGS_TRANSFORMER_TRIPPING_TAG -> readThreeWindingsTransformerTripping(adder, context, key, name, currentLimit, openAction);
+ default -> readSubElement(elementName, id, toApply, context);
+ }
+ });
+ }
+
+ private static void readBranchTripping(OverloadManagementSystemAdder adder, NetworkDeserializerContext context,
+ String key, String name, double currentLimit, boolean openAction) {
+ String branchId = context.getAnonymizer().deanonymizeString(context.getReader().readStringAttribute("branchId"));
+ String side = context.getReader().readStringAttribute("side");
+ TwoSides sideToOperate = side == null ? TwoSides.ONE : TwoSides.valueOf(side);
+ context.getReader().readEndNode();
+ if (adder != null) {
+ adder.newBranchTripping()
+ .setKey(key)
+ .setName(name)
+ .setCurrentLimit(currentLimit)
+ .setOpenAction(openAction)
+ .setBranchToOperateId(branchId)
+ .setSideToOperate(sideToOperate)
+ .add();
+ }
+ }
+
+ private static void readSwitchTripping(OverloadManagementSystemAdder adder, NetworkDeserializerContext context,
+ String key, String name, double currentLimit, boolean openAction) {
+ String switchId = context.getAnonymizer().deanonymizeString(context.getReader().readStringAttribute("switchId"));
+ context.getReader().readEndNode();
+ if (adder != null) {
+ adder.newSwitchTripping()
+ .setKey(key)
+ .setName(name)
+ .setCurrentLimit(currentLimit)
+ .setOpenAction(openAction)
+ .setSwitchToOperateId(switchId)
+ .add();
+ }
+ }
+
+ private static void readThreeWindingsTransformerTripping(OverloadManagementSystemAdder adder, NetworkDeserializerContext context,
+ String key, String name, double currentLimit, boolean openAction) {
+ String twtId = context.getAnonymizer().deanonymizeString(
+ context.getReader().readStringAttribute("threeWindingsTransformerId"));
+ String side = context.getReader().readStringAttribute("side");
+ ThreeSides sideToOperate = side == null ? ThreeSides.ONE : ThreeSides.valueOf(side);
+ context.getReader().readEndNode();
+ if (adder != null) {
+ adder.newThreeWindingsTransformerTripping()
+ .setKey(key)
+ .setName(name)
+ .setCurrentLimit(currentLimit)
+ .setOpenAction(openAction)
+ .setThreeWindingsTransformerToOperateId(twtId)
+ .setSideToOperate(sideToOperate)
+ .add();
+ }
+ }
+
+ @Override
+ protected boolean postponeElementCreation() {
+ // OverloadManagementSystems may reference other elements which are not in the same substation (for instance lines).
+ // In that case, there's no guarantee that the other elements were previously read when deserializing the network.
+ // This could lead to errors at the OverloadManagementSystem's creation.
+ // To avoid this, this latter is postponed.
+ return true;
+ }
+
+ public final void skip(NetworkDeserializerContext context) {
+ List> toApply = new ArrayList<>();
+ String id = readIdentifierAttributes(null, context);
+ readRootElementAttributes(null, toApply, context);
+ readSubElements(id, null, toApply, context);
+ }
+}
diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/SubstationSerDe.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/SubstationSerDe.java
index c23a9565b0c..e70034b8999 100644
--- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/SubstationSerDe.java
+++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/SubstationSerDe.java
@@ -8,7 +8,10 @@
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.serde.util.IidmSerDeUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.Collection;
import java.util.Optional;
/**
@@ -17,6 +20,8 @@
*/
class SubstationSerDe extends AbstractSimpleIdentifiableSerDe {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SubstationSerDe.class);
+
static final SubstationSerDe INSTANCE = new SubstationSerDe();
static final String ROOT_ELEMENT_NAME = "substation";
@@ -43,12 +48,21 @@ protected void writeRootElementAttributes(Substation s, Network n, NetworkSerial
@Override
protected void writeSubElements(Substation s, Network n, NetworkSerializerContext context) {
+ writeVoltageLevels(s, context);
+ writeTwoWindingsTransformers(s, context);
+ writeThreeWindingsTransformers(s, context);
+ writeOverloadManagementSystems(s, context);
+ }
+
+ private static void writeVoltageLevels(Substation s, NetworkSerializerContext context) {
context.getWriter().writeStartNodes();
for (VoltageLevel vl : IidmSerDeUtil.sorted(s.getVoltageLevels(), context.getOptions())) {
VoltageLevelSerDe.INSTANCE.write(vl, null, context);
}
context.getWriter().writeEndNodes();
+ }
+ private static void writeTwoWindingsTransformers(Substation s, NetworkSerializerContext context) {
context.getWriter().writeStartNodes();
Iterable twts = IidmSerDeUtil.sorted(s.getTwoWindingsTransformers(), context.getOptions());
for (TwoWindingsTransformer twt : twts) {
@@ -58,10 +72,12 @@ protected void writeSubElements(Substation s, Network n, NetworkSerializerContex
TwoWindingsTransformerSerDe.INSTANCE.write(twt, null, context);
}
context.getWriter().writeEndNodes();
+ }
+ private static void writeThreeWindingsTransformers(Substation s, NetworkSerializerContext context) {
context.getWriter().writeStartNodes();
- Iterable twts2 = IidmSerDeUtil.sorted(s.getThreeWindingsTransformers(), context.getOptions());
- for (ThreeWindingsTransformer twt : twts2) {
+ Iterable twts = IidmSerDeUtil.sorted(s.getThreeWindingsTransformers(), context.getOptions());
+ for (ThreeWindingsTransformer twt : twts) {
if (!context.getFilter().test(twt)) {
continue;
}
@@ -70,6 +86,60 @@ protected void writeSubElements(Substation s, Network n, NetworkSerializerContex
context.getWriter().writeEndNodes();
}
+ private static void writeOverloadManagementSystems(Substation s, NetworkSerializerContext context) {
+ if (!context.getOptions().isWithAutomationSystems()) {
+ return;
+ }
+ IidmSerDeUtil.runFromMinimumVersion(IidmVersion.V_1_12, context, () -> {
+ Collection validOverloadManagementSystems = filterValidOverloadManagementSystems(s);
+ if (!validOverloadManagementSystems.isEmpty()) {
+ context.getWriter().writeStartNodes();
+ IidmSerDeUtil.sorted(validOverloadManagementSystems, context.getOptions())
+ .forEach(oms -> OverloadManagementSystemSerDe.INSTANCE.write(oms, null, context));
+ context.getWriter().writeEndNodes();
+ }
+ });
+ }
+
+ private static Collection filterValidOverloadManagementSystems(Substation s) {
+ Network n = s.getNetwork();
+ return s.getOverloadManagementSystemStream().filter(o -> {
+ if (n.getIdentifiable(o.getMonitoredElementId()) == null) {
+ LOGGER.warn(String.format("Discard overload management system '%s': monitored element '%s' is unknown.",
+ o.getNameOrId(), o.getMonitoredElementId()));
+ return false;
+ }
+ for (OverloadManagementSystem.Tripping tripping : o.getTrippings()) {
+ Identifiable> element = null;
+ String id = "";
+ String type = "";
+ switch (tripping.getType()) {
+ case BRANCH_TRIPPING -> {
+ type = "branch";
+ id = ((OverloadManagementSystem.BranchTripping) tripping).getBranchToOperateId();
+ element = n.getBranch(id);
+ }
+ case SWITCH_TRIPPING -> {
+ type = "switch";
+ id = ((OverloadManagementSystem.SwitchTripping) tripping).getSwitchToOperateId();
+ element = n.getSwitch(id);
+ }
+ case THREE_WINDINGS_TRANSFORMER_TRIPPING -> {
+ type = "three windings transformer";
+ id = ((OverloadManagementSystem.ThreeWindingsTransformerTripping) tripping).getThreeWindingsTransformerToOperateId();
+ element = n.getThreeWindingsTransformer(id);
+ }
+ }
+ if (element == null) {
+ LOGGER.warn(String.format("Discard overload management system '%s': invalid %s tripping. '%s' is unknown.",
+ o.getNameOrId(), type, id));
+ return false;
+ }
+ }
+ return true;
+ }).toList();
+ }
+
@Override
protected SubstationAdder createAdder(Network network) {
return network.newSubstation();
@@ -97,8 +167,19 @@ protected void readSubElements(Substation s, NetworkDeserializerContext context)
case VoltageLevelSerDe.ROOT_ELEMENT_NAME -> VoltageLevelSerDe.INSTANCE.read(s, context);
case TwoWindingsTransformerSerDe.ROOT_ELEMENT_NAME -> TwoWindingsTransformerSerDe.INSTANCE.read(s, context);
case ThreeWindingsTransformerSerDe.ROOT_ELEMENT_NAME -> ThreeWindingsTransformerSerDe.INSTANCE.read(s, context);
+ case OverloadManagementSystemSerDe.ROOT_ELEMENT_NAME -> checkSupportedAndReadOverloadManagementSystems(s, context);
default -> readSubElement(elementName, s, context);
}
});
}
+
+ private static void checkSupportedAndReadOverloadManagementSystems(Substation s, NetworkDeserializerContext context) {
+ IidmSerDeUtil.assertMinimumVersion(ROOT_ELEMENT_NAME, OverloadManagementSystemSerDe.ROOT_ELEMENT_NAME,
+ IidmSerDeUtil.ErrorMessage.NOT_SUPPORTED, IidmVersion.V_1_12, context);
+ if (context.getOptions().isWithAutomationSystems()) {
+ OverloadManagementSystemSerDe.INSTANCE.read(s, context);
+ } else {
+ OverloadManagementSystemSerDe.INSTANCE.skip(context);
+ }
+ }
}
diff --git a/iidm/iidm-serde/src/main/resources/xsd/iidm_V1_12.xsd b/iidm/iidm-serde/src/main/resources/xsd/iidm_V1_12.xsd
index 91a8ad187f1..c11d28a6b77 100644
--- a/iidm/iidm-serde/src/main/resources/xsd/iidm_V1_12.xsd
+++ b/iidm/iidm-serde/src/main/resources/xsd/iidm_V1_12.xsd
@@ -78,6 +78,7 @@
+
@@ -499,6 +500,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/main/resources/xsd/iidm_equipment_V1_12.xsd b/iidm/iidm-serde/src/main/resources/xsd/iidm_equipment_V1_12.xsd
index e3ae492b20f..c3541f1971f 100644
--- a/iidm/iidm-serde/src/main/resources/xsd/iidm_equipment_V1_12.xsd
+++ b/iidm/iidm-serde/src/main/resources/xsd/iidm_equipment_V1_12.xsd
@@ -77,6 +77,7 @@
+
@@ -495,6 +496,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/AbstractIidmSerDeTest.java b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/AbstractIidmSerDeTest.java
index eb2bbe45099..169a85e4316 100644
--- a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/AbstractIidmSerDeTest.java
+++ b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/AbstractIidmSerDeTest.java
@@ -128,6 +128,15 @@ protected void testForAllPreviousVersions(IidmVersion maxVersion, Consumer test) {
+ Stream.of(IidmVersion.values())
+ .filter(v -> v.compareTo(minVersion) >= 0)
+ .forEach(test);
+ }
+
/**
* Execute a write test for the given network, for all IIDM versions strictly older than a given maximum IIDM
* version, and compare to the given versioned xml reference test resource.
@@ -190,6 +199,7 @@ public Network allFormatsRoundTripTest(Network network, String refXmlFile) throw
*
* @param network the network to start with
* @param filename the filename of the reference versioned file resource
+ * @param version the version to use for exporting and for the versioned filename
* @return the Network read just before the end of the round trip
*/
public Network allFormatsRoundTripTest(Network network, String filename, IidmVersion version) throws IOException {
diff --git a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/ExportOptionsTest.java b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/ExportOptionsTest.java
index 23e85658b1c..f9c0a7df577 100644
--- a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/ExportOptionsTest.java
+++ b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/ExportOptionsTest.java
@@ -46,8 +46,10 @@ void exportOptionsTest2() {
ExportOptions options = new ExportOptions();
options.setCharset(StandardCharsets.ISO_8859_1);
options.setExtensions(extensionsList);
+ options.setWithAutomationSystems(false);
assertEquals(0, (int) options.getExtensions().map(Set::size).orElse(-1));
assertEquals(StandardCharsets.ISO_8859_1, options.getCharset());
+ assertFalse(options.isWithAutomationSystems());
}
@Test
@@ -85,5 +87,6 @@ private void testDefaultExportOptions(ExportOptions options) {
assertEquals(IidmSerDeConstants.CURRENT_IIDM_VERSION, options.getVersion());
assertEquals(THROW_EXCEPTION, options.getIidmVersionIncompatibilityBehavior());
assertEquals(StandardCharsets.UTF_8, options.getCharset());
+ assertEquals(Boolean.TRUE, options.isWithAutomationSystems());
}
}
diff --git a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/ImportOptionsTest.java b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/ImportOptionsTest.java
index f39ca4e68f4..0a84c6e2943 100644
--- a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/ImportOptionsTest.java
+++ b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/ImportOptionsTest.java
@@ -23,7 +23,9 @@ void importOptionsTest() {
ImportOptions options = new ImportOptions();
Set extensionsList = Sets.newHashSet("loadFoo", "loadBar");
options.setExtensions(extensionsList);
+ options.setWithAutomationSystems(false);
assertEquals(Boolean.FALSE, options.withNoExtension());
+ assertEquals(Boolean.FALSE, options.isWithAutomationSystems());
options.addExtension("loadBar");
assertEquals(2, (int) options.getExtensions().map(Set::size).orElse(-1));
@@ -48,5 +50,6 @@ void importOptionsDefaultValues() {
assertEquals(Boolean.FALSE, options.withNoExtension());
assertEquals(-1, (int) options.getExtensions().map(Set::size).orElse(-1));
assertEquals(Boolean.TRUE, options.withAllExtensions());
+ assertEquals(Boolean.TRUE, options.isWithAutomationSystems());
}
}
diff --git a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/OverloadManagementSystemSerDeTest.java b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/OverloadManagementSystemSerDeTest.java
new file mode 100644
index 00000000000..325cfff4321
--- /dev/null
+++ b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/OverloadManagementSystemSerDeTest.java
@@ -0,0 +1,338 @@
+/**
+ * Copyright (c) 2024, RTE (http://www.rte-france.com)
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+package com.powsybl.iidm.serde;
+
+import com.powsybl.commons.io.TreeDataFormat;
+import com.powsybl.iidm.network.*;
+import com.powsybl.iidm.serde.anonymizer.Anonymizer;
+import org.apache.commons.io.IOUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.time.ZonedDateTime;
+import java.util.stream.Stream;
+
+import static com.powsybl.iidm.serde.IidmSerDeConstants.CURRENT_IIDM_VERSION;
+
+/**
+ * @author Olivier Perrin {@literal }
+ */
+class OverloadManagementSystemSerDeTest extends AbstractIidmSerDeTest {
+
+ private static Network network;
+
+ @BeforeAll
+ public static void setup() {
+ network = createNetwork();
+ }
+
+ @Test
+ void roundTripTest() throws IOException {
+ // backward compatibility
+ allFormatsRoundTripAllPreviousVersionedXmlTest("overloadManagementSystemRoundTripRef.xml");
+ allFormatsRoundTripTest(network, "overloadManagementSystemRoundTripRef.xml", CURRENT_IIDM_VERSION);
+ }
+
+ private record ExportResult(Anonymizer anonymizer, String content) {
+ }
+
+ static Stream provideFormats() {
+ return Stream.of(
+ Arguments.of(TreeDataFormat.JSON),
+ Arguments.of(TreeDataFormat.XML)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideFormats")
+ void exportDisabledTest(TreeDataFormat format) {
+ testForAllVersionsSince(IidmVersion.V_1_12, v -> exportDisabledTest(format, v));
+ }
+
+ private void exportDisabledTest(TreeDataFormat format, IidmVersion version) {
+ // Export the network without the automation systems
+ ExportResult exportResult = writeNetwork(network, format, version, false);
+ // Check that the exported String does NOT contain OMS tags
+ Assertions.assertFalse(exportResult.content().contains(OverloadManagementSystemSerDe.ROOT_ELEMENT_NAME));
+ // Load the exported String to check if it is really valid
+ Network networkOutput = readNetwork(format, exportResult, true);
+ // Check that the read network has substations, lines, ... but no OMS (none were exported)
+ checkNetworkAgainstRef(networkOutput, false);
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideFormats")
+ void importDisabledTest(TreeDataFormat format) {
+ testForAllVersionsSince(IidmVersion.V_1_12, v -> importDisabledTest(format, v));
+ }
+
+ private void importDisabledTest(TreeDataFormat format, IidmVersion version) {
+ // Export the network (with the automation systems)
+ ExportResult exportResult = writeNetwork(network, format, version, true);
+ // Check that the exported String DOES contain OMS tags
+ Assertions.assertTrue(exportResult.content().contains(OverloadManagementSystemSerDe.ROOT_ELEMENT_NAME));
+ // Load the exported String without the automation systems
+ Network networkOutput = readNetwork(format, exportResult, false);
+ // Check that the read network has substations, lines, ... but no OMS (none were imported)
+ checkNetworkAgainstRef(networkOutput, false);
+
+ // Final check: import the same network, but this time with the automation systems
+ // They should now be present
+ networkOutput = readNetwork(format, exportResult, true);
+ checkNetworkAgainstRef(networkOutput, true);
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideFormats")
+ void roundTripWithInvalidOverloadManagementSystemsTest(TreeDataFormat format) {
+ Network n = createNetwork();
+ // Remove the monitoredElement of OMS2
+ n.getLine("LINE_1").remove();
+ ExportResult exportResult = writeNetwork(n, format, CURRENT_IIDM_VERSION, true);
+ Network networkOutput = readNetwork(format, exportResult, true);
+ Assertions.assertNotNull(networkOutput.getOverloadManagementSystem("OMS1"));
+ Assertions.assertNull(networkOutput.getOverloadManagementSystem("OMS2"));
+
+ // Remove the 3 windings transformer (3WT) of the OMS1's 3WT tripping
+ n.getThreeWindingsTransformer("3WT").remove();
+ exportResult = writeNetwork(n, format, CURRENT_IIDM_VERSION, true);
+ networkOutput = readNetwork(format, exportResult, true);
+ Assertions.assertNull(networkOutput.getOverloadManagementSystem("OMS1"));
+
+ // Recreate the network
+ n = createNetwork();
+
+ // Remove the branch of the OMS2's tripping
+ n.getLine("LINE_2").remove();
+ exportResult = writeNetwork(n, format, CURRENT_IIDM_VERSION, true);
+ networkOutput = readNetwork(format, exportResult, true);
+ Assertions.assertNotNull(networkOutput.getOverloadManagementSystem("OMS1"));
+ Assertions.assertNull(networkOutput.getOverloadManagementSystem("OMS2"));
+
+ // No test on switch tripping because the switch cannot be removed with the API.
+ }
+
+ private static ExportResult writeNetwork(Network n, TreeDataFormat format, IidmVersion version, boolean withAutomationSystems) {
+ ExportOptions options = new ExportOptions()
+ .setFormat(format)
+ .setWithAutomationSystems(withAutomationSystems)
+ .setVersion(version.toString("."));
+ ExportResult exportResult;
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+ Anonymizer anonymizer = NetworkSerDe.write(n, options, os);
+ String exportedContent = os.toString(StandardCharsets.UTF_8);
+ exportResult = new ExportResult(anonymizer, exportedContent);
+ } catch (IOException ex) {
+ throw new UncheckedIOException(ex);
+ }
+ return exportResult;
+ }
+
+ private static Network readNetwork(TreeDataFormat format, ExportResult exportResult, boolean withAutomationSystems) {
+ ImportOptions options = new ImportOptions()
+ .setFormat(format)
+ .setWithAutomationSystems(withAutomationSystems);
+ Network networkOutput;
+ try (InputStream is = IOUtils.toInputStream(exportResult.content(), "UTF-8")) {
+ networkOutput = NetworkSerDe.read(is, options, exportResult.anonymizer());
+ } catch (IOException ex) {
+ throw new UncheckedIOException(ex);
+ }
+ return networkOutput;
+ }
+
+ private static void checkNetworkAgainstRef(Network networkOutput, boolean shouldHaveAutomationSystems) {
+ Assertions.assertEquals(network.getSubstationCount(), networkOutput.getSubstationCount());
+ Assertions.assertEquals(network.getLineCount(), networkOutput.getLineCount());
+ Assertions.assertEquals(network.getTwoWindingsTransformerCount(), networkOutput.getTwoWindingsTransformerCount());
+ Assertions.assertEquals(network.getThreeWindingsTransformerCount(), networkOutput.getThreeWindingsTransformerCount());
+ int expectedNbAutomationSystem = shouldHaveAutomationSystems ? network.getOverloadManagementSystemCount() : 0;
+ Assertions.assertEquals(expectedNbAutomationSystem, networkOutput.getOverloadManagementSystemCount());
+ }
+
+ private static Network createNetwork() {
+ Network network = NetworkFactory.findDefault().createNetwork("fictitious", "test");
+ network.setCaseDate(ZonedDateTime.parse("2024-01-02T15:00:00.000+01:00"));
+ network.setForecastDistance(0);
+
+ // Create a substation "S1", with 3 voltage levels "S1_400", "S1_220" and "S1_90"
+ Substation s1 = network.newSubstation().setId("S1").add();
+ VoltageLevel s1v400 = createVoltageLevel(s1, 400);
+ VoltageLevel s1v225 = createVoltageLevel(s1, 225);
+ VoltageLevel s1v90 = createVoltageLevel(s1, 90);
+
+ // Create a substation "S2", with 1 voltage level "S2_400"
+ Substation s2 = network.newSubstation().setId("S2").add();
+ VoltageLevel s2v400 = createVoltageLevel(s2, 400);
+
+ // Create 2 lines between "S1_400" and "S2_400" ("LINE_1" and "LINE_2")
+ createLine(network, s1v400, s2v400, 1);
+ createLine(network, s1v400, s2v400, 2);
+
+ // Create a 2-windings transformer between "S1_400" and "S1_225" ("2WT")
+ createTwoWindingsTransformer(s1, s1v400, s1v225);
+
+ // Create a 3-windings transformer between "S1_400", "S1_225" and "S1_90" ("3WT")
+ createThreeWindingsTransformer(s1, s1v400, s1v225, s1v90);
+
+ // Create an overload management system with trippings on "2WT", "3WT" and "S1_400_LINE_2_BREAKER"
+ s1.newOverloadManagementSystem()
+ .setId("OMS1")
+ .setName("1st OMS")
+ .setEnabled(true)
+ .setMonitoredElementId("2WT")
+ .setMonitoredElementSide(ThreeSides.TWO)
+ .newBranchTripping()
+ .setKey("tripping1")
+ .setName("1st tripping name")
+ .setCurrentLimit(1200)
+ .setOpenAction(true)
+ .setBranchToOperateId("2WT")
+ .setSideToOperate(TwoSides.ONE)
+ .add()
+ .newThreeWindingsTransformerTripping()
+ .setKey("tripping2")
+ .setName("2nd tripping name")
+ .setCurrentLimit(1000)
+ .setOpenAction(false)
+ .setThreeWindingsTransformerToOperateId("3WT")
+ .setSideToOperate(ThreeSides.ONE)
+ .add()
+ .newSwitchTripping()
+ .setKey("tripping3")
+ .setName("3rd tripping name")
+ .setCurrentLimit(1000)
+ .setOpenAction(true)
+ .setSwitchToOperateId("S1_400_LINE_2_BREAKER")
+ .add()
+ .add();
+
+ // Create an overload management system monitoring "LINE_1" with a tripping on "LINE_2".
+ // Note that this test is very important since the OMS uses identifiers of elements which are not
+ // defined in the same substation, and furthermore which will be serialized AFTER the OMS (lines are serialized
+ // after the substations). This means that the referenced elements won't be already in the network in creation
+ // when the OMS will be read.
+ s1.newOverloadManagementSystem()
+ .setId("OMS2")
+ .setName("2nd OMS")
+ .setEnabled(true)
+ .setMonitoredElementId("LINE_1")
+ .setMonitoredElementSide(ThreeSides.ONE)
+ .newBranchTripping()
+ .setKey("tripping")
+ .setName("tripping name")
+ .setCurrentLimit(1300)
+ .setOpenAction(true)
+ .setBranchToOperateId("LINE_2")
+ .setSideToOperate(TwoSides.ONE)
+ .add()
+ .add();
+ return network;
+ }
+
+ private static VoltageLevel createVoltageLevel(Substation substation, int nominalV) {
+ String vlId = String.format("%s_%d", substation.getId(), nominalV);
+ VoltageLevel vl = substation.newVoltageLevel()
+ .setId(vlId)
+ .setNominalV(nominalV)
+ .setTopologyKind(TopologyKind.NODE_BREAKER)
+ .add();
+ vl.getNodeBreakerView().newBusbarSection()
+ .setId(vlId + "_BBS")
+ .setNode(0)
+ .add();
+ return vl;
+ }
+
+ private static void createLine(Network network, VoltageLevel s1v400, VoltageLevel s2v400, int nb) {
+ createSwitch(s1v400, "S1_400_LINE_" + nb + "_DISCONNECTOR", SwitchKind.DISCONNECTOR, 0, nb);
+ createSwitch(s1v400, "S1_400_LINE_" + nb + "_BREAKER", SwitchKind.BREAKER, nb, 10 + nb);
+ createSwitch(s2v400, "S2_400_LINE_" + nb + "_DISCONNECTOR", SwitchKind.DISCONNECTOR, 0, nb);
+ createSwitch(s2v400, "S2_400_LINE_" + nb + "_BREAKER", SwitchKind.BREAKER, nb, 10 + nb);
+ network.newLine()
+ .setId("LINE_" + nb)
+ .setR(0.01)
+ .setX(50)
+ .setG1(0.0)
+ .setB1(0.0)
+ .setG2(0.0)
+ .setB2(0.0)
+ .setNode1(10 + nb)
+ .setVoltageLevel1("S1_400")
+ .setNode2(10 + nb)
+ .setVoltageLevel2("S2_400")
+ .add();
+ }
+
+ private static void createTwoWindingsTransformer(Substation s1, VoltageLevel s1v400, VoltageLevel s1v225) {
+ createSwitch(s1v400, "S1_400_BBS_2WT_DISCONNECTOR", SwitchKind.DISCONNECTOR, 0, 13);
+ createSwitch(s1v400, "S1_400_2WT_BREAKER", SwitchKind.BREAKER, 13, 23);
+ createSwitch(s1v225, "S1_225_BBS_2WT_DISCONNECTOR", SwitchKind.DISCONNECTOR, 0, 13);
+ createSwitch(s1v225, "S1_225_2WT_BREAKER", SwitchKind.BREAKER, 13, 23);
+ s1.newTwoWindingsTransformer()
+ .setId("2WT")
+ .setR(2.0)
+ .setX(25)
+ .setG(0.0)
+ .setB(3.2E-5)
+ .setRatedU1(400.0)
+ .setRatedU2(225.0)
+ .setNode1(23)
+ .setVoltageLevel1("S1_400")
+ .setNode2(23)
+ .setVoltageLevel2("S1_225")
+ .add();
+ }
+
+ private static void createThreeWindingsTransformer(Substation s1, VoltageLevel s1v400, VoltageLevel s1v225, VoltageLevel s1v90) {
+ createSwitch(s1v400, "S1_400_BBS_3WT_DISCONNECTOR", SwitchKind.DISCONNECTOR, 0, 14);
+ createSwitch(s1v400, "S1_400_3WT_BREAKER", SwitchKind.BREAKER, 14, 24);
+ createSwitch(s1v225, "S1_225_BBS_3WT_DISCONNECTOR", SwitchKind.DISCONNECTOR, 0, 14);
+ createSwitch(s1v225, "S1_225_3WT_BREAKER", SwitchKind.BREAKER, 14, 24);
+ createSwitch(s1v90, "S1_90_BBS_3WT_DISCONNECTOR", SwitchKind.DISCONNECTOR, 0, 14);
+ createSwitch(s1v90, "S1_90_3WT_BREAKER", SwitchKind.BREAKER, 14, 24);
+ s1.newThreeWindingsTransformer()
+ .setId("3WT")
+ .setRatedU0(400)
+ .newLeg1()
+ .setR(0.001).setX(0.000001).setB(0).setG(0)
+ .setNode(24)
+ .setRatedU(400)
+ .setVoltageLevel("S1_400")
+ .add()
+ .newLeg2()
+ .setR(0.1).setX(0.00001).setB(0).setG(0)
+ .setNode(24)
+ .setRatedU(225)
+ .setVoltageLevel("S1_225")
+ .add()
+ .newLeg3()
+ .setR(0.01).setX(0.0001).setB(0).setG(0)
+ .setNode(24)
+ .setRatedU(90)
+ .setVoltageLevel("S1_90")
+ .add()
+ .add();
+ }
+
+ private static void createSwitch(VoltageLevel vl, String id, SwitchKind kind, int node1, int node2) {
+ vl.getNodeBreakerView().newSwitch()
+ .setId(id)
+ .setKind(kind)
+ .setOpen(true)
+ .setNode1(node1)
+ .setNode2(node2)
+ .add();
+ }
+}
diff --git a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/XMLExporterTest.java b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/XMLExporterTest.java
index b38b91254a2..d18d0e8dda7 100644
--- a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/XMLExporterTest.java
+++ b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/XMLExporterTest.java
@@ -56,7 +56,7 @@ void exportTest() throws IOException {
@Test
void paramsTest() {
var xmlExporter = new XMLExporter();
- assertEquals(10, xmlExporter.getParameters().size());
+ assertEquals(11, xmlExporter.getParameters().size());
assertEquals("IIDM XML v" + CURRENT_IIDM_VERSION.toString(".") + " exporter", xmlExporter.getComment());
}
diff --git a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/XMLImporterTest.java b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/XMLImporterTest.java
index 01e194663fb..90294d2fc8b 100644
--- a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/XMLImporterTest.java
+++ b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/XMLImporterTest.java
@@ -137,7 +137,7 @@ void getFormat() {
@Test
void getParameters() {
- assertEquals(2, importer.getParameters().size());
+ assertEquals(3, importer.getParameters().size());
assertEquals("iidm.import.xml.throw-exception-if-extension-not-found", importer.getParameters().get(0).getName());
assertEquals(Arrays.asList("iidm.import.xml.throw-exception-if-extension-not-found", "throwExceptionIfExtensionNotFound"), importer.getParameters().get(0).getNames());
}
diff --git a/iidm/iidm-serde/src/test/resources/V1_0/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_0/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..57741decbc2
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_0/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_1/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_1/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..24815f6c2e8
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_1/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_10/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_10/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..b7d479a61e8
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_10/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_11/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_11/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..2ac9f768f2a
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_11/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_12/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_12/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..027422ab9d7
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_12/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_2/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_2/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..18aadca2b1f
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_2/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_3/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_3/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..5ce6c74523e
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_3/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_4/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_4/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..5cccf75ba2b
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_4/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_5/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_5/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..e1a3fa3787f
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_5/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_6/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_6/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..4c9c25e0450
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_6/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_7/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_7/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..c6866f9cbec
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_7/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_8/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_8/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..3a06ecbcfa5
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_8/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iidm/iidm-serde/src/test/resources/V1_9/overloadManagementSystemRoundTripRef.xml b/iidm/iidm-serde/src/test/resources/V1_9/overloadManagementSystemRoundTripRef.xml
new file mode 100644
index 00000000000..ac324374aa4
--- /dev/null
+++ b/iidm/iidm-serde/src/test/resources/V1_9/overloadManagementSystemRoundTripRef.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+