diff --git a/cgmes/cgmes-conformity/src/main/java/com/powsybl/cgmes/conformity/CgmesConformity1ModifiedCatalog.java b/cgmes/cgmes-conformity/src/main/java/com/powsybl/cgmes/conformity/CgmesConformity1ModifiedCatalog.java index 587eee314c4..7580c6a161d 100644 --- a/cgmes/cgmes-conformity/src/main/java/com/powsybl/cgmes/conformity/CgmesConformity1ModifiedCatalog.java +++ b/cgmes/cgmes-conformity/src/main/java/com/powsybl/cgmes/conformity/CgmesConformity1ModifiedCatalog.java @@ -1561,6 +1561,20 @@ public static GridModelReference microGridBaseBEInvalidVoltageBus() { microGridBaseCaseBoundaries()); } + public static GridModelReference microGridBaseCaseBELineDisconnectedAtBoundaryNode() { + String base = ENTSOE_CONFORMITY_1_MODIFIED + + "/MicroGrid/BaseCase/BC_BE_v2_line_disconnected_at_boundary_node/"; + return new GridModelReferenceResources( + "MicroGrid-BaseCase-BE-line-disconnected-at-boundary-node", + null, + new ResourceSet(base, + MICRO_GRID_BE_SSH), + new ResourceSet(MICRO_GRID_BE_BASE, + MICRO_GRID_BE_EQ, + MICRO_GRID_BE_TP), + microGridBaseCaseBoundaries()); + } + public static GridModelReferenceResources smallGridBusBranchWithBusbarSectionsAndIpMax() { String base = ENTSOE_CONFORMITY_1_MODIFIED + "/SmallGrid/BusBranch_busbarSections_ipMax"; diff --git a/cgmes/cgmes-conformity/src/main/resources/conformity-modified/cas-1.1.3-data-4.0.3/MicroGrid/BaseCase/BC_BE_v2_line_disconnected_at_boundary_node/MicroGridTestConfiguration_BC_BE_SSH_V2.xml b/cgmes/cgmes-conformity/src/main/resources/conformity-modified/cas-1.1.3-data-4.0.3/MicroGrid/BaseCase/BC_BE_v2_line_disconnected_at_boundary_node/MicroGridTestConfiguration_BC_BE_SSH_V2.xml new file mode 100644 index 00000000000..3338257bca9 --- /dev/null +++ b/cgmes/cgmes-conformity/src/main/resources/conformity-modified/cas-1.1.3-data-4.0.3/MicroGrid/BaseCase/BC_BE_v2_line_disconnected_at_boundary_node/MicroGridTestConfiguration_BC_BE_SSH_V2.xml @@ -0,0 +1,286 @@ + + + + 2014-10-24T11:42:40 + 2014-06-01T10:30:00 + 2 + + CGMES Conformity Assessment: 'MicroGridTestConfiguration....BC (MAS BE) Test Configuration. The model is owned by ENTSO-E and is provided by ENTSO-E “as it is”. To the fullest extent permitted by law, ENTSO-E shall not be liable for any damages of any kind arising out of the use of the model (including any of its subsequent modifications). ENTSO-E neither warrants, nor represents that the use of the model will not infringe the rights of third parties. Any use of the model shall include a reference to ENTSO-E. ENTSO-E web site is the only official source of information related to the model. + http://elia.be/CGMES/2.4.15 + http://entsoe.eu/CIM/SteadyStateHypothesis/1/1 + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + false + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + 1.000000 + 0e+000 + + + 200.000000 + 90.000000 + + + 200.000000 + 50.000000 + + + 0e+000 + + + -118.000000 + -18.720301 + + 0 + true + + + 0e+000 + + + -90.000000 + -100.256000 + + 0 + true + + + 10 + true + + + 10 + false + + + 14 + true + + + 17 + false + + + 1 + false + + + 1 + false + + + -26.805006 + 1.489867 + false + 0.0 + + + -27.365225 + 0.425626 + false + 0.0 + + + -43.687227 + 84.876604 + false + 0.0 + + + -46.816625 + 79.193778 + false + 0.0 + + + -90.037005 + 148.603743 + false + 0.0 + + + true + 35.00000 + + true + -65.000000 + + + true + 0.500000 + + false + 0e+000 + + + true + 0.500000 + + true + 10.815000 + + + true + 0.500000 + + false + 0e+000 + + + false + 0.500000 + + true + 21.987000 + + + false + 0.500000 + + true + 115.500000 + + + true + 0.500000 + + false + 110.000000 + + + true + 0.500000 + + false + 380.000000 + + diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesImport.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesImport.java index 4f177e69a85..e282966e27a 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesImport.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesImport.java @@ -277,6 +277,12 @@ private Conversion.Config config(ReadOnlyDataSource ds, Properties p) { getFormat(), p, IMPORT_NODE_BREAKER_AS_BUS_BREAKER_PARAMETER, + defaultValueConfig)) + .setDisconnectNetworkSideOfDanglingLinesIfBoundaryIsDisconnected( + Parameter.readBoolean( + getFormat(), + p, + DISCONNECT_DANGLING_LINE_IF_BOUNDARY_SIDE_IS_DISCONNECTED_PARAMETER, defaultValueConfig)); String namingStrategy = Parameter.readString(getFormat(), p, NAMING_STRATEGY_PARAMETER, defaultValueConfig); String idMappingFilePath = Parameter.readString(getFormat(), p, ID_MAPPING_FILE_PATH_PARAMETER, defaultValueConfig); @@ -350,6 +356,7 @@ private void copyStream(ReadOnlyDataSource from, DataSource to, String fromName, public static final String STORE_CGMES_MODEL_AS_NETWORK_EXTENSION = "iidm.import.cgmes.store-cgmes-model-as-network-extension"; public static final String STORE_CGMES_CONVERSION_CONTEXT_AS_NETWORK_EXTENSION = "iidm.import.cgmes.store-cgmes-conversion-context-as-network-extension"; public static final String IMPORT_NODE_BREAKER_AS_BUS_BREAKER = "iidm.import.cgmes.import-node-breaker-as-bus-breaker"; + public static final String DISCONNECT_DANGLING_LINE_IF_BOUNDARY_SIDE_IS_DISCONNECTED = "iidm.import.cgmes.disconnect-dangling-line-if-boundary-side-is-disconnected"; public static final String SOURCE_FOR_IIDM_ID_MRID = "mRID"; public static final String SOURCE_FOR_IIDM_ID_RDFID = "rdfID"; @@ -459,6 +466,11 @@ private void copyStream(ReadOnlyDataSource from, DataSource to, String fromName, ParameterType.BOOLEAN, "Force import of CGMES node/breaker models as bus/breaker", Boolean.FALSE); + public static final Parameter DISCONNECT_DANGLING_LINE_IF_BOUNDARY_SIDE_IS_DISCONNECTED_PARAMETER = new Parameter( + DISCONNECT_DANGLING_LINE_IF_BOUNDARY_SIDE_IS_DISCONNECTED, + ParameterType.BOOLEAN, + "Force disconnection of dangling line network side if boundary side is disconnected", + Boolean.TRUE); private static final List STATIC_PARAMETERS = List.of( ALLOW_UNSUPPORTED_TAP_CHANGERS_PARAMETER, @@ -478,7 +490,8 @@ private void copyStream(ReadOnlyDataSource from, DataSource to, String fromName, CREATE_ACTIVE_POWER_CONTROL_EXTENSION_PARAMETER, DECODE_ESCAPED_IDENTIFIERS_PARAMETER, CREATE_FICTITIOUS_SWITCHES_FOR_DISCONNECTED_TERMINALS_MODE_PARAMETER, - IMPORT_NODE_BREAKER_AS_BUS_BREAKER_PARAMETER); + IMPORT_NODE_BREAKER_AS_BUS_BREAKER_PARAMETER, + DISCONNECT_DANGLING_LINE_IF_BOUNDARY_SIDE_IS_DISCONNECTED_PARAMETER); private final Parameter boundaryLocationParameter; private final Parameter preProcessorsParameter; diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesReports.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesReports.java index 7f2fb0967e2..9ddedddfa97 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesReports.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesReports.java @@ -85,4 +85,13 @@ public static void inconsistentProfilesTPRequiredReport(Reporter reporter, Strin .withSeverity(TypedValue.ERROR_SEVERITY) .build()); } + + public static void danglingLineDisconnectedAtBoundaryHasBeenDisconnectedReport(Reporter reporter, String danglingLineId) { + reporter.report(Report.builder() + .withKey("danglingLineDisconnectedAtBoundaryHasBeenDisconnected") + .withDefaultMessage("DanglingLine ${danglingLineId} was connected at network side and disconnected at boundary side. It has been disconnected also at network side.") + .withValue("danglingLineId", danglingLineId) + .withSeverity(TypedValue.WARN_SEVERITY) + .build()); + } } 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 bc661a590af..aad27e9703a 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 @@ -239,6 +239,7 @@ public Network convert(Reporter reporter) { } // apply post-processors + handleDangingLineDisconnectedAtBoundary(network, context); for (CgmesImportPostProcessor postProcessor : postProcessors) { // FIXME generic cgmes models may not have an underlying triplestore // TODO maybe pass the properties to the post processors @@ -258,6 +259,28 @@ public Network convert(Reporter reporter) { return network; } + private void handleDangingLineDisconnectedAtBoundary(Network network, Context context) { + if (config.disconnectNetworkSideOfDanglingLinesIfBoundaryIsDisconnected()) { + for (DanglingLine dl : network.getDanglingLines()) { + String terminalBoundaryId = dl.getAliasFromType(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + "Terminal_Boundary").orElse(null); + if (terminalBoundaryId == null) { + LOG.warn("Dangling line {}: alias for terminal at boundary is missing", dl.getId()); + } else { + CgmesTerminal terminalBoundary = cgmes.terminal(terminalBoundaryId); + if (terminalBoundary == null) { + LOG.warn("Dangling line {}: terminal at boundary with id {} is not found in CGMES model", dl.getId(), terminalBoundaryId); + } else { + if (!terminalBoundary.connected() && dl.getTerminal().isConnected()) { + LOG.warn("DanglingLine {} was connected at network side and disconnected at boundary side. It has been disconnected also at network side.", dl.getId()); + CgmesReports.danglingLineDisconnectedAtBoundaryHasBeenDisconnectedReport(context.getReporter(), dl.getId()); + dl.getTerminal().disconnect(); + } + } + } + } + } + } + private Source isBoundaryBaseVoltage(String graph) { //There are unit tests where the boundary file contains the sequence "EQBD" and others "EQ_BD" return graph.contains("EQ") && graph.contains("BD") ? Source.BOUNDARY : Source.IGM; @@ -913,6 +936,15 @@ public Config createFictitiousSwitchesForDisconnectedTerminalsMode(CgmesImport.F return this; } + public Config setDisconnectNetworkSideOfDanglingLinesIfBoundaryIsDisconnected(boolean b) { + disconnectNetworkSideOfDanglingLinesIfBoundaryIsDisconnected = b; + return this; + } + + public boolean disconnectNetworkSideOfDanglingLinesIfBoundaryIsDisconnected() { + return disconnectNetworkSideOfDanglingLinesIfBoundaryIsDisconnected; + } + private boolean allowUnsupportedTapChangers = true; private boolean convertBoundary = false; private boolean changeSignForShuntReactivePowerFlowInitialState = false; @@ -931,6 +963,7 @@ public Config createFictitiousSwitchesForDisconnectedTerminalsMode(CgmesImport.F private boolean ensureIdAliasUnicity = false; private boolean importControlAreas = true; private boolean importNodeBreakerAsBusBreaker = false; + private boolean disconnectNetworkSideOfDanglingLinesIfBoundaryIsDisconnected = true; private NamingStrategy namingStrategy = new NamingStrategy.Identity(); diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java index c09d81b7db3..4c6f869d5e4 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java @@ -997,6 +997,22 @@ void microGridBaseBETargetDeadbandNegative() { assertFalse(rtc.isRegulating()); } + @Test + void microGridBELineDisconnectedAtBoundaryNode() { + Properties importParams = new Properties(); + String dlId = "17086487-56ba-4979-b8de-064025a6b4da"; + + importParams.setProperty(CgmesImport.DISCONNECT_DANGLING_LINE_IF_BOUNDARY_SIDE_IS_DISCONNECTED, "true"); + Network be0 = Network.read(CgmesConformity1ModifiedCatalog.microGridBaseCaseBELineDisconnectedAtBoundaryNode().dataSource(), importParams); + Bus bus0 = be0.getDanglingLine(dlId).getTerminal().getBusView().getBus(); + assertNull(bus0); + + importParams.setProperty(CgmesImport.DISCONNECT_DANGLING_LINE_IF_BOUNDARY_SIDE_IS_DISCONNECTED, "false"); + Network be1 = Network.read(CgmesConformity1ModifiedCatalog.microGridBaseCaseBELineDisconnectedAtBoundaryNode().dataSource(), importParams); + Bus bus1 = be1.getDanglingLine(dlId).getTerminal().getBusView().getBus(); + assertNotNull(bus1); + } + private static void checkTerminals(PropertyBags eqSeq, PropertyBags eqNoSeq, String idPropertyName, String terminal1PropertyName, String terminal2PropertyName) { Map eqsSeqTerminal1 = eqSeq.stream().collect(Collectors.toMap(acls -> acls.getId(idPropertyName), acls -> acls.getId(terminal1PropertyName))); Map eqsSeqTerminal2 = eqSeq.stream().collect(Collectors.toMap(acls -> acls.getId(idPropertyName), acls -> acls.getId(terminal2PropertyName)));