diff --git a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/AbstractNamingStrategy.java b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/AbstractNamingStrategy.java new file mode 100644 index 00000000000..42e70197d5a --- /dev/null +++ b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/AbstractNamingStrategy.java @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2024, 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.ucte.converter; + +import com.powsybl.commons.PowsyblException; +import com.powsybl.iidm.network.*; +import com.powsybl.ucte.converter.util.UcteConverterConstants; +import com.powsybl.ucte.network.UcteElementId; +import com.powsybl.ucte.network.UcteNodeCode; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Clément LECLERC {@literal } + */ +public abstract class AbstractNamingStrategy implements NamingStrategy { + + protected final Map ucteNodeIds = new HashMap<>(); + protected final Map ucteElementIds = new HashMap<>(); + + @Override + public void initializeNetwork(Network network) { + //Empty implementation by default + } + + @Override + public UcteNodeCode getUcteNodeCode(String id) { + return ucteNodeIds.computeIfAbsent(id, k -> UcteNodeCode.parseUcteNodeCode(k) + .orElseThrow(() -> new UcteException(UcteConverterConstants.NO_UCTE_CODE_ERROR + k))); + } + + @Override + public UcteNodeCode getUcteNodeCode(Bus bus) { + if (bus == null) { + throw new PowsyblException("the bus is null"); + } + return getUcteNodeCode(bus.getId()); + } + + @Override + public UcteNodeCode getUcteNodeCode(DanglingLine danglingLine) { + if (danglingLine.getPairingKey() == null) { + return getUcteNodeCode(danglingLine.getId()); + } + return getUcteNodeCode(danglingLine.getPairingKey()); + } + + @Override + public UcteElementId getUcteElementId(String id) { + return ucteElementIds.computeIfAbsent(id, k -> UcteElementId.parseUcteElementId(k) + .orElseThrow(() -> new UcteException(UcteConverterConstants.NO_UCTE_CODE_ERROR + k))); + } + + @Override + public UcteElementId getUcteElementId(Switch sw) { + if (sw == null) { + throw new PowsyblException("the switch is null"); + } + return getUcteElementId(sw.getId()); + } + + @Override + public UcteElementId getUcteElementId(Branch branch) { + if (branch == null) { + throw new PowsyblException("the branch is null"); + } + return getUcteElementId(branch.getId()); + } + + @Override + public UcteElementId getUcteElementId(DanglingLine danglingLine) { + if (danglingLine == null) { + throw new PowsyblException("the danglingLine is null"); + } + return getUcteElementId(danglingLine.getId()); + } +} + diff --git a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/CounterNamingStrategy.java b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/CounterNamingStrategy.java new file mode 100644 index 00000000000..318499e7749 --- /dev/null +++ b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/CounterNamingStrategy.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2024, 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.ucte.converter; + +import com.google.auto.service.AutoService; +import com.powsybl.iidm.network.*; +import com.powsybl.ucte.network.UcteCountryCode; +import com.powsybl.ucte.network.UcteElementId; +import com.powsybl.ucte.network.UcteNodeCode; +import com.powsybl.ucte.network.UcteVoltageLevelCode; +import com.powsybl.ucte.network.util.UcteNetworkUtil; + +import java.util.*; + +/** + * @author Clément LECLERC {@literal } + */ +@AutoService(NamingStrategy.class) +public class CounterNamingStrategy extends AbstractNamingStrategy { + + private int voltageLevelCounter; + + @Override + public String getName() { + return "Counter"; + } + + @Override + public void initializeNetwork(Network network) { + voltageLevelCounter = 0; + network.getVoltageLevelStream() + .forEach(this::processVoltageLevel); + + network.getBranchStream().forEach(this::generateUcteElementId); + network.getDanglingLineStream().forEach(this::generateUcteElementId); + } + + private void processVoltageLevel(VoltageLevel voltageLevel) { + Iterator buslist = voltageLevel.getBusBreakerView().getBuses().iterator(); + for (int i = 0; buslist.hasNext(); i++) { + Bus bus = buslist.next(); + char orderCode = UcteNetworkUtil.getOrderCode(i); + generateUcteNodeId(bus.getId(), voltageLevel, orderCode); + } + + voltageLevel.getBusBreakerView().getSwitches() + .forEach(this::generateUcteElementId); + voltageLevelCounter++; + } + + private UcteNodeCode generateUcteNodeId(String busId, VoltageLevel voltageLevel, char orderCode) { + if (UcteNodeCode.isUcteNodeId(busId)) { + return changeOrderCode(busId, orderCode); + } + return createNewUcteNodeId(busId, voltageLevel, orderCode); + } + + private UcteNodeCode changeOrderCode(String busId, char orderCode) { + UcteNodeCode newNodeCode = UcteNodeCode.parseUcteNodeCode(busId).orElseThrow(); + newNodeCode.setBusbar(orderCode); + ucteNodeIds.put(busId, newNodeCode); + return newNodeCode; + } + + private UcteNodeCode createNewUcteNodeId(String busId, VoltageLevel voltageLevel, char orderCode) { + String newNodeId = String.format("%05d", voltageLevelCounter); + char countryCode = UcteCountryCode.fromVoltagelevel(voltageLevel).getUcteCode(); + char voltageLevelCode = UcteVoltageLevelCode.voltageLevelCodeFromVoltage(voltageLevel.getNominalV()); + + UcteNodeCode ucteNodeCode = new UcteNodeCode( + UcteCountryCode.fromUcteCode(countryCode), + newNodeId, + UcteVoltageLevelCode.voltageLevelCodeFromChar(voltageLevelCode), + orderCode); + + ucteNodeIds.put(busId, ucteNodeCode); + return ucteNodeCode; + } + + private UcteElementId generateUcteElementId(String id, UcteNodeCode node1, UcteNodeCode node2) { + if (ucteElementIds.containsKey(id)) { + return ucteElementIds.get(id); + } + + UcteElementId uniqueElementId = UcteNetworkUtil.ORDER_CODES.stream() + .map(orderCode -> new UcteElementId(node1, node2, orderCode)) + .filter(elementId -> !ucteElementIds.containsValue(elementId)) + .findFirst() + .orElseThrow(() -> new UcteException("Unable to generate unique element ID")); + + ucteElementIds.put(id, uniqueElementId); + return uniqueElementId; + } + + private UcteElementId generateUcteElementId(Branch branch) { + if (ucteElementIds.containsKey(branch.getId())) { + return ucteElementIds.get(branch.getId()); + } + UcteNodeCode node1 = ucteNodeIds.get(branch.getTerminal1().getBusBreakerView().getBus().getId()); + UcteNodeCode node2 = ucteNodeIds.get(branch.getTerminal2().getBusBreakerView().getBus().getId()); + + return generateUcteElementId(branch.getId(), node1, node2); + } + + private UcteElementId generateUcteElementId(DanglingLine danglingLine) { + if (ucteElementIds.containsKey(danglingLine.getId())) { + return ucteElementIds.get(danglingLine.getId()); + } + + UcteNodeCode code1; + UcteNodeCode code2; + + code1 = getUcteNodeCode(danglingLine.getTerminal().getBusBreakerView().getBus()); + + if (danglingLine.getPairingKey() != null && UcteNodeCode.isUcteNodeId(danglingLine.getPairingKey())) { + code2 = UcteNodeCode.parseUcteNodeCode(danglingLine.getPairingKey()).orElseThrow(); + ucteNodeIds.put(danglingLine.getPairingKey(), code2); + } else { + code2 = generateUcteNodeId(danglingLine.getId(), danglingLine.getTerminal().getVoltageLevel(), UcteNetworkUtil.getOrderCode(0)); + } + return generateUcteElementId(danglingLine.getId(), code1, code2); + } + + private UcteElementId generateUcteElementId(Switch sw) { + if (ucteElementIds.containsKey(sw.getId())) { + return ucteElementIds.get(sw.getId()); + } + + VoltageLevel.BusBreakerView view = sw.getVoltageLevel().getBusBreakerView(); + Bus bus1 = view.getBus1(sw.getId()); + Bus bus2 = view.getBus2(sw.getId()); + + UcteNodeCode u1 = getUcteNodeCode(bus1.getId()); + UcteNodeCode u2 = getUcteNodeCode(bus2.getId()); + + return generateUcteElementId(sw.getId(), u1, u2); + } + +} diff --git a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/DefaultNamingStrategy.java b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/DefaultNamingStrategy.java index 79fbc719893..d4855e4aba2 100644 --- a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/DefaultNamingStrategy.java +++ b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/DefaultNamingStrategy.java @@ -9,12 +9,7 @@ package com.powsybl.ucte.converter; import com.google.auto.service.AutoService; -import com.powsybl.iidm.network.*; -import com.powsybl.ucte.network.UcteElementId; -import com.powsybl.ucte.network.UcteNodeCode; -import java.util.HashMap; -import java.util.Map; /** * A {@link NamingStrategy} implementation that ensures the conformity of IDs with the UCTE-DEF format @@ -22,50 +17,10 @@ * @author Mathieu Bague {@literal } */ @AutoService(NamingStrategy.class) -public class DefaultNamingStrategy implements NamingStrategy { - - private final Map ucteNodeIds = new HashMap<>(); - - private final Map ucteElementIds = new HashMap<>(); +public class DefaultNamingStrategy extends AbstractNamingStrategy { @Override public String getName() { return "Default"; } - - @Override - public UcteNodeCode getUcteNodeCode(String id) { - return ucteNodeIds.computeIfAbsent(id, k -> UcteNodeCode.parseUcteNodeCode(k).orElseThrow(() -> new UcteException("Invalid UCTE node identifier: " + k))); - } - - @Override - public UcteNodeCode getUcteNodeCode(Bus bus) { - return getUcteNodeCode(bus.getId()); - } - - @Override - public UcteNodeCode getUcteNodeCode(DanglingLine danglingLine) { - return getUcteNodeCode(danglingLine.getPairingKey()); - } - - @Override - public UcteElementId getUcteElementId(String id) { - return ucteElementIds.computeIfAbsent(id, k -> UcteElementId.parseUcteElementId(k).orElseThrow(() -> new UcteException("Invalid UCTE node identifier: " + k))); - } - - @Override - public UcteElementId getUcteElementId(Switch sw) { - return getUcteElementId(sw.getId()); - } - - @Override - public UcteElementId getUcteElementId(Branch branch) { - return getUcteElementId(branch.getId()); - } - - @Override - public UcteElementId getUcteElementId(DanglingLine danglingLine) { - return getUcteElementId(danglingLine.getId()); - } - } diff --git a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/NamingStrategy.java b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/NamingStrategy.java index eb925831124..19fdca2291c 100644 --- a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/NamingStrategy.java +++ b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/NamingStrategy.java @@ -17,6 +17,8 @@ */ public interface NamingStrategy { + void initializeNetwork(Network network); + String getName(); UcteNodeCode getUcteNodeCode(String id); diff --git a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteExporter.java b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteExporter.java index 2a41a45c4e2..33dbf02bed6 100644 --- a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteExporter.java +++ b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteExporter.java @@ -32,7 +32,7 @@ import java.util.*; import java.util.function.Supplier; -import static com.powsybl.ucte.converter.util.UcteConstants.*; +import static com.powsybl.ucte.converter.util.UcteConverterConstants.*; import static com.powsybl.ucte.converter.util.UcteConverterHelper.*; /** @@ -87,6 +87,7 @@ public void export(Network network, Properties parameters, DataSource dataSource String namingStrategyName = Parameter.readString(getFormat(), parameters, NAMING_STRATEGY_PARAMETER, defaultValueConfig); NamingStrategy namingStrategy = findNamingStrategy(namingStrategyName, NAMING_STRATEGY_SUPPLIERS.get()); + namingStrategy.initializeNetwork(network); boolean combinePhaseAngleRegulation = Parameter.readBoolean(getFormat(), parameters, COMBINE_PHASE_ANGLE_REGULATION_PARAMETER, defaultValueConfig); UcteNetwork ucteNetwork = createUcteNetwork(network, namingStrategy, combinePhaseAngleRegulation); diff --git a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteImporter.java b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteImporter.java index d689a73b68d..8e577ab7d3c 100644 --- a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteImporter.java +++ b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/UcteImporter.java @@ -38,7 +38,7 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static com.powsybl.ucte.converter.util.UcteConstants.*; +import static com.powsybl.ucte.converter.util.UcteConverterConstants.*; /** * @author Geoffroy Jamgotchian {@literal } diff --git a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/util/UcteConstants.java b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/util/UcteConverterConstants.java similarity index 88% rename from ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/util/UcteConstants.java rename to ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/util/UcteConverterConstants.java index 10bb3766fb8..a73681a91bc 100644 --- a/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/util/UcteConstants.java +++ b/ucte/ucte-converter/src/main/java/com/powsybl/ucte/converter/util/UcteConverterConstants.java @@ -10,9 +10,9 @@ /** * @author Sebastien Murgey {@literal } */ -public final class UcteConstants { +public final class UcteConverterConstants { - private UcteConstants() { + private UcteConverterConstants() { throw new IllegalStateException("Should not be constructed"); } @@ -26,4 +26,5 @@ private UcteConstants() { public static final String ORDER_CODE = "orderCode"; public static final String POWER_PLANT_TYPE_PROPERTY_KEY = "powerPlantType"; public static final int DEFAULT_POWER_LIMIT = 9999; + public static final String NO_UCTE_CODE_ERROR = "No UCTE code found for id: "; } diff --git a/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/CounterNamingStrategyTest.java b/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/CounterNamingStrategyTest.java new file mode 100644 index 00000000000..d4b8a1ab4a5 --- /dev/null +++ b/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/CounterNamingStrategyTest.java @@ -0,0 +1,250 @@ +/** + * Copyright (c) 2024, 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.ucte.converter; + +import com.powsybl.commons.PowsyblException; +import com.powsybl.iidm.network.*; +import com.powsybl.commons.datasource.ResourceDataSource; +import com.powsybl.commons.datasource.ResourceSet; +import com.powsybl.ucte.network.UcteNodeCode; +import com.powsybl.ucte.network.UcteElementId; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Clément LECLERC {@literal } + */ +class CounterNamingStrategyTest { + + private Network network; + private CounterNamingStrategy strategy; + + @BeforeEach + void setUp() { + ResourceDataSource dataSource = new ResourceDataSource("network", new ResourceSet("/", "network.xiidm")); + network = Network.read(dataSource); + strategy = new CounterNamingStrategy(); + } + + @Test + void testName() { + assertEquals("Counter", strategy.getName()); + } + + @Test + void testInitialNetwork() { + assertThrows(UcteException.class, () -> strategy.getUcteNodeCode("NGEN")); + assertThrows(UcteException.class, () -> strategy.getUcteElementId("NHV1_NHV2_1")); + + strategy.initializeNetwork(network); + + assertDoesNotThrow(() -> strategy.getUcteNodeCode("NGEN")); + assertDoesNotThrow(() -> strategy.getUcteElementId("NHV1_NHV2_1")); + } + + @Test + void testVoltageLevelCounterNaming() { + strategy.initializeNetwork(network); + + UcteNodeCode firstBusCode = strategy.getUcteNodeCode(network.getBusBreakerView().getBus("NGEN")); + UcteNodeCode secondBusCode = strategy.getUcteNodeCode(network.getBusBreakerView().getBus("NGEN2")); + UcteNodeCode thirdBusCode = strategy.getUcteNodeCode(network.getBusBreakerView().getBus("NGEN3")); + + String firstIdPart = firstBusCode.toString().substring(0, 6); + String secondIdPart = secondBusCode.toString().substring(0, 6); + String thirdIdPart = thirdBusCode.toString().substring(0, 6); + + assertEquals(firstIdPart, secondIdPart); + assertEquals(firstIdPart, thirdIdPart); + assertEquals(secondIdPart, thirdIdPart); + } + + @Test + void testBasicNodeCodeGeneration() { + + strategy.initializeNetwork(network); + Bus genBus = network.getBusBreakerView().getBus("NGEN"); + Bus genbus2 = network.getBusBreakerView().getBus("NGEN2"); + Bus ucteBus = network.getBusBreakerView().getBus("F0000079"); + Bus loadBus = network.getBusBreakerView().getBus("NLOAD"); + + UcteNodeCode genCode = strategy.getUcteNodeCode(genBus); + UcteNodeCode genCode2 = strategy.getUcteNodeCode(genbus2); + UcteNodeCode loadCode = strategy.getUcteNodeCode(loadBus); + UcteNodeCode ucteCode = strategy.getUcteNodeCode(ucteBus); + + assertAll( + () -> assertTrue(UcteNodeCode.isUcteNodeId(genCode.toString())), + () -> assertTrue(UcteNodeCode.isUcteNodeId(genCode2.toString())), + () -> assertTrue(UcteNodeCode.isUcteNodeId(loadCode.toString())), + () -> assertTrue(UcteNodeCode.isUcteNodeId(ucteCode.toString())), + + () -> assertNotEquals(genCode, genCode2), + () -> assertNotEquals(genCode, loadCode), + () -> assertNotEquals(genCode, ucteCode), + () -> assertNotEquals(genCode2, loadCode), + () -> assertNotEquals(genCode2, ucteCode), + () -> assertNotEquals(ucteCode, loadCode), + + () -> assertEquals("F0000070", genCode.toString()), + () -> assertEquals("F0000071", genCode2.toString()), + () -> assertEquals("F0000073", ucteCode.toString()), + () -> assertEquals("F0000330", loadCode.toString()) + + ); + } + + @Test + void testBranchElementIds() { + strategy.initializeNetwork(network); + + Branch transformer1 = network.getBranch("NGEN_NHV1"); + Branch transformer2 = network.getBranch("NHV2_NLOAD"); + Branch line1 = network.getBranch("NHV1_NHV2_1"); + Branch line2 = network.getBranch("NHV1_NHV2_2"); + + UcteElementId transformerId1 = strategy.getUcteElementId(transformer1); + UcteElementId transformerId2 = strategy.getUcteElementId(transformer2); + UcteElementId lineId1 = strategy.getUcteElementId(line1); + UcteElementId lineId2 = strategy.getUcteElementId(line2); + + assertAll( + () -> assertTrue(UcteElementId.isUcteElementId(transformerId1.toString())), + () -> assertTrue(UcteElementId.isUcteElementId(transformerId2.toString())), + () -> assertTrue(UcteElementId.isUcteElementId(lineId1.toString())), + () -> assertTrue(UcteElementId.isUcteElementId(lineId2.toString())), + + () -> assertNotEquals(transformerId1, transformerId2), + () -> assertNotEquals(lineId1, lineId2), + + () -> assertEquals(transformerId1, strategy.getUcteElementId(transformer1)), + () -> assertEquals(transformerId2, strategy.getUcteElementId(transformer2)), + + () -> assertEquals("F0000070 F0000110 0", transformerId1.toString()), + () -> assertEquals("F0000210 F0000330 0", transformerId2.toString()), + () -> assertEquals("F0000110 F0000210 0", lineId1.toString()), + () -> assertEquals("F0000110 F0000210 1", lineId2.toString()) + + ); + } + + @Test + void testSwitchElementIds() { + strategy.initializeNetwork(network); + Switch sw = network.getSwitch("NGEN-NGEN2"); + Switch sw2 = network.getSwitch("NGEN-NGEN3"); + Switch sw3 = network.getSwitch("NGEN-NGEN3"); + Switch sw4 = network.getSwitch("NGEN-NGEN4"); + + UcteElementId swId = strategy.getUcteElementId(sw); + UcteElementId swId2 = strategy.getUcteElementId(sw2); + UcteElementId swId3 = strategy.getUcteElementId(sw3); + UcteElementId swId4 = strategy.getUcteElementId(sw4); + + assertAll( + () -> assertTrue(UcteElementId.isUcteElementId(swId.toString())), + () -> assertTrue(UcteElementId.isUcteElementId(swId2.toString())), + () -> assertTrue(UcteElementId.isUcteElementId(swId3.toString())), + () -> assertTrue(UcteElementId.isUcteElementId(swId4.toString())), + () -> assertNotEquals(swId, swId2), + () -> assertNotEquals(swId3, swId4), + () -> assertNotEquals(swId, swId4), + () -> assertNotEquals(swId2, swId4), + () -> assertEquals(swId3, swId2), + + () -> assertEquals("F0000070 F0000071 0", swId.toString()), + () -> assertEquals("F0000070 F0000072 0", swId2.toString()), + () -> assertEquals("F0000070 F0000072 0", swId3.toString()), + () -> assertEquals("F0000070 F0000072 1", swId4.toString()) + ); + } + + @Test + void testDanglingLineElementIds() { + strategy.initializeNetwork(network); + DanglingLine dl1 = network.getDanglingLine("DL1"); + DanglingLine dl2 = network.getDanglingLine("DL2"); + DanglingLine dl3 = network.getDanglingLine("DL3"); + UcteElementId dlId1 = strategy.getUcteElementId(dl1); + UcteElementId dlId2 = strategy.getUcteElementId(dl2); + UcteElementId dlId3 = strategy.getUcteElementId(dl3); + + assertAll( + () -> assertTrue(UcteElementId.isUcteElementId(dlId1.toString())), + () -> assertTrue(UcteElementId.isUcteElementId(dlId3.toString())), + () -> assertNotEquals(dlId1, dlId2), + () -> assertNotEquals(dlId1, dlId3), + () -> assertNotEquals(dlId2, dlId3), + + () -> assertEquals("F0000071 F0000670 0", dlId1.toString()), + () -> assertEquals("F0000071 X0000011 0", dlId2.toString()), + () -> assertEquals("F0000071 F0000670 1", dlId3.toString()) + ); + } + + @Test + void testParallelLines() { + strategy.initializeNetwork(network); + + Branch line1 = network.getBranch("NHV1_NHV2_1"); + Branch line2 = network.getBranch("NHV1_NHV2_2"); + + UcteElementId id1 = strategy.getUcteElementId(line1); + UcteElementId id2 = strategy.getUcteElementId(line2); + + assertAll( + () -> assertTrue(UcteElementId.isUcteElementId(id1.toString())), + () -> assertTrue(UcteElementId.isUcteElementId(id2.toString())), + () -> assertNotEquals(id1, id2), + + () -> assertEquals("F0000110 F0000210 0", id1.toString()), + () -> assertEquals("F0000110 F0000210 1", id2.toString()) + ); + } + + @Test + void testExistingUcteNodeCodes() { + strategy.initializeNetwork(network); + + Bus bus = network.getBusBreakerView().getBus("NGEN"); + UcteNodeCode firstCode = strategy.getUcteNodeCode(bus); + assertNotNull(firstCode); + + UcteNodeCode existingCode = strategy.getUcteNodeCode(bus); + assertNotNull(existingCode); + assertEquals(firstCode, existingCode); + + UcteNodeCode presentCode = strategy.getUcteNodeCode(bus.getId()); + assertNotNull(presentCode); + assertEquals(firstCode, presentCode); + assertEquals(existingCode, presentCode); + } + + @Test + void testNullAndInvalidIds() { + strategy.initializeNetwork(network); + + assertAll( + () -> assertThrows(PowsyblException.class, () -> strategy.getUcteNodeCode((String) null)), + () -> assertThrows(PowsyblException.class, () -> strategy.getUcteElementId((String) null)), + () -> assertThrows(UcteException.class, () -> strategy.getUcteNodeCode("INVALID_ID")), + () -> assertThrows(UcteException.class, () -> strategy.getUcteElementId("INVALID_ID")) + ); + } + + @Test + void testCountryCode() { + strategy.initializeNetwork(network); + + Bus genBus = network.getBusBreakerView().getBus("NGEN"); + UcteNodeCode code = strategy.getUcteNodeCode(genBus); + assertEquals('F', code.toString().charAt(0)); + } +} diff --git a/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/NamingStrategyTest.java b/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/NamingStrategyTest.java index 00736736edd..f3e0cf045c0 100644 --- a/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/NamingStrategyTest.java +++ b/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/NamingStrategyTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019, RTE (http://www.rte-france.com) + * Copyright (c) 2024, 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/. diff --git a/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/UcteImporterTest.java b/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/UcteImporterTest.java index 079cf5ea9ea..add5d45cb37 100644 --- a/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/UcteImporterTest.java +++ b/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/UcteImporterTest.java @@ -18,7 +18,7 @@ import com.powsybl.entsoe.util.EntsoeGeographicalCode; import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.impl.NetworkFactoryImpl; -import com.powsybl.ucte.converter.util.UcteConstants; +import com.powsybl.ucte.converter.util.UcteConverterConstants; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -271,7 +271,7 @@ void emptyElementName() { Network network = new UcteImporter().importData(dataSource, new NetworkFactoryImpl(), null); Line l = network.getLine("F_SU1_12 F_SU1_11 1"); assertNotNull(l); - assertFalse(l.hasProperty(UcteConstants.ELEMENT_NAME_PROPERTY_KEY)); + assertFalse(l.hasProperty(UcteConverterConstants.ELEMENT_NAME_PROPERTY_KEY)); } @Test diff --git a/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/util/UcteConverterHelperTest.java b/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/util/UcteConverterHelperTest.java index 0eb86fb1d39..85cbc0a3e67 100644 --- a/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/util/UcteConverterHelperTest.java +++ b/ucte/ucte-converter/src/test/java/com/powsybl/ucte/converter/util/UcteConverterHelperTest.java @@ -18,8 +18,7 @@ import org.junit.jupiter.api.Test; import static com.powsybl.ucte.converter.util.UcteConverterHelper.*; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.*; /** * @author Abdelsalem HEDHILI {@literal } @@ -90,4 +89,5 @@ void calculatePhaseDuTest2() { assertEquals(0.990, duRef6.abs(), 0.00001); assertEquals(90.00, Math.toDegrees(duRef6.getArgument()), 0.00001); // loss of one decimal with sign } + } diff --git a/ucte/ucte-converter/src/test/resources/network.xiidm b/ucte/ucte-converter/src/test/resources/network.xiidm new file mode 100644 index 00000000000..2a653a93ad3 --- /dev/null +++ b/ucte/ucte-converter/src/test/resources/network.xiidm @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ucte/ucte-network/pom.xml b/ucte/ucte-network/pom.xml index 11fee760cd5..3d968421a82 100644 --- a/ucte/ucte-network/pom.xml +++ b/ucte/ucte-network/pom.xml @@ -85,6 +85,10 @@ ${project.version} test + + com.powsybl + powsybl-iidm-api + diff --git a/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteCountryCode.java b/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteCountryCode.java index 67557c04dcc..19ce759d720 100644 --- a/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteCountryCode.java +++ b/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteCountryCode.java @@ -7,6 +7,10 @@ */ package com.powsybl.ucte.network; +import com.powsybl.iidm.network.Country; +import com.powsybl.iidm.network.Substation; +import com.powsybl.iidm.network.VoltageLevel; + import java.util.Objects; /** @@ -121,4 +125,15 @@ public static boolean isUcteCountryCode(char character) { } } + public static UcteCountryCode fromVoltagelevel(VoltageLevel voltageLevel) { + Country country = voltageLevel.getSubstation() + .flatMap(Substation::getCountry) + .orElseThrow(() -> new UcteException("No UCTE country found for substation")); + try { + return UcteCountryCode.valueOf(country.name()); + } catch (IllegalArgumentException e) { + throw new UcteException(String.format("No UCTE country found for %s", country.name())); + } + } + } diff --git a/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteElementId.java b/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteElementId.java index 852af51fb65..5cc8d13c480 100644 --- a/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteElementId.java +++ b/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteElementId.java @@ -7,6 +7,8 @@ */ package com.powsybl.ucte.network; +import com.powsybl.ucte.network.util.UcteNetworkUtil; + import java.util.*; /** @@ -15,9 +17,6 @@ */ public class UcteElementId implements Comparable { - private static final List ORDER_CODES = Arrays.asList('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', - 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', '-', '.', ' '); - private final UcteNodeCode nodeCode1; private final UcteNodeCode nodeCode2; private char orderCode; @@ -114,8 +113,7 @@ private static boolean isOrderCode(char orderCode) { /* Update to match modification on UCTE format The new update is available on the ENTSO-E website: - https://docstore.entsoe.eu/Documents/Publications/SOC/Continental_Europe/150420_quality_of_datasets_and_calculations_3rd_edition.pdf - */ - return ORDER_CODES.contains(orderCode); + https://eepublicdownloads.entsoe.eu/clean-documents/Publications/SOC/Continental_Europe/150420_quality_of_datasets_and_calculations_3rd_edition.pdf */ + return UcteNetworkUtil.ORDER_CODES.contains(orderCode); } } diff --git a/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteVoltageLevelCode.java b/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteVoltageLevelCode.java index 1c03015b9f7..0b25a723626 100644 --- a/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteVoltageLevelCode.java +++ b/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/UcteVoltageLevelCode.java @@ -7,6 +7,9 @@ */ package com.powsybl.ucte.network; +import java.util.Arrays; +import java.util.Comparator; + /** * * @author Geoffroy Jamgotchian {@literal } @@ -75,6 +78,21 @@ public static UcteVoltageLevelCode voltageLevelCodeFromChar(char code) { return UcteVoltageLevelCode.values()[code - '0']; } + public static char voltageLevelCodeFromVoltage(double voltage) { + if (voltage < UcteVoltageLevelCode.VL_27.getVoltageLevel()) { + return '7'; + } + if (voltage > UcteVoltageLevelCode.VL_750.getVoltageLevel()) { + return '0'; + } + + return Arrays.stream(UcteVoltageLevelCode.values()) + .min(Comparator.comparingDouble(code -> + Math.abs(voltage - code.getVoltageLevel()))) + .map(code -> (char) ('0' + code.ordinal())) + .orElseThrow(); + } + public static boolean isVoltageLevelCode(char character) { return character >= '0' && character <= '9'; } diff --git a/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/util/UcteNetworkUtil.java b/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/util/UcteNetworkUtil.java new file mode 100644 index 00000000000..85aad09fb35 --- /dev/null +++ b/ucte/ucte-network/src/main/java/com/powsybl/ucte/network/util/UcteNetworkUtil.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2024, 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.ucte.network.util; + +import com.powsybl.ucte.network.UcteException; + +import java.util.List; + +/** + * @author Clément LECLERC {@literal } + */ +public final class UcteNetworkUtil { + + private UcteNetworkUtil() { + throw new IllegalStateException("Should not be constructed"); + } + + public static final List ORDER_CODES = List.of('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', '-', '.', ' '); + + public static char getOrderCode(int index) { + if (index > ORDER_CODES.size() || index < 0) { + throw new UcteException("Order code index out of bounds"); + } + return ORDER_CODES.get(index); + } +} diff --git a/ucte/ucte-network/src/test/java/com/powsybl/ucte/network/UcteVoltageLevelCodeTest.java b/ucte/ucte-network/src/test/java/com/powsybl/ucte/network/UcteVoltageLevelCodeTest.java index d9582f02f97..859ec7061e5 100644 --- a/ucte/ucte-network/src/test/java/com/powsybl/ucte/network/UcteVoltageLevelCodeTest.java +++ b/ucte/ucte-network/src/test/java/com/powsybl/ucte/network/UcteVoltageLevelCodeTest.java @@ -29,5 +29,14 @@ void test() { assertEquals(27, UcteVoltageLevelCode.VL_27.getVoltageLevel()); assertEquals(330, UcteVoltageLevelCode.VL_330.getVoltageLevel()); assertEquals(500, UcteVoltageLevelCode.VL_500.getVoltageLevel()); + + assertEquals('0', UcteVoltageLevelCode.voltageLevelCodeFromVoltage(1000)); + assertEquals('1', UcteVoltageLevelCode.voltageLevelCodeFromVoltage(386)); + assertEquals('2', UcteVoltageLevelCode.voltageLevelCodeFromVoltage(220)); + assertEquals('2', UcteVoltageLevelCode.voltageLevelCodeFromVoltage(195)); + assertEquals('3', UcteVoltageLevelCode.voltageLevelCodeFromVoltage(150)); + assertEquals('4', UcteVoltageLevelCode.voltageLevelCodeFromVoltage(120)); + assertEquals('4', UcteVoltageLevelCode.voltageLevelCodeFromVoltage(125)); + assertEquals('7', UcteVoltageLevelCode.voltageLevelCodeFromVoltage(22)); } } diff --git a/ucte/ucte-network/src/test/java/com/powsybl/ucte/network/util/UcteNetworkUtilTest.java b/ucte/ucte-network/src/test/java/com/powsybl/ucte/network/util/UcteNetworkUtilTest.java new file mode 100644 index 00000000000..148b756b9a1 --- /dev/null +++ b/ucte/ucte-network/src/test/java/com/powsybl/ucte/network/util/UcteNetworkUtilTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2024, 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.ucte.network.util; + +import com.powsybl.ucte.network.UcteException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author Clément LECLERC {@literal } + */ +class UcteNetworkUtilTest { + + @Test + void getOrderCodeTest() { + assertEquals('0', UcteNetworkUtil.getOrderCode(0)); + assertEquals('A', UcteNetworkUtil.getOrderCode(10)); + assertThrows(UcteException.class, () -> UcteNetworkUtil.getOrderCode(-1)); + assertThrows(UcteException.class, () -> UcteNetworkUtil.getOrderCode(50)); + } +}