From 26e68b91cdd28d4024cfd00dbc288168dd91b251 Mon Sep 17 00:00:00 2001 From: Bertrand Rix Date: Fri, 28 Apr 2023 11:21:22 +0200 Subject: [PATCH 1/3] Wrap moveConnectable from terminal bus breaker view. Signed-off-by: Bertrand Rix --- cpp/src/bindings.cpp | 2 ++ cpp/src/pypowsybl.cpp | 4 ++++ cpp/src/pypowsybl.h | 2 ++ .../python/network/NetworkCFunctions.java | 13 ++++++++++++ .../powsybl/python/network/NetworkUtil.java | 20 +++++++++++++++++++ pypowsybl/network.py | 2 ++ tests/test_network.py | 3 +++ 7 files changed, 46 insertions(+) diff --git a/cpp/src/bindings.cpp b/cpp/src/bindings.cpp index 3db18ba47..80e505107 100644 --- a/cpp/src/bindings.cpp +++ b/cpp/src/bindings.cpp @@ -762,4 +762,6 @@ PYBIND11_MODULE(_pypowsybl, m) { m.def("get_network_modification_metadata_with_element_type", &pypowsybl::getModificationMetadataWithElementType, "Get network modification metadata with element type", py::arg("network_modification_type"), py::arg("element_type")); m.def("create_network_modification", ::createNetworkModification, "Create and apply network modification", py::arg("network"), py::arg("dataframe"), py::arg("network_modification_type"), py::arg("raise_exception"), py::arg("reporter")); + + m.def("move_connectable", &pypowsybl::moveConnectable, "Move connectable", py::arg("network"), py::arg("equipment_id"), py::arg("bus_origin_id"), py::arg("bus_destination_id")); } diff --git a/cpp/src/pypowsybl.cpp b/cpp/src/pypowsybl.cpp index c17cbbecb..f87212eea 100644 --- a/cpp/src/pypowsybl.cpp +++ b/cpp/src/pypowsybl.cpp @@ -1311,4 +1311,8 @@ void createNetworkModification(pypowsybl::JavaHandle network, dataframe_array* d pypowsybl::callJava(::createNetworkModification, network, dataframes, networkModificationType, throwException, (reporter == nullptr) ? nullptr : *reporter); } +void moveConnectable(pypowsybl::JavaHandle network, std::string equipmentId, std::string idBusOrigin, std::string idBusDestination) { + pypowsybl::callJava(::moveConnectable, network, (char*) equipmentId.c_str(), (char*) idBusOrigin.c_str(), (char*) idBusDestination.c_str()); +} + } diff --git a/cpp/src/pypowsybl.h b/cpp/src/pypowsybl.h index 86a6ca58e..6220af233 100644 --- a/cpp/src/pypowsybl.h +++ b/cpp/src/pypowsybl.h @@ -521,6 +521,8 @@ SeriesArray* getConnectablesOrderPositions(const JavaHandle& network, const std: std::vector getUnusedConnectableOrderPositions(pypowsybl::JavaHandle network, std::string busbarSectionId, std::string beforeOrAfter); +void moveConnectable(pypowsybl::JavaHandle network, std::string equipmentId, std::string idBusOrigin, std::string idBusDestination); + void removeAliases(pypowsybl::JavaHandle network, dataframe* dataframe); void closePypowsybl(); diff --git a/java/src/main/java/com/powsybl/python/network/NetworkCFunctions.java b/java/src/main/java/com/powsybl/python/network/NetworkCFunctions.java index 0106fcae1..29399fcf3 100644 --- a/java/src/main/java/com/powsybl/python/network/NetworkCFunctions.java +++ b/java/src/main/java/com/powsybl/python/network/NetworkCFunctions.java @@ -978,4 +978,17 @@ public static DataframesMetadataPointer getModificationMetadataWithElementType(I return res; }); } + + @CEntryPoint(name = "moveConnectable") + public static void moveConnectable(IsolateThread thread, ObjectHandle networkHandle, CCharPointer equipmentId, + CCharPointer busOrigin, CCharPointer busDestination, + ExceptionHandlerPointer exceptionHandlerPtr) { + doCatch(exceptionHandlerPtr, () -> { + Network network = ObjectHandles.getGlobal().get(networkHandle); + String idEq = CTypeUtil.toString(equipmentId); + String idBusOrigin = CTypeUtil.toString(busOrigin); + String idBusDestination = CTypeUtil.toString(busDestination); + NetworkUtil.moveConnectable(network, idEq, idBusOrigin, idBusDestination); + }); + } } diff --git a/java/src/main/java/com/powsybl/python/network/NetworkUtil.java b/java/src/main/java/com/powsybl/python/network/NetworkUtil.java index 1a9c44fe7..e8a489031 100644 --- a/java/src/main/java/com/powsybl/python/network/NetworkUtil.java +++ b/java/src/main/java/com/powsybl/python/network/NetworkUtil.java @@ -238,4 +238,24 @@ public static Stream getFeeders(Network network) return feeders.build(); } + public static void moveConnectable(Network network, String equipmentId, String busOrigin, String busDestination) { + Bus b = network.getBusBreakerView().getBus(busOrigin); + if (b == null) { + throw new PowsyblException("Cannot find bus origin " + busOrigin + " in the bus breaker view"); + } + if (network.getBusBreakerView().getBus(busDestination) == null) { + throw new PowsyblException("Cannot find bus destination " + busDestination + " in the bus breaker view"); + } + + boolean foundTerminal = false; + for (Terminal t : b.getConnectedTerminals()) { + if (t.getConnectable().getId().equals(equipmentId)) { + t.getBusBreakerView().moveConnectable(busDestination, true); + foundTerminal = true; + } + } + if (!foundTerminal) { + throw new PowsyblException("Could not find terminal for equipment " + equipmentId + " in bus " + busOrigin); + } + } } diff --git a/pypowsybl/network.py b/pypowsybl/network.py index 1815195f3..b7e59cea8 100644 --- a/pypowsybl/network.py +++ b/pypowsybl/network.py @@ -5796,6 +5796,8 @@ def create_voltage_level_topology(network: Network, df: _DataFrame = None, raise raise_exception, None if reporter is None else reporter._reporter_model) # pylint: disable=protected-access +def move_connectable(network: Network, equipment_id: str, bus_origin_id: str, bus_destination_id: str) -> None: + _pp.move_connectable(network._handle, equipment_id, bus_origin_id, bus_destination_id) def transform_list_to_str(entry: _Union[str, _List[str]]) -> str: if isinstance(entry, list): diff --git a/tests/test_network.py b/tests/test_network.py index 76313792b..9b9de9433 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -1772,6 +1772,9 @@ def test_terminals(): n.update_terminals(element_id='LINE_S2S3', connected=False, element_side='side') assert "No enum constant" in str(e) +def test_move_connectable(): + n = pp.network.create_ieee14() + pp.network.move_connectable(network=n, equipment_id='L1-2-1', bus_origin_id='B1', bus_destination_id='B5') if __name__ == '__main__': unittest.main() From d00316ef6629b8f094d306e089f4c8f8a9dd8fee Mon Sep 17 00:00:00 2001 From: Bertrand Rix Date: Wed, 4 Oct 2023 10:36:45 +0200 Subject: [PATCH 2/3] Add temporary fix for generator regulating terminal. Signed-off-by: Bertrand Rix --- .../java/com/powsybl/python/network/NetworkUtil.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/java/src/main/java/com/powsybl/python/network/NetworkUtil.java b/java/src/main/java/com/powsybl/python/network/NetworkUtil.java index e8a489031..94cea24bf 100644 --- a/java/src/main/java/com/powsybl/python/network/NetworkUtil.java +++ b/java/src/main/java/com/powsybl/python/network/NetworkUtil.java @@ -247,6 +247,15 @@ public static void moveConnectable(Network network, String equipmentId, String b throw new PowsyblException("Cannot find bus destination " + busDestination + " in the bus breaker view"); } + boolean updateRegulatingTerminal = false; + Generator gen = network.getGenerator(equipmentId); + if (gen != null && gen.getRegulatingTerminal().equals(gen.getTerminal())) { + //Equipment is a generator, move connectable does not update regulating terminal properly, + //If generator is regulating on its terminal we have to update it manually + //Fix to do properly within move connectable in powsybl-core + updateRegulatingTerminal = true; + } + boolean foundTerminal = false; for (Terminal t : b.getConnectedTerminals()) { if (t.getConnectable().getId().equals(equipmentId)) { @@ -257,5 +266,8 @@ public static void moveConnectable(Network network, String equipmentId, String b if (!foundTerminal) { throw new PowsyblException("Could not find terminal for equipment " + equipmentId + " in bus " + busOrigin); } + if (updateRegulatingTerminal) { + gen.setRegulatingTerminal(gen.getTerminal()); + } } } From 81268bc9e62afcb1feba6e2fba5ebe1a32bfcce4 Mon Sep 17 00:00:00 2001 From: Bertrand Rix Date: Wed, 4 Oct 2023 15:05:13 +0200 Subject: [PATCH 3/3] Update slack terminal if connectable is related. Signed-off-by: Bertrand Rix --- .../com/powsybl/python/network/NetworkUtil.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/java/src/main/java/com/powsybl/python/network/NetworkUtil.java b/java/src/main/java/com/powsybl/python/network/NetworkUtil.java index 94cea24bf..1fd648a84 100644 --- a/java/src/main/java/com/powsybl/python/network/NetworkUtil.java +++ b/java/src/main/java/com/powsybl/python/network/NetworkUtil.java @@ -10,6 +10,7 @@ import com.powsybl.dataframe.network.extensions.ConnectablePositionFeederData; import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.extensions.ConnectablePosition; +import com.powsybl.iidm.network.extensions.SlackTerminal; import com.powsybl.python.commons.PyPowsyblApiHeader; import java.util.List; @@ -258,8 +259,21 @@ public static void moveConnectable(Network network, String equipmentId, String b boolean foundTerminal = false; for (Terminal t : b.getConnectedTerminals()) { - if (t.getConnectable().getId().equals(equipmentId)) { + Connectable connectable = t.getConnectable(); + if (connectable.getId().equals(equipmentId)) { + SlackTerminal slackTerminal = t.getVoltageLevel().getExtension(SlackTerminal.class); + //Terminal of the connectable was a slack terminal, mus be updated after the move... + boolean updateSlackTerminal = slackTerminal != null && slackTerminal.getTerminal().equals(t); + t.getBusBreakerView().moveConnectable(busDestination, true); + + if (updateSlackTerminal) { + for (Terminal newTerminal : connectable.getTerminals()) { + if (newTerminal.getBusBreakerView().getBus().getId().equals(busDestination)) { + slackTerminal.setTerminal(newTerminal); + } + } + } foundTerminal = true; } }