diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/SwitchConversionTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/SwitchConversionTest.java index 1155f93272a..9746cba6910 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/SwitchConversionTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/SwitchConversionTest.java @@ -100,4 +100,43 @@ void fictitiousSwitchForDisconnectedTerminalTest() throws IOException { assertNull(getFirstMatch(eqExport, switchPattern)); assertEquals("true", getFirstMatch(sshExport, terminalPattern)); } + + @Test + void retainedSwitchTest() throws IOException { + // IIDM network: + // Two BusbarSections first on different topological nodes, then on the same topological node. + // A retained Switch coupling the two bars. + // CGMES export: + // A retained switch cannot have both its terminals associated to the same topological node. + Network network = Network.create("retained-switch-between-two-bars", "manual"); + Substation st = network.newSubstation().setId("ST").add(); + VoltageLevel vl = st.newVoltageLevel().setId("VL").setNominalV(110).setTopologyKind(TopologyKind.NODE_BREAKER).add(); + VoltageLevel.BusBreakerView bbv = vl.getBusBreakerView(); + VoltageLevel.NodeBreakerView nbv = vl.getNodeBreakerView(); + nbv.newBusbarSection().setId("BBS_1").setNode(1).add(); + nbv.newBusbarSection().setId("BBS_2").setNode(2).add(); + nbv.newBreaker().setId("COUPLER").setNode1(1).setNode2(2).setRetained(true).add(); + nbv.newDisconnector().setId("DIS_1").setNode1(1).setNode2(3).add(); + nbv.newDisconnector().setId("DIS_2").setNode1(2).setNode2(3).add(); + nbv.newBreaker().setId("BK").setNode1(3).setNode2(4).add(); + vl.newLoad().setId("LD").setNode(4).setP0(1).setQ0(0).add(); + + // Open one disconnector so that the 2 ends of the retained switch are on different buses/topological nodes. + nbv.getSwitch("DIS_1").setOpen(true); + assertNotEquals(bbv.getBus1("COUPLER"), bbv.getBus2("COUPLER")); + + // In that case, the retained switch can be exported as retained. + String eqExport = writeCgmesProfile(network, "EQ", tmpDir); + Pattern couplerRetainedPattern = Pattern.compile(".*?" + + "(.*?)", Pattern.DOTALL); + assertEquals("true", getFirstMatch(eqExport, couplerRetainedPattern)); + + // Now close the disconnector so that the 2 ends of the retained switch are on the same bus/topological node. + nbv.getSwitch("DIS_1").setOpen(false); + assertEquals(bbv.getBus1("COUPLER"), bbv.getBus2("COUPLER")); + + // The retained switch can't be exported as retained. + eqExport = writeCgmesProfile(network, "EQ", tmpDir); + assertEquals("false", getFirstMatch(eqExport, couplerRetainedPattern)); + } } diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/issues/RetainedSwitchExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/issues/RetainedSwitchExportTest.java deleted file mode 100644 index bb44a9b8e39..00000000000 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/issues/RetainedSwitchExportTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.powsybl.cgmes.conversion.test.export.issues; - -import com.powsybl.cgmes.conversion.CgmesExport; -import com.powsybl.commons.test.AbstractSerDeTest; -import com.powsybl.iidm.network.*; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.nio.file.Files; -import java.util.Properties; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static org.junit.jupiter.api.Assertions.*; - -class RetainedSwitchExportTest extends AbstractSerDeTest { - @Test - void testRetainedSwitchDifferentTN() throws IOException { - Network network = Network.create("retained-switch-same-TN", "manual"); - VoltageLevel vl = network.newSubstation().setId("S0").add().newVoltageLevel() - .setId("VL0") - .setNominalV(100) - .setTopologyKind(TopologyKind.NODE_BREAKER) - .add(); - vl.getNodeBreakerView().newBusbarSection().setId("BBS0").setNode(0).add(); - vl.getNodeBreakerView().newBusbarSection().setId("BBS1").setNode(1).add(); - vl.getNodeBreakerView().newBreaker().setId("COUPLER").setRetained(true).setNode1(0).setNode2(1).add(); - vl.newLoad().setId("LOAD").setNode(2).setP0(1).setQ0(0).add(); - vl.getNodeBreakerView().newBreaker().setId("LOAD_BK").setNode1(2).setNode2(0).add(); - vl.newGenerator().setId("GEN").setNode(3).setTargetP(1).setTargetQ(0).setMinP(0).setMaxP(10).setVoltageRegulatorOn(false).add(); - vl.getNodeBreakerView().newBreaker().setId("GEN_BK").setNode1(3).setNode2(1).add(); - - // Check that bus/breaker view buses are different at ends of coupler - Bus bus1 = vl.getBusBreakerView().getBus1("COUPLER"); - Bus bus2 = vl.getBusBreakerView().getBus2("COUPLER"); - assertNotEquals(bus1, bus2); - - // Export only EQ to CGMES - Properties exportParams = new Properties(); - exportParams.put(CgmesExport.PROFILES, "EQ"); - - String basenameRetained = "net"; - network.write("CGMES", exportParams, tmpDir.resolve(basenameRetained)); - String eqRetained = read(basenameRetained, "EQ"); - - // Look for the coupler retained attribute - // Include multiple lines and non-greedy matches - Pattern couplerRetainedPattern = Pattern.compile(".*?(.*?)", Pattern.DOTALL); - Matcher couplerRetained = couplerRetainedPattern.matcher(eqRetained); - assertTrue(couplerRetained.find()); - assertTrue(Boolean.parseBoolean(couplerRetained.group(1))); - - // Now add a load that is connected to the two busbars through disconnectors - vl.newLoad().setId("LOAD_BOTH").setP0(5).setQ0(0).setNode(5).add(); - vl.getNodeBreakerView().newBreaker().setId("LOAD5_BK").setNode1(5).setNode2(4).add(); - vl.getNodeBreakerView().newDisconnector().setId("LOAD5_DIS0").setNode1(4).setNode2(0).add(); - vl.getNodeBreakerView().newDisconnector().setId("LOAD5_DIS1").setNode1(4).setNode2(1).add(); - - // Export only EQ to CGMES - String basenameNonRetained = "netnr"; - network.write("CGMES", exportParams, tmpDir.resolve(basenameNonRetained)); - String eqNonRetained = read(basenameNonRetained, "EQ"); - - // Look for the coupler retained attribute - // Include multiple lines and non-greedy matches - Matcher couplerNonRetained = couplerRetainedPattern.matcher(eqNonRetained); - assertTrue(couplerNonRetained.find()); - assertFalse(Boolean.parseBoolean(couplerNonRetained.group(1))); - } - - private String read(String basename, String profile) throws IOException { - String instanceFile = String.format("%s_%s.xml", basename, profile); - return Files.readString(tmpDir.resolve(instanceFile)); - } -} diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/issues/SwitchExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/issues/SwitchExportTest.java deleted file mode 100644 index b16f3aa2e38..00000000000 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/issues/SwitchExportTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2023, 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.cgmes.conversion.test.export.issues; - -import com.powsybl.cgmes.conversion.CgmesImport; -import com.powsybl.commons.datasource.DirectoryDataSource; -import com.powsybl.commons.test.AbstractSerDeTest; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.SwitchKind; -import com.powsybl.iidm.network.TopologyKind; -import com.powsybl.iidm.network.VoltageLevel; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.io.*; -import java.util.Properties; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -/** - * @author Luma ZamarreƱo {@literal } - */ -class SwitchExportTest extends AbstractSerDeTest { - - private Properties importParams; - - @BeforeEach - public void setUp() throws IOException { - super.setUp(); - importParams = new Properties(); - importParams.put(CgmesImport.IMPORT_CGM_WITH_SUBNETWORKS, "false"); - } - - @Test - void testExportRetainedSwitchWithSameBusBreakerBusAtBothEnds() { - // We create a network where a retained breaker has the same bus-breaker buses at both ends - // After #2574, a breaker with these characteristics was not exported to CGMES - // It may happen in some double bar configurations where lines (or other equipment) may be connected to both bars - // and there is also a retained coupler - Network n = Network.create("retained-breaker-between-busbar-sections", "manual"); - VoltageLevel vl = n.newVoltageLevel().setId("vl").setName("vl").setTopologyKind(TopologyKind.NODE_BREAKER).setNominalV(10).add(); - VoltageLevel.NodeBreakerView nb = vl.getNodeBreakerView(); - nb.newBusbarSection().setId("bbs1").setNode(1).add(); - nb.newBusbarSection().setId("bbs2").setNode(2).add(); - nb.newSwitch().setId("coupler").setName("coupler").setNode1(1).setNode2(2).setKind(SwitchKind.BREAKER).setRetained(true).add(); - vl.newLoad().setId("load").setName("load").setNode(3) - .setP0(10).setQ0(0).add(); - vl.newGenerator().setId("gen").setName("gen").setNode(4) - .setTargetP(10).setTargetV(10).setMinP(0).setMaxP(100).setVoltageRegulatorOn(true).add(); - nb.newSwitch().setId("load-bk").setName("load-bk").setNode1(3).setNode2(31).setKind(SwitchKind.BREAKER).add(); - nb.newSwitch().setId("load-dis1").setName("load-dis1").setNode1(31).setNode2(1).setKind(SwitchKind.DISCONNECTOR).add(); - nb.newSwitch().setId("load-dis2").setName("load-dis2").setNode1(31).setNode2(2).setKind(SwitchKind.DISCONNECTOR).add(); - nb.newSwitch().setId("gen-bk").setName("gen-bk").setNode1(4).setNode2(41).setKind(SwitchKind.BREAKER).add(); - nb.newSwitch().setId("gen-dis1").setName("gen-dis1").setNode1(41).setNode2(1).setKind(SwitchKind.DISCONNECTOR).add(); - nb.newSwitch().setId("gen-dis2").setName("gen-dis2").setNode1(41).setNode2(2).setKind(SwitchKind.DISCONNECTOR).add(); - - // Check that the coupler is preserved when exported to CGMES - String basename = n.getNameOrId(); - n.write("CGMES", null, tmpDir.resolve(basename)); - Network n1 = Network.read(new DirectoryDataSource(tmpDir, basename)); - assertNotNull(n1.getSwitch("coupler")); - } - -}