diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/Conversion.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/Conversion.java index 77f9a16d96c..832d57e047c 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/Conversion.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/Conversion.java @@ -281,6 +281,7 @@ private static void createControlArea(CgmesControlAreas cgmesControlAreas, Prope .setName(ca.getLocal("name")) .setEnergyIdentificationCodeEic(ca.getLocal("energyIdentCodeEic")) .setNetInterchange(ca.asDouble("netInterchange", Double.NaN)) + .setPTolerance(ca.asDouble("pTolerance", Double.NaN)) .add(); } @@ -385,6 +386,7 @@ private void addCgmesSshMetadata(Network network, Context context) { PropertyBags sshDescription = cgmes.fullModel(CgmesSubset.STEADY_STATE_HYPOTHESIS.getProfile()); if (sshDescription != null && !sshDescription.isEmpty()) { CgmesSshMetadataAdder adder = network.newExtension(CgmesSshMetadataAdder.class) + .setId(sshDescription.get(0).get("FullModel")) .setDescription(sshDescription.get(0).get("description")) .setSshVersion(readVersion(sshDescription, context)) .setModelingAuthoritySet(sshDescription.get(0).get("modelingAuthoritySet")); diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java index 80aedc85130..09a27062261 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java @@ -120,6 +120,7 @@ public static final class ModelDescription { private String description; private int version = 1; + private String supersedes; private final List dependencies = new ArrayList<>(); private String modelingAuthoritySet = "powsybl.org"; private Set ids = new HashSet<>(); @@ -136,6 +137,10 @@ public String getDescription() { return description; } + public String getSupersedes() { + return supersedes; + } + public ModelDescription setDescription(String description) { this.description = description; return this; @@ -208,6 +213,10 @@ public void setIds(String... ids) { public Set getIds() { return Collections.unmodifiableSet(ids); } + + public void setSupersedes(String id) { + this.supersedes = id; + } } public CgmesExportContext() { @@ -246,6 +255,7 @@ public CgmesExportContext(Network network, ReferenceDataProvider referenceDataPr if (sshMetadata != null) { sshModelDescription.setDescription(sshMetadata.getDescription()); sshModelDescription.setVersion(sshMetadata.getSshVersion() + 1); + sshModelDescription.setSupersedes(sshMetadata.getId()); sshModelDescription.addDependencies(sshMetadata.getDependencies()); sshModelDescription.setModelingAuthoritySet(sshMetadata.getModelingAuthoritySet()); } diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportUtil.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportUtil.java index ad7a4a64f6a..14162c4643a 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportUtil.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportUtil.java @@ -132,6 +132,10 @@ public static void writeModelDescription(XMLStreamWriter writer, ModelDescriptio writer.writeEmptyElement(MD_NAMESPACE, CgmesNames.DEPENDENT_ON); writer.writeAttribute(RDF_NAMESPACE, CgmesNames.RESOURCE, dependency); } + if (modelDescription.getSupersedes() != null) { + writer.writeEmptyElement(MD_NAMESPACE, CgmesNames.SUPERSEDES); + writer.writeAttribute(RDF_NAMESPACE, CgmesNames.RESOURCE, modelDescription.getSupersedes()); + } writer.writeStartElement(MD_NAMESPACE, CgmesNames.PROFILE); writer.writeCharacters(modelDescription.getProfile()); writer.writeEndElement(); diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java index ec18f4b1cd3..2c7206afe48 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java @@ -62,7 +62,6 @@ public static void write(Network network, XMLStreamWriter writer, CgmesExportCon writeConverters(network, cimNamespace, writer, context); // FIXME open status of retained switches in bus-branch models writeSwitches(network, cimNamespace, writer, context); - // TODO writeControlAreas writeTerminals(network, cimNamespace, writer, context); writeControlAreas(network, cimNamespace, writer, context); @@ -778,6 +777,9 @@ private static void writeControlArea(CgmesControlArea area, String cimNamespace, writer.writeStartElement(cimNamespace, "ControlArea.netInterchange"); writer.writeCharacters(CgmesExportUtil.format(area.getNetInterchange())); writer.writeEndElement(); + writer.writeStartElement(cimNamespace, "ControlArea.pTolerance"); + writer.writeCharacters(CgmesExportUtil.format(area.getPTolerance())); + writer.writeEndElement(); writer.writeEndElement(); } diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportXmlCompare.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportXmlCompare.java index a843eb73c1e..63214ef4223 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportXmlCompare.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportXmlCompare.java @@ -288,6 +288,19 @@ static ComparisonResult noKnownDiffs(Comparison comparison, ComparisonResult res return result; } + static ComparisonResult ignoringCgmesSshMetadataId(Comparison comparison, ComparisonResult result) { + if (result == ComparisonResult.DIFFERENT) { + Node control = comparison.getControlDetails().getTarget(); + if (comparison.getType() == ComparisonType.ATTR_VALUE + && control.getNodeName().equals("id")) { + if (comparison.getControlDetails().getXPath().contains("cgmesSshMetadata")) { + return ComparisonResult.EQUAL; + } + } + } + return result; + } + static ComparisonResult ensuringIncreasedModelVersion(Comparison comparison, ComparisonResult result) { if (result == ComparisonResult.DIFFERENT) { Node control = comparison.getControlDetails().getTarget(); diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java index 13a2160174d..d5b2afd4f12 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java @@ -8,9 +8,12 @@ import com.powsybl.cgmes.conformity.CgmesConformity1Catalog; import com.powsybl.cgmes.conformity.CgmesConformity1ModifiedCatalog; +import com.powsybl.cgmes.conformity.CgmesConformity3Catalog; +import com.powsybl.cgmes.conversion.CgmesExport; import com.powsybl.cgmes.conversion.CgmesImport; import com.powsybl.cgmes.conversion.export.CgmesExportContext; import com.powsybl.cgmes.conversion.export.SteadyStateHypothesisExport; +import com.powsybl.cgmes.extensions.CgmesControlArea; import com.powsybl.cgmes.extensions.CgmesControlAreas; import com.powsybl.cgmes.model.CgmesNamespace; import com.powsybl.commons.test.AbstractConverterTest; @@ -31,9 +34,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; +import java.util.*; import static org.junit.jupiter.api.Assertions.*; @@ -45,31 +46,40 @@ class SteadyStateHypothesisExportTest extends AbstractConverterTest { @Test void microGridBE() throws IOException, XMLStreamException { - DifferenceEvaluator knownDiffs = DifferenceEvaluators.chain( + DifferenceEvaluator knownDiffsSsh = DifferenceEvaluators.chain( ExportXmlCompare::sameScenarioTime, ExportXmlCompare::ensuringIncreasedModelVersion, ExportXmlCompare::ignoringSynchronousMachinesSVCsWithTargetDeadband, ExportXmlCompare::ignoringJunctionOrBusbarTerminals); - test(CgmesConformity1Catalog.microGridBaseCaseBE().dataSource(), 2, knownDiffs); + DifferenceEvaluator knownDiffsXiidm = DifferenceEvaluators.chain( + DifferenceEvaluators.Default, + ExportXmlCompare::ignoringCgmesSshMetadataId); + test(CgmesConformity1Catalog.microGridBaseCaseBE().dataSource(), 2, knownDiffsSsh, knownDiffsXiidm); } @Test void microGridBEWithHiddenTapChangers() throws IOException, XMLStreamException { - DifferenceEvaluator knownDiffs = DifferenceEvaluators.chain( + DifferenceEvaluator knownDiffsSsh = DifferenceEvaluators.chain( ExportXmlCompare::sameScenarioTime, ExportXmlCompare::ensuringIncreasedModelVersion, ExportXmlCompare::ignoringSynchronousMachinesSVCsWithTargetDeadband, ExportXmlCompare::ignoringJunctionOrBusbarTerminals); - test(CgmesConformity1ModifiedCatalog.microGridBaseCaseBEHiddenTapChangers().dataSource(), 2, knownDiffs); + DifferenceEvaluator knownDiffsXiidm = DifferenceEvaluators.chain( + DifferenceEvaluators.Default, + ExportXmlCompare::ignoringCgmesSshMetadataId); + test(CgmesConformity1ModifiedCatalog.microGridBaseCaseBEHiddenTapChangers().dataSource(), 2, knownDiffsSsh, knownDiffsXiidm); } @Test void microGridBEWithSharedRegulatingControl() throws IOException, XMLStreamException { - DifferenceEvaluator knownDiffs = DifferenceEvaluators.chain( + DifferenceEvaluator knownDiffsSsh = DifferenceEvaluators.chain( ExportXmlCompare::sameScenarioTime, ExportXmlCompare::ensuringIncreasedModelVersion, ExportXmlCompare::ignoringJunctionOrBusbarTerminals); - test(CgmesConformity1ModifiedCatalog.microGridBaseCaseBESharedRegulatingControl().dataSource(), 2, knownDiffs); + DifferenceEvaluator knownDiffsXiidm = DifferenceEvaluators.chain( + DifferenceEvaluators.Default, + ExportXmlCompare::ignoringCgmesSshMetadataId); + test(CgmesConformity1ModifiedCatalog.microGridBaseCaseBESharedRegulatingControl().dataSource(), 2, knownDiffsSsh, knownDiffsXiidm); } @Test @@ -81,6 +91,7 @@ void smallGrid() throws IOException, XMLStreamException { test(CgmesConformity1Catalog.smallBusBranch().dataSource(), 4, knownDiffs, DifferenceEvaluators.chain( DifferenceEvaluators.Default, ExportXmlCompare::numericDifferenceEvaluator, + ExportXmlCompare::ignoringCgmesSshMetadataId, ExportXmlCompare::ignoringControlAreaNetInterchange)); } @@ -94,6 +105,7 @@ void smallGridHVDC() throws IOException, XMLStreamException { DifferenceEvaluators.Default, ExportXmlCompare::numericDifferenceEvaluator, ExportXmlCompare::ignoringControlAreaNetInterchange, + ExportXmlCompare::ignoringCgmesSshMetadataId, ExportXmlCompare::ignoringHvdcLinePmax)); } @@ -222,4 +234,111 @@ void add(String shuntCompensatorId, int sections, boolean controlEnabled) { map.put(shuntCompensatorId, Pair.of(sections, controlEnabled)); } } + + @Test + void testUpdateControlArea() throws IOException { + Path outputPath = tmpDir.resolve("update-control-areas"); + Files.createDirectories(outputPath); + + // Read network and check control area data + Network be = Network.read(CgmesConformity3Catalog.microGridBaseCaseBE().dataSource()); + CgmesControlAreas controlAreas = be.getExtension(CgmesControlAreas.class); + assertNotNull(controlAreas); + System.out.println("cgmes control areas = " + controlAreas); + assertFalse(controlAreas.getCgmesControlAreas().isEmpty()); + CgmesControlArea controlArea = controlAreas.getCgmesControlAreas().iterator().next(); + assertEquals(236.9798, controlArea.getNetInterchange(), 1e-10); + assertEquals(10, controlArea.getPTolerance(), 1e-10); + + // Update control area data + controlArea.setNetInterchange(controlArea.getNetInterchange() * 2); + controlArea.setPTolerance(controlArea.getPTolerance() / 2); + + // Write and read the network to check serialization of the extension + Path updatedXiidm = outputPath.resolve("BE-updated.xiidm"); + be.write("XIIDM", null, updatedXiidm); + Network beUpdated = Network.read(updatedXiidm); + + // Export only SSH instance file + Properties exportParams = new Properties(); + exportParams.put(CgmesExport.PROFILES, "SSH"); + beUpdated.write("CGMES", exportParams, outputPath.resolve("BE")); + + // Check that exported SSH contains updated values for net interchange and p tolerance + Collection sshExportedControlAreas = readSshControlAreas(outputPath.resolve("BE_SSH.xml")); + assertFalse(sshExportedControlAreas.isEmpty()); + SshExportedControlArea sshExportedControlArea = sshExportedControlAreas.iterator().next(); + assertEquals(473.9596, sshExportedControlArea.netInterchange, 1e-10); + assertEquals(5, sshExportedControlArea.pTolerance, 1e-10); + + // Check that SSH full model contains a reference to the original SSH that is superseding + String modelSupersedes = readSshModelSupersedes(outputPath.resolve("BE_SSH.xml")); + assertEquals("urn:uuid:1b092ff0-f8a0-49da-82d3-75eff5f1e820", modelSupersedes); + } + + static class SshExportedControlArea { + String id; + double netInterchange; + double pTolerance; + } + + private static final String ATTR_ABOUT = "about"; + private static final String CONTROL_AREA = "ControlArea"; + private static final String CONTROL_AREA_NET_INTERCHANGE = "ControlArea.netInterchange"; + private static final String CONTROL_AREA_P_TOLERANCE = "ControlArea.pTolerance"; + + private static Collection readSshControlAreas(Path ssh) { + List sshExportedControlAreas = new ArrayList<>(); + SshExportedControlArea sshExportedControlArea = null; + try (InputStream is = Files.newInputStream(ssh)) { + XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(is); + while (reader.hasNext()) { + int next = reader.next(); + if (next == XMLStreamConstants.START_ELEMENT) { + if (reader.getLocalName().equals(CONTROL_AREA)) { + sshExportedControlArea = new SshExportedControlArea(); + sshExportedControlArea.id = reader.getAttributeValue(CgmesNamespace.RDF_NAMESPACE, ATTR_ABOUT).substring(2); + } else if (reader.getLocalName().equals(CONTROL_AREA_NET_INTERCHANGE) && sshExportedControlArea != null) { + sshExportedControlArea.netInterchange = Double.parseDouble(reader.getElementText()); + } else if (reader.getLocalName().equals(CONTROL_AREA_P_TOLERANCE) && sshExportedControlArea != null) { + sshExportedControlArea.pTolerance = Double.parseDouble(reader.getElementText()); + } + } else if (next == XMLStreamConstants.END_ELEMENT) { + if (reader.getLocalName().equals(CONTROL_AREA) && sshExportedControlArea != null) { + sshExportedControlAreas.add(sshExportedControlArea); + sshExportedControlArea = null; + } + } + } + reader.close(); + } catch (XMLStreamException | IOException e) { + throw new RuntimeException(e); + } + return sshExportedControlAreas; + } + + private static final String ATTR_RESOURCE = "resource"; + private static final String MODEL_SUPERSEDES = "Model.Supersedes"; + + private static String readSshModelSupersedes(Path ssh) { + String modelSupersedes; + try (InputStream is = Files.newInputStream(ssh)) { + XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(is); + while (reader.hasNext()) { + int next = reader.next(); + if (next == XMLStreamConstants.START_ELEMENT) { + if (reader.getLocalName().equals(MODEL_SUPERSEDES)) { + modelSupersedes = reader.getAttributeValue(CgmesNamespace.RDF_NAMESPACE, ATTR_RESOURCE); + reader.close(); + return modelSupersedes; + } + } + } + reader.close(); + } catch (XMLStreamException | IOException e) { + throw new RuntimeException(e); + } + return null; + } + } diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlArea.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlArea.java index 399a2fcd33a..1de89332e5b 100644 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlArea.java +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlArea.java @@ -6,6 +6,7 @@ */ package com.powsybl.cgmes.extensions; +import com.powsybl.commons.PowsyblException; import com.powsybl.iidm.network.Boundary; import com.powsybl.iidm.network.Terminal; @@ -31,4 +32,16 @@ public interface CgmesControlArea { Set getTerminals(); Set getBoundaries(); + + default void setNetInterchange(double netInterchange) { + throw new PowsyblException("Unsupported method"); + } + + default double getPTolerance() { + throw new PowsyblException("Unsupported method"); + } + + default void setPTolerance(double pTolerance) { + throw new PowsyblException("Unsupported method"); + } } diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdder.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdder.java index b90f40db0d0..c35a65d6d86 100644 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdder.java +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdder.java @@ -6,6 +6,8 @@ */ package com.powsybl.cgmes.extensions; +import com.powsybl.commons.PowsyblException; + /** * @author Miora Ralambotiana */ @@ -19,5 +21,9 @@ public interface CgmesControlAreaAdder { CgmesControlAreaAdder setNetInterchange(double netInterchange); + default CgmesControlAreaAdder setPTolerance(double pTolerance) { + throw new PowsyblException("Unsupported method"); + } + CgmesControlArea add(); } diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdderImpl.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdderImpl.java index 263c49a72d3..9d0ad39d2e1 100644 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdderImpl.java +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdderImpl.java @@ -20,6 +20,7 @@ class CgmesControlAreaAdderImpl implements CgmesControlAreaAdder { private String name; private String energyIdentificationCodeEic; private double netInterchange = Double.NaN; + private double pTolerance = Double.NaN; CgmesControlAreaAdderImpl(CgmesControlAreasImpl mapping) { this.mapping = Objects.requireNonNull(mapping); @@ -49,11 +50,17 @@ public CgmesControlAreaAdder setNetInterchange(double netInterchange) { return this; } + @Override + public CgmesControlAreaAdder setPTolerance(double pTolerance) { + this.pTolerance = pTolerance; + return this; + } + @Override public CgmesControlAreaImpl add() { if (id == null) { throw new PowsyblException("Undefined ID for CGMES control area"); } - return new CgmesControlAreaImpl(id, name, energyIdentificationCodeEic, netInterchange, mapping); + return new CgmesControlAreaImpl(id, name, energyIdentificationCodeEic, netInterchange, pTolerance, mapping); } } diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaImpl.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaImpl.java index ee0a7aea855..e734698b919 100644 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaImpl.java +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaImpl.java @@ -20,13 +20,15 @@ class CgmesControlAreaImpl implements CgmesControlArea { private final String energyIdentificationCodeEic; private final Set terminals = new LinkedHashSet<>(); private final Set boundaries = new LinkedHashSet<>(); - private final double netInterchange; + private double netInterchange; + private double pTolerance; - CgmesControlAreaImpl(String id, String name, String energyIdentificationCodeEic, double netInterchange, CgmesControlAreasImpl mapping) { + CgmesControlAreaImpl(String id, String name, String energyIdentificationCodeEic, double netInterchange, double pTolerance, CgmesControlAreasImpl mapping) { this.id = Objects.requireNonNull(id); this.name = name; this.energyIdentificationCodeEic = energyIdentificationCodeEic; this.netInterchange = netInterchange; + this.pTolerance = pTolerance; attach(mapping); } @@ -73,4 +75,19 @@ public void add(Terminal terminal) { public void add(Boundary boundary) { boundaries.add(boundary); } + + @Override + public void setNetInterchange(double netInterchange) { + this.netInterchange = netInterchange; + } + + @Override + public double getPTolerance() { + return pTolerance; + } + + @Override + public void setPTolerance(double pTolerance) { + this.pTolerance = pTolerance; + } } diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasXmlSerializer.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasXmlSerializer.java index fbfbdb0d4b0..b9743aaeb6a 100644 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasXmlSerializer.java +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasXmlSerializer.java @@ -52,6 +52,7 @@ public void write(CgmesControlAreas extension, XmlWriterContext context) throws writer.writeAttribute("energyIdentificationCodeEic", controlArea.getEnergyIdentificationCodeEIC()); } XmlUtil.writeDouble("netInterchange", controlArea.getNetInterchange(), writer); + XmlUtil.writeDouble("pTolerance", controlArea.getPTolerance(), writer); for (Terminal terminal : controlArea.getTerminals()) { TerminalRefXml.writeTerminalRef(terminal, networkContext, getNamespaceUri(), "terminal"); } @@ -94,6 +95,7 @@ public CgmesControlAreas read(Network extendable, XmlReaderContext context) thro .setName(reader.getAttributeValue(null, "name")) .setEnergyIdentificationCodeEic(reader.getAttributeValue(null, "energyIdentificationCodeEic")) .setNetInterchange(XmlUtil.readOptionalDoubleAttribute(reader, "netInterchange")) + .setPTolerance(XmlUtil.readOptionalDoubleAttribute(reader, "pTolerance")) .add(); readBoundariesAndTerminals(networkContext, reader, cgmesControlArea, extendable); } else { diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadata.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadata.java index a92806a2dd2..dc87f261514 100644 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadata.java +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadata.java @@ -6,6 +6,7 @@ */ package com.powsybl.cgmes.extensions; +import com.powsybl.commons.PowsyblException; import com.powsybl.commons.extensions.Extension; import com.powsybl.iidm.network.Network; @@ -19,6 +20,10 @@ public interface CgmesSshMetadata extends Extension { String NAME = "cgmesSshMetadata"; + default String getId() { + throw new PowsyblException("Unsupported method"); + } + String getDescription(); int getSshVersion(); diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataAdder.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataAdder.java index f805ff19314..237998c7cac 100644 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataAdder.java +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataAdder.java @@ -6,6 +6,7 @@ */ package com.powsybl.cgmes.extensions; +import com.powsybl.commons.PowsyblException; import com.powsybl.commons.extensions.ExtensionAdder; import com.powsybl.iidm.network.Network; @@ -15,6 +16,10 @@ */ public interface CgmesSshMetadataAdder extends ExtensionAdder { + default CgmesSshMetadataAdder setId(String id) { + throw new PowsyblException("Unsupported method"); + } + CgmesSshMetadataAdder setDescription(String description); CgmesSshMetadataAdder setSshVersion(int sshVersion); diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataAdderImpl.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataAdderImpl.java index e7340d16770..8d321a90fc7 100644 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataAdderImpl.java +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataAdderImpl.java @@ -20,6 +20,7 @@ */ class CgmesSshMetadataAdderImpl extends AbstractExtensionAdder implements CgmesSshMetadataAdder { + private String id; private String description; private int sshVersion = 0; private final List dependencies = new ArrayList<>(); @@ -29,6 +30,12 @@ public CgmesSshMetadataAdderImpl(Network extendable) { super(extendable); } + @Override + public CgmesSshMetadataAdder setId(String id) { + this.id = id; + return this; + } + @Override public CgmesSshMetadataAdder setDescription(String description) { this.description = description; @@ -61,6 +68,6 @@ protected CgmesSshMetadata createExtension(Network extendable) { if (modelingAuthoritySet == null) { throw new PowsyblException("cgmesSshMetadata.modelingAuthoritySet is undefined"); } - return new CgmesSshMetadataImpl(description, sshVersion, dependencies, modelingAuthoritySet); + return new CgmesSshMetadataImpl(id, description, sshVersion, dependencies, modelingAuthoritySet); } } diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataImpl.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataImpl.java index 5425d9f2842..5feb3131e5f 100644 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataImpl.java +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataImpl.java @@ -20,18 +20,25 @@ */ class CgmesSshMetadataImpl extends AbstractExtension implements CgmesSshMetadata { + private final String id; private final String description; private final int sshVersion; private final List dependencies = new ArrayList<>(); private final String modelingAuthoritySet; - public CgmesSshMetadataImpl(String description, int sshVersion, List dependencies, String modelingAuthoritySet) { + public CgmesSshMetadataImpl(String id, String description, int sshVersion, List dependencies, String modelingAuthoritySet) { + this.id = id; this.description = description; this.sshVersion = sshVersion; this.dependencies.addAll(Objects.requireNonNull(dependencies)); this.modelingAuthoritySet = Objects.requireNonNull(modelingAuthoritySet); } + @Override + public String getId() { + return id; + } + @Override public String getDescription() { return description; diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataXmlSerializer.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataXmlSerializer.java index de8706b90b7..37d716de7d0 100644 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataXmlSerializer.java +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesSshMetadataXmlSerializer.java @@ -37,6 +37,9 @@ public CgmesSshMetadataXmlSerializer() { public void write(CgmesSshMetadata extension, XmlWriterContext context) throws XMLStreamException { NetworkXmlWriterContext networkContext = (NetworkXmlWriterContext) context; XMLStreamWriter writer = networkContext.getWriter(); + if (extension.getId() != null) { + writer.writeAttribute("id", extension.getId()); + } if (extension.getDescription() != null) { writer.writeAttribute("description", extension.getDescription()); } @@ -55,6 +58,7 @@ public CgmesSshMetadata read(Network extendable, XmlReaderContext context) throw XMLStreamReader reader = networkContext.getReader(); CgmesSshMetadataAdder adder = extendable.newExtension(CgmesSshMetadataAdder.class); adder.setDescription(reader.getAttributeValue(null, "description")) + .setId(reader.getAttributeValue(null, "id")) .setSshVersion(XmlUtil.readIntAttribute(reader, "sshVersion")) .setModelingAuthoritySet(reader.getAttributeValue(null, "modelingAuthoritySet")); XmlUtil.readUntilEndElement("cgmesSshMetadata", reader, () -> { diff --git a/cgmes/cgmes-extensions/src/main/resources/xsd/cgmesControlAreas.xsd b/cgmes/cgmes-extensions/src/main/resources/xsd/cgmesControlAreas.xsd index b71ca046892..ff847b57b94 100644 --- a/cgmes/cgmes-extensions/src/main/resources/xsd/cgmesControlAreas.xsd +++ b/cgmes/cgmes-extensions/src/main/resources/xsd/cgmesControlAreas.xsd @@ -32,6 +32,7 @@ + diff --git a/cgmes/cgmes-extensions/src/main/resources/xsd/cgmesSshMetadata.xsd b/cgmes/cgmes-extensions/src/main/resources/xsd/cgmesSshMetadata.xsd index be20f199276..fb294524cd3 100644 --- a/cgmes/cgmes-extensions/src/main/resources/xsd/cgmesSshMetadata.xsd +++ b/cgmes/cgmes-extensions/src/main/resources/xsd/cgmesSshMetadata.xsd @@ -14,6 +14,7 @@ +