diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportToCimVersionTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportToCimVersionTest.java index b8b2b83c39c..c8220987733 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportToCimVersionTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportToCimVersionTest.java @@ -8,7 +8,9 @@ import com.powsybl.cgmes.conversion.CgmesExport; import com.powsybl.cgmes.conversion.CgmesImport; +import com.powsybl.cgmes.conversion.CgmesModelExtension; import com.powsybl.cgmes.extensions.CimCharacteristics; +import com.powsybl.cgmes.model.CgmesModel; import com.powsybl.cgmes.model.test.cim14.Cim14SmallCasesCatalog; import com.powsybl.commons.AbstractConverterTest; import com.powsybl.commons.datasource.MemDataSource; @@ -23,7 +25,7 @@ import java.io.IOException; import java.util.Properties; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; /** * @author Luma @@ -60,7 +62,26 @@ public void testExportIEEE14Cim14ToCim100() { testExportToCim(network, "IEEE14", 100); } - private Network ieee14Cim14() { + @Test + public void testExportIEEE14ToCim100CheckIsNodeBreaker() { + // Testing export to CGMES 3 is interpreted as a node/breaker CGMES model + // Input was a bus/branch model + + Network network = ieee14Cim14(); + CgmesModel cgmesModel14 = network.getExtension(CgmesModelExtension.class).getCgmesModel(); + assertFalse(cgmesModel14.isNodeBreaker()); + + String cimZipFilename = "ieee14_CIM100"; + Properties params = new Properties(); + params.put(CgmesExport.CIM_VERSION, "100"); + ZipFileDataSource zip = new ZipFileDataSource(tmpDir.resolve("."), cimZipFilename); + new CgmesExport().export(network, params, zip); + Network network100 = Importers.loadNetwork(tmpDir.resolve(cimZipFilename + ".zip")); + CgmesModel cgmesModel100 = network100.getExtension(CgmesModelExtension.class).getCgmesModel(); + assertTrue(cgmesModel100.isNodeBreaker()); + } + + private static Network ieee14Cim14() { ReadOnlyDataSource dataSource = Cim14SmallCasesCatalog.ieee14().dataSource(); return new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), null); } diff --git a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesNamespace.java b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesNamespace.java index 5fda2d0a1f0..12e6a46b620 100644 --- a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesNamespace.java +++ b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesNamespace.java @@ -39,17 +39,18 @@ private CgmesNamespace() { public static final String EU_NAMESPACE = "http://iec.ch/TC57/CIM100-European#"; public static final String MD_NAMESPACE = "http://iec.ch/TC57/61970-552/ModelDescription/1#"; - private static final String CIM_16_EQ_PROFILE = "http://entsoe.eu/CIM/EquipmentCore/3/1"; - private static final String CIM_16_EQ_OPERATION_PROFILE = "http://entsoe.eu/CIM/EquipmentOperation/3/1"; - private static final String CIM_16_TP_PROFILE = "http://entsoe.eu/CIM/Topology/4/1"; - private static final String CIM_16_SV_PROFILE = "http://entsoe.eu/CIM/StateVariables/4/1"; - private static final String CIM_16_SSH_PROFILE = "http://entsoe.eu/CIM/SteadyStateHypothesis/1/1"; + public static final String CIM_16_EQ_PROFILE = "http://entsoe.eu/CIM/EquipmentCore/3/1"; + public static final String CIM_16_EQ_OPERATION_PROFILE = "http://entsoe.eu/CIM/EquipmentOperation/3/1"; + public static final String CIM_16_TP_PROFILE = "http://entsoe.eu/CIM/Topology/4/1"; + public static final String CIM_16_SV_PROFILE = "http://entsoe.eu/CIM/StateVariables/4/1"; + public static final String CIM_16_SSH_PROFILE = "http://entsoe.eu/CIM/SteadyStateHypothesis/1/1"; - private static final String CIM_100_EQ_PROFILE = "http://iec.ch/TC57/ns/CIM/CoreEquipment-EU/3.0"; - private static final String CIM_100_EQ_OPERATION_PROFILE = "http://iec.ch/TC57/ns/CIM/Operation-EU/3.0"; - private static final String CIM_100_TP_PROFILE = "http://iec.ch/TC57/ns/CIM/Topology-EU/3.0"; - private static final String CIM_100_SV_PROFILE = "http://iec.ch/TC57/ns/CIM/StateVariables-EU/3.0"; - private static final String CIM_100_SSH_PROFILE = "http://iec.ch/TC57/ns/CIM/SteadyStateHypothesis-EU/3.0"; + public static final String CGMES_EQ_3_OR_GREATER_PREFIX = "http://iec.ch/TC57/ns/CIM/CoreEquipment-EU/"; + public static final String CIM_100_EQ_PROFILE = "http://iec.ch/TC57/ns/CIM/CoreEquipment-EU/3.0"; + public static final String CIM_100_EQ_OPERATION_PROFILE = "http://iec.ch/TC57/ns/CIM/Operation-EU/3.0"; + public static final String CIM_100_TP_PROFILE = "http://iec.ch/TC57/ns/CIM/Topology-EU/3.0"; + public static final String CIM_100_SV_PROFILE = "http://iec.ch/TC57/ns/CIM/StateVariables-EU/3.0"; + public static final String CIM_100_SSH_PROFILE = "http://iec.ch/TC57/ns/CIM/SteadyStateHypothesis-EU/3.0"; private static final Map> PROFILES = Map.of( 16, Map.of("EQ", CIM_16_EQ_PROFILE, "EQ_OP", CIM_16_EQ_OPERATION_PROFILE, "SSH", CIM_16_SSH_PROFILE, "SV", CIM_16_SV_PROFILE, "TP", CIM_16_TP_PROFILE), diff --git a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/triplestore/CgmesModelTripleStore.java b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/triplestore/CgmesModelTripleStore.java index 2abd68b43be..06e423111c8 100644 --- a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/triplestore/CgmesModelTripleStore.java +++ b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/triplestore/CgmesModelTripleStore.java @@ -26,6 +26,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import static com.powsybl.cgmes.model.CgmesNamespace.CGMES_EQ_3_OR_GREATER_PREFIX; +import static com.powsybl.cgmes.model.CgmesNamespace.CIM_100_EQ_PROFILE; + /** * @author Luma ZamarreƱo */ @@ -163,6 +166,9 @@ private boolean computeIsNodeBreaker() { if (r == null) { return false; } + if (allEqCgmes3OrGreater(r)) { + return true; + } // Only consider is node breaker if all models that have profile // EquipmentCore or EquipmentBoundary // also have EquipmentOperation or EquipmentBoundaryOperation @@ -174,6 +180,20 @@ private boolean computeIsNodeBreaker() { return consideredNodeBreaker; } + private boolean allEqCgmes3OrGreater(PropertyBags modelProfiles) { + for (PropertyBag mp : modelProfiles) { + String p = mp.get(PROFILE); + if (p != null && isEquipmentCore(p) && !isEqCgmes3OrGreater(p)) { + return false; + } + } + return true; + } + + private static boolean isEqCgmes3OrGreater(String profile) { + return profile.startsWith(CGMES_EQ_3_OR_GREATER_PREFIX) && profile.compareTo(CIM_100_EQ_PROFILE) >= 0; + } + private void logNodeBreaker(boolean consideredNodeBreaker, Map modelHasOperationProfile) { if (consideredNodeBreaker) { LOG.info(