Skip to content

Commit 455fd74

Browse files
authored
CGMES export as bus/branch: unit test to clarify behaviour with non-retained open switches (#3370)
* unit test to clarify bus/branch export with non-retained open switches * add documentation * move paragraph Signed-off-by: Luma <[email protected]>
1 parent c2514b1 commit 455fd74

File tree

2 files changed

+129
-1
lines changed

2 files changed

+129
-1
lines changed

cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/CgmesTopologyKindTest.java

+125
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@
1515
import com.powsybl.cgmes.model.CgmesNamespace;
1616
import com.powsybl.commons.test.AbstractSerDeTest;
1717
import com.powsybl.iidm.network.*;
18+
import org.junit.jupiter.api.Test;
1819
import org.junit.jupiter.params.ParameterizedTest;
1920
import org.junit.jupiter.params.provider.EnumSource;
2021

2122
import java.io.IOException;
23+
import java.nio.file.Files;
24+
import java.nio.file.Path;
2225
import java.util.Properties;
26+
import java.util.function.Predicate;
2327

2428
import static com.powsybl.cgmes.conversion.test.ConversionUtil.getElement;
2529
import static com.powsybl.cgmes.conversion.test.ConversionUtil.getElementCount;
@@ -41,6 +45,60 @@ void cgmesTopologyKindTest(CgmesTopologyKind topologyKind) throws IOException {
4145
assertValidExport(network, topologyKind, true);
4246
}
4347

48+
@Test
49+
void nonRetainedOpenTest() throws IOException {
50+
Properties exportParams = new Properties();
51+
exportParams.put(CgmesExport.TOPOLOGY_KIND, "BUS_BRANCH");
52+
53+
// We start with a network that has two connected components
54+
Network network = nonRetainedOpenNetwork();
55+
assertEquals(2, network.getBusView().getConnectedComponents().size());
56+
57+
Path outputCgmes = Files.createDirectories(tmpDir.resolve("cgmes-non-retained-open"));
58+
network.write("CGMES", exportParams, outputCgmes);
59+
Network network1 = Network.read(outputCgmes);
60+
assertEquals(2, network1.getBusView().getConnectedComponents().size());
61+
62+
// If we close all switches in our original IIDM network we end up with only one connected component
63+
network.getSwitchStream().forEach(sw -> sw.setOpen(false));
64+
assertEquals(1, network.getBusView().getConnectedComponents().size());
65+
66+
// Even if we close all switches in the re-imported network we will have two connected components
67+
// In the exported network we can not get all equipment in a single connected component
68+
network1.getSwitchStream().forEach(sw -> sw.setOpen(false));
69+
assertEquals(2, network1.getBusView().getConnectedComponents().size());
70+
// If we force the reconnection of the line we have 3 connected components
71+
network1.getLine("LN").getTerminal1().connect();
72+
network1.getLine("LN").getTerminal2().connect();
73+
assertEquals(3, network1.getBusView().getConnectedComponents().size());
74+
}
75+
76+
@Test
77+
void nonRetainedClosedTest() throws IOException {
78+
Properties exportParams = new Properties();
79+
exportParams.put(CgmesExport.TOPOLOGY_KIND, "BUS_BRANCH");
80+
81+
// We start with a network that has two connected components
82+
Network network = nonRetainedOpenNetwork();
83+
assertEquals(2, network.getBusView().getConnectedComponents().size());
84+
// Before export, we close all non-retained switches, we still have two connected components
85+
network.getSwitchStream().filter(Predicate.not(Switch::isRetained)).forEach(sw -> sw.setOpen(false));
86+
assertEquals(2, network.getBusView().getConnectedComponents().size());
87+
88+
// Export to CGMES as bus/branch and recover the exported network
89+
Path outputCgmes = Files.createDirectories(tmpDir.resolve("cgmes-non-retained-closed"));
90+
network.write("CGMES", exportParams, outputCgmes);
91+
Network network1 = Network.read(outputCgmes);
92+
assertEquals(2, network1.getBusView().getConnectedComponents().size());
93+
94+
// Now if we close all switches in the re-imported network and force the line as connected,
95+
// we end up with only one connected component
96+
network1.getSwitchStream().forEach(sw -> sw.setOpen(false));
97+
network1.getLine("LN").getTerminal1().connect();
98+
network1.getLine("LN").getTerminal2().connect();
99+
assertEquals(1, network1.getBusView().getConnectedComponents().size());
100+
}
101+
44102
private void assertValidExport(Network network, CgmesTopologyKind topologyKind, boolean cim100Export) throws IOException {
45103
// Build the export parameters
46104
Properties exportParams = new Properties();
@@ -281,4 +339,71 @@ private Network mixedTopologyNetwork() {
281339

282340
return network;
283341
}
342+
343+
private Network nonRetainedOpenNetwork() {
344+
Network network = NetworkFactory.findDefault().createNetwork("network-non-retained-open", "test");
345+
346+
// -------------- LN ------------------
347+
// | |
348+
// (2) (2)
349+
// | |
350+
// [ ] BK_1, retained, open [ ] BK_2, retained, open
351+
// | |
352+
// (1) (1)
353+
// | |
354+
// / DIS_1, open / DIS_2, open
355+
// | |
356+
// (0)== BB_1 (0)== BB_2
357+
// | |
358+
// (10) (10)
359+
// | |
360+
// GEN LOAD
361+
362+
Substation substation1 = network.newSubstation().setId("ST_1").add();
363+
VoltageLevel voltageLevel1 = substation1.newVoltageLevel().setId("VL_1").setNominalV(400.0)
364+
.setTopologyKind(TopologyKind.NODE_BREAKER).add();
365+
voltageLevel1.getNodeBreakerView().newBusbarSection().setId("BB_1")
366+
.setNode(0).add();
367+
voltageLevel1.getNodeBreakerView().newSwitch().setId("DIS_1")
368+
.setNode1(0)
369+
.setNode2(1)
370+
.setOpen(true).setRetained(false).setKind(SwitchKind.DISCONNECTOR).add();
371+
voltageLevel1.getNodeBreakerView().newSwitch().setId("BK_1")
372+
.setNode1(1)
373+
.setNode2(2)
374+
.setOpen(true).setRetained(true).setKind(SwitchKind.BREAKER).add();
375+
voltageLevel1.newGenerator().setId("GEN")
376+
.setNode(10)
377+
.setTargetP(1.0).setTargetQ(1.0).setMinP(0.0).setMaxP(2.0).setVoltageRegulatorOn(false).add();
378+
voltageLevel1.getNodeBreakerView().newInternalConnection()
379+
.setNode1(0)
380+
.setNode2(10).add();
381+
382+
Substation substation2 = network.newSubstation().setId("ST_2").add();
383+
VoltageLevel voltageLevel2 = substation2.newVoltageLevel().setId("VL_2").setNominalV(400.0)
384+
.setTopologyKind(TopologyKind.NODE_BREAKER).add();
385+
voltageLevel2.getNodeBreakerView().newBusbarSection().setId("BB_2")
386+
.setNode(0).add();
387+
voltageLevel2.getNodeBreakerView().newSwitch().setId("DIS_2")
388+
.setNode1(0)
389+
.setNode2(1)
390+
.setOpen(true).setRetained(false).setKind(SwitchKind.DISCONNECTOR).add();
391+
voltageLevel2.getNodeBreakerView().newSwitch().setId("BK_2")
392+
.setNode1(1)
393+
.setNode2(2)
394+
.setOpen(true).setRetained(true).setKind(SwitchKind.BREAKER).add();
395+
voltageLevel2.newLoad().setId("LOAD")
396+
.setNode(10)
397+
.setP0(1.0).setQ0(1.0).add();
398+
voltageLevel2.getNodeBreakerView().newInternalConnection().setNode1(0).setNode2(10).add();
399+
400+
network.newLine().setId("LN")
401+
.setVoltageLevel1("VL_1")
402+
.setVoltageLevel2("VL_2")
403+
.setNode1(2)
404+
.setNode2(2)
405+
.setR(0.1).setX(1.0).setG1(0.0).setG2(0.0).setB1(0.0).setB2(0.0).add();
406+
407+
return network;
408+
}
284409
}

docs/grid_exchange_formats/cgmes/export.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,10 @@ The various configurations and the differences in what's written are summarized
174174
| 100 | `BUS_BRANCH` | Yes (**) | Yes |
175175

176176
### Connectivity elements
177-
* Non-retained `Switch` are always written in the case of a `NODE_BREAKER` export, and never written in the case of a `BUS_BRANCH` export
177+
* Non-retained `Switch` are always written in the case of a `NODE_BREAKER` export, and never written in the case of a `BUS_BRANCH` export.
178+
* Having non-retained open switches in a node/breaker network that is exported as bus/branch may result in multiple connectivity components in the exported network.
179+
* To avoid this, it would be best to close all non-retained switches in the case before exporting it.
180+
* Then, the maximum amount of connectivity will be preserved in the export, and the bus/branch exported files can more easily be used for later calculations.
178181
* `ConnectivityNode` are:
179182
* Never exported in the case of a CIM 16 `BUS_BRANCH` export
180183
* (*) Always exported in the case of a `NODE_BREAKER` export. If the VoltageLevel's connectivity level is `node/breaker`,

0 commit comments

Comments
 (0)