From 10aa574b442f904b0a3d22f18352a8cd5485e2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LAIGRE?= Date: Thu, 10 Feb 2022 17:17:36 +0100 Subject: [PATCH 01/11] Update Traverse API (#362, #367, #394 and #387) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien LAIGRE --- include/powsybl/iidm/VoltageLevelViews.hpp | 10 ++- .../powsybl/iidm/util/NodeBreakerTopology.hpp | 29 +++++++ include/powsybl/math/TraverseResult.hpp | 8 +- include/powsybl/math/UndirectedGraph.hpp | 6 +- include/powsybl/math/UndirectedGraph.hxx | 44 +++++++++-- src/CMakeLists.txt | 1 + src/iidm/BusBreakerVoltageLevel.cpp | 2 +- src/iidm/BusBreakerVoltageLevelTopology.cpp | 2 +- src/iidm/BusBreakerVoltageLevelViews.cpp | 9 +++ src/iidm/BusBreakerVoltageLevelViews.hpp | 2 + src/iidm/CalculatedBus.cpp | 19 +---- src/iidm/NodeBreakerVoltageLevel.cpp | 4 +- src/iidm/NodeBreakerVoltageLevelTopology.cpp | 6 +- src/iidm/NodeBreakerVoltageLevelViews.cpp | 16 +++- src/iidm/NodeBreakerVoltageLevelViews.hpp | 4 + src/iidm/util/Networks.cpp | 4 +- src/iidm/util/NodeBreakerTopology.cpp | 74 +++++++++++++++++ test/iidm/CMakeLists.txt | 1 + test/iidm/NetworkFactory.cpp | 79 +++++++++++++++++++ test/iidm/NetworkFactory.hpp | 2 + test/iidm/NodeBreakerVoltageLevelTest.cpp | 2 +- test/iidm/util/NodeBreakerTopologyTest.cpp | 79 +++++++++++++++++++ test/math/UndirectedGraphTest.cpp | 39 +++++++-- 23 files changed, 396 insertions(+), 46 deletions(-) create mode 100644 include/powsybl/iidm/util/NodeBreakerTopology.hpp create mode 100644 src/iidm/util/NodeBreakerTopology.cpp create mode 100644 test/iidm/util/NodeBreakerTopologyTest.cpp diff --git a/include/powsybl/iidm/VoltageLevelViews.hpp b/include/powsybl/iidm/VoltageLevelViews.hpp index 84b7ccce7..fee2bd382 100644 --- a/include/powsybl/iidm/VoltageLevelViews.hpp +++ b/include/powsybl/iidm/VoltageLevelViews.hpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -35,6 +37,8 @@ class BusBreakerView { public: using SwitchAdder = bus_breaker_view::SwitchAdder; + using Traverser = std::function& sw, const Bus& bus2)>; + public: virtual ~BusBreakerView() noexcept = default; @@ -75,6 +79,8 @@ class BusBreakerView { virtual void removeBus(const std::string& busId) = 0; virtual void removeSwitch(const std::string& switchId) = 0; + + virtual void traverse(const Bus& bus, Traverser& traverser) = 0; }; class BusView { @@ -102,7 +108,7 @@ class NodeBreakerView { using SwitchAdder = node_breaker_view::SwitchAdder; - using Traverser = std::function& sw, unsigned long node2)>; + using Traverser = std::function& sw, unsigned long node2)>; public: virtual ~NodeBreakerView() noexcept = default; @@ -172,6 +178,8 @@ class NodeBreakerView { virtual void removeSwitch(const std::string& switchId) = 0; virtual void traverse(unsigned long node, const Traverser& traverser) const = 0; + + virtual void traverse(stdcxx::const_range& nodes, const Traverser& traverser) const = 0; }; } // namespace voltage_level diff --git a/include/powsybl/iidm/util/NodeBreakerTopology.hpp b/include/powsybl/iidm/util/NodeBreakerTopology.hpp new file mode 100644 index 000000000..e5a6e45c6 --- /dev/null +++ b/include/powsybl/iidm/util/NodeBreakerTopology.hpp @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2022, 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/. + */ + +#ifndef POWSYBL_IIDM_UTIL_NODEBREAKERTOPOLOGY_HPP +#define POWSYBL_IIDM_UTIL_NODEBREAKERTOPOLOGY_HPP + +#include + +namespace powsybl { + +namespace iidm { + +namespace NodeBreakerTopology { + +unsigned long newStandardConnection(BusbarSection& bb); + +void removeIsolatedSwitches(voltage_level::NodeBreakerView& topo); + +} // namespace NodeBreakerTopology + +} // namespace iidm + +} // namespace powsybl + +#endif // POWSYBL_IIDM_UTIL_NODEBREAKERTOPOLOGY_HPP diff --git a/include/powsybl/math/TraverseResult.hpp b/include/powsybl/math/TraverseResult.hpp index 65f55ad34..9ae4af2b8 100644 --- a/include/powsybl/math/TraverseResult.hpp +++ b/include/powsybl/math/TraverseResult.hpp @@ -13,8 +13,14 @@ namespace powsybl { namespace math { enum class TraverseResult { + /** Indicates that traversal should continue */ CONTINUE, - TERMINATE + + /** Indicates that traversal should terminate on current path */ + TERMINATE_PATH, + + /** Indicates that traversal should break, i.e., terminate on all paths */ + TERMINATE_TRAVERSER }; } // namespace math diff --git a/include/powsybl/math/UndirectedGraph.hpp b/include/powsybl/math/UndirectedGraph.hpp index e80ba56a4..5c9f31ecf 100644 --- a/include/powsybl/math/UndirectedGraph.hpp +++ b/include/powsybl/math/UndirectedGraph.hpp @@ -92,9 +92,11 @@ class UndirectedGraph { void setVertexObject(unsigned long v, const stdcxx::Reference& object); - void traverse(unsigned long v, const Traverser& traverser) const; + bool traverse(unsigned long v, const Traverser& traverser) const; - void traverse(unsigned long v, const Traverser& traverser, std::vector& encountered) const; + bool traverse(stdcxx::const_range& startingVertices, const Traverser& traverser) const; + + bool traverse(unsigned long v, const Traverser& traverser, std::vector& encountered) const; bool vertexExists(unsigned long v) const; diff --git a/include/powsybl/math/UndirectedGraph.hxx b/include/powsybl/math/UndirectedGraph.hxx index 90746fdc9..9aac1fe13 100644 --- a/include/powsybl/math/UndirectedGraph.hxx +++ b/include/powsybl/math/UndirectedGraph.hxx @@ -418,14 +418,28 @@ void UndirectedGraph::setVertexObject(unsigned long v, const stdcxx::Refer } template -void UndirectedGraph::traverse(unsigned long v, const Traverser& traverser) const { +bool UndirectedGraph::traverse(unsigned long v, const Traverser& traverser) const { std::vector encountered(m_vertices.size(), false); - traverse(v, traverser, encountered); + return traverse(v, traverser, encountered); } template -void UndirectedGraph::traverse(unsigned long v, const Traverser& traverser, std::vector& encountered) const { +bool UndirectedGraph::traverse(stdcxx::const_range& startingVertices, const Traverser& traverser) const { + std::vector encountered(m_vertices.size(), false); + + for (unsigned long startingVertex : startingVertices) { + if (!encountered[startingVertex]) { + if (!traverse(startingVertex, traverser, encountered)) { + return false; + } + } + } + return true; +} + +template +bool UndirectedGraph::traverse(unsigned long v, const Traverser& traverser, std::vector& encountered) const { checkVertex(v); encountered.resize(m_vertices.size(), false); @@ -434,20 +448,34 @@ void UndirectedGraph::traverse(unsigned long v, const Traverser& traverser const std::vector& adjacentEdges = adjacencyList[v]; encountered[v] = true; + bool keepGoing = true; for (unsigned long e : adjacentEdges) { const std::unique_ptr& edge = m_edges[e]; unsigned long v1 = edge->getVertex1(); unsigned long v2 = edge->getVertex2(); if (!encountered[v1]) { - if (traverser(v2, e, v1) == TraverseResult::CONTINUE) { + const TraverseResult& traverserResult = traverser(v2, e, v1); + if (traverserResult == TraverseResult::CONTINUE) { encountered[v1] = true; - traverse(v1, traverser, encountered); + keepGoing = traverse(v1, traverser, encountered); + } else if (traverserResult == TraverseResult::TERMINATE_TRAVERSER) { + keepGoing = false; + } + } else if (!encountered[v2]) { + const TraverseResult& traverserResult = traverser(v1, e, v2); + if (traverserResult == TraverseResult::CONTINUE) { + encountered[v2] = true; + keepGoing = traverse(v2, traverser, encountered); + } else if (traverserResult == TraverseResult::TERMINATE_TRAVERSER) { + keepGoing = false; } - } else if (!encountered[v2] && (traverser(v1, e, v2) == TraverseResult::CONTINUE)) { - encountered[v2] = true; - traverse(v2, traverser, encountered); + } + if (!keepGoing) { + break; } } + + return keepGoing; } template diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4fdc2480b..894dddedf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -205,6 +205,7 @@ set(IIDM_SOURCES iidm/util/LimitViolationUtils.cpp iidm/util/LinkData.cpp iidm/util/Networks.cpp + iidm/util/NodeBreakerTopology.cpp iidm/util/Substations.cpp iidm/util/SV.cpp iidm/util/TerminalFinder.cpp diff --git a/src/iidm/BusBreakerVoltageLevel.cpp b/src/iidm/BusBreakerVoltageLevel.cpp index 952b8ca2c..21890d4b2 100644 --- a/src/iidm/BusBreakerVoltageLevel.cpp +++ b/src/iidm/BusBreakerVoltageLevel.cpp @@ -405,7 +405,7 @@ void BusBreakerVoltageLevel::traverse(BusTerminal& terminal, VoltageLevel::Topol return math::TraverseResult::CONTINUE; } } - return math::TraverseResult::TERMINATE; + return math::TraverseResult::TERMINATE_PATH; }); for (Terminal& t : nextTerminals) { diff --git a/src/iidm/BusBreakerVoltageLevelTopology.cpp b/src/iidm/BusBreakerVoltageLevelTopology.cpp index a670bb022..99cd09854 100644 --- a/src/iidm/BusBreakerVoltageLevelTopology.cpp +++ b/src/iidm/BusBreakerVoltageLevelTopology.cpp @@ -126,7 +126,7 @@ void CalculatedBusTopology::updateCache() { graph.traverse(v, [&busSet, &graph](unsigned long /*v1*/, unsigned long e, unsigned long v2) { stdcxx::Reference aSwitch = graph.getEdgeObject(e); if (aSwitch.get().isOpen()) { - return math::TraverseResult::TERMINATE; + return math::TraverseResult::TERMINATE_PATH; } busSet.push_back(std::ref(graph.getVertexObject(v2).get())); diff --git a/src/iidm/BusBreakerVoltageLevelViews.cpp b/src/iidm/BusBreakerVoltageLevelViews.cpp index 668eaac90..996378190 100644 --- a/src/iidm/BusBreakerVoltageLevelViews.cpp +++ b/src/iidm/BusBreakerVoltageLevelViews.cpp @@ -125,6 +125,15 @@ void BusBreakerViewImpl::removeSwitch(const std::string& switchId) { m_voltageLevel.removeSwitch(switchId); } +void BusBreakerViewImpl::traverse(const Bus& bus, Traverser& traverser) { + math::Traverser graphTraverser = [this, &traverser](unsigned long v1, unsigned long e, unsigned long v2) { + const auto& graph = m_voltageLevel.getGraph(); + return traverser(graph.getVertexObject(v1), graph.getEdgeObject(e), graph.getVertexObject(v2)); + }; + + m_voltageLevel.getGraph().traverse(*m_voltageLevel.getVertex(bus.getId(), true), graphTraverser); +} + BusViewImpl::BusViewImpl(BusBreakerVoltageLevel& voltageLevel) : m_voltageLevel(voltageLevel) { } diff --git a/src/iidm/BusBreakerVoltageLevelViews.hpp b/src/iidm/BusBreakerVoltageLevelViews.hpp index f393a9669..0a9a82b9d 100644 --- a/src/iidm/BusBreakerVoltageLevelViews.hpp +++ b/src/iidm/BusBreakerVoltageLevelViews.hpp @@ -59,6 +59,8 @@ class BusBreakerViewImpl : public voltage_level::BusBreakerView { void removeSwitch(const std::string& switchId) override; + void traverse(const Bus& bus, Traverser& traverser) override; + public: explicit BusBreakerViewImpl(BusBreakerVoltageLevel& voltageLevel); diff --git a/src/iidm/CalculatedBus.cpp b/src/iidm/CalculatedBus.cpp index 30652f323..c0327c82a 100644 --- a/src/iidm/CalculatedBus.cpp +++ b/src/iidm/CalculatedBus.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -38,23 +39,7 @@ stdcxx::CReference CalculatedBus::findTerminal(const NodeBreakerVo if (!terminals.empty()) { return stdcxx::cref(terminals.front().get()); } - - stdcxx::CReference terminal; - - VoltageLevel::NodeBreakerView::Traverser traverser = [&terminal, &voltageLevel](unsigned long /*node1*/, const stdcxx::Reference& sw, unsigned long node2) { - if (terminal) { - return false; - } - - if (static_cast(sw) && sw.get().isOpen()) { - return false; - } - terminal = voltageLevel.getNodeBreakerView().getTerminal(node2); - return !static_cast(terminal); - }; - voltageLevel.getNodeBreakerView().traverse(nodes.front(), traverser); - - return stdcxx::cref(terminal); + return stdcxx::cref(Networks::getEquivalentTerminal(voltageLevel, nodes.front())); } double CalculatedBus::getAngle() const { diff --git a/src/iidm/NodeBreakerVoltageLevel.cpp b/src/iidm/NodeBreakerVoltageLevel.cpp index d262806ee..cd66ca205 100644 --- a/src/iidm/NodeBreakerVoltageLevel.cpp +++ b/src/iidm/NodeBreakerVoltageLevel.cpp @@ -422,9 +422,9 @@ void NodeBreakerVoltageLevel::traverse(NodeTerminal& terminal, VoltageLevel::Top addNextTerminals(otherTerminal.get(), nextTerminals); return math::TraverseResult::CONTINUE; } - return math::TraverseResult::TERMINATE; + return math::TraverseResult::TERMINATE_PATH; } - return math::TraverseResult::TERMINATE; + return math::TraverseResult::TERMINATE_PATH; }); for (auto nextTerminal : nextTerminals) { diff --git a/src/iidm/NodeBreakerVoltageLevelTopology.cpp b/src/iidm/NodeBreakerVoltageLevelTopology.cpp index 9ca3179d2..3ad026db1 100644 --- a/src/iidm/NodeBreakerVoltageLevelTopology.cpp +++ b/src/iidm/NodeBreakerVoltageLevelTopology.cpp @@ -168,11 +168,11 @@ stdcxx::Reference CalculatedBusTopology::getConnectableBus(unsigned long no if (static_cast(connectableBus)) { // traverse does not stop the algorithm when TERMINATE, it only stops searching in a given direction // this condition insures that while checking all the edges (in every direction) of a node, if a bus is found, it will not be lost - return math::TraverseResult::TERMINATE; + return math::TraverseResult::TERMINATE_PATH; } connectableBus = getBus(v2); - return static_cast(connectableBus) ? math::TraverseResult::TERMINATE : math::TraverseResult::CONTINUE; + return static_cast(connectableBus) ? math::TraverseResult::TERMINATE_PATH : math::TraverseResult::CONTINUE; }); // if nothing found, just take the first bus @@ -261,7 +261,7 @@ void CalculatedBusTopology::traverse(unsigned long v, std::vector& encount graph.traverse(v, [&graph, &terminate, &vertices](unsigned long /*v1*/, unsigned long e, unsigned long v2) { const stdcxx::Reference aSwitch = graph.getEdgeObject(e); if (static_cast(aSwitch) && terminate(aSwitch)) { - return math::TraverseResult::TERMINATE; + return math::TraverseResult::TERMINATE_PATH; } vertices.push_back(v2); diff --git a/src/iidm/NodeBreakerVoltageLevelViews.cpp b/src/iidm/NodeBreakerVoltageLevelViews.cpp index e43dd82fb..c239d9b5b 100644 --- a/src/iidm/NodeBreakerVoltageLevelViews.cpp +++ b/src/iidm/NodeBreakerVoltageLevelViews.cpp @@ -109,6 +109,10 @@ void BusBreakerViewImpl::removeSwitch(const std::string& /*switchId*/) { throw AssertionError("Not implemented"); } +void BusBreakerViewImpl::traverse(const Bus& /*bus*/, Traverser& /*traverser*/) { + throw AssertionError("Not implemented"); +} + BusViewImpl::BusViewImpl(NodeBreakerVoltageLevel& voltageLevel) : m_voltageLevel(voltageLevel) { } @@ -312,13 +316,21 @@ void NodeBreakerViewImpl::removeSwitch(const std::string& switchId) { } void NodeBreakerViewImpl::traverse(unsigned long node, const Traverser& traverser) const { - powsybl::math::Traverser graphTraverser = [this, &traverser](unsigned long v1, unsigned long e, unsigned long v2) { - return traverser(v1, m_voltageLevel.getGraph().getEdgeObject(e), v2) ? powsybl::math::TraverseResult::CONTINUE : powsybl::math::TraverseResult::TERMINATE; + math::Traverser graphTraverser = [this, &traverser](unsigned long v1, unsigned long e, unsigned long v2) { + return traverser(v1, m_voltageLevel.getGraph().getEdgeObject(e), v2); }; m_voltageLevel.getGraph().traverse(node, graphTraverser); } +void NodeBreakerViewImpl::traverse(stdcxx::const_range& nodes, const Traverser& traverser) const { + powsybl::math::Traverser graphTraverser = [this, &traverser](unsigned long v1, unsigned long e, unsigned long v2) { + return traverser(v1, m_voltageLevel.getGraph().getEdgeObject(e), v2); + }; + + m_voltageLevel.getGraph().traverse(nodes, graphTraverser); +} + } // namespace node_breaker_voltage_level } // namespace iidm diff --git a/src/iidm/NodeBreakerVoltageLevelViews.hpp b/src/iidm/NodeBreakerVoltageLevelViews.hpp index 070051d78..d69a07c94 100644 --- a/src/iidm/NodeBreakerVoltageLevelViews.hpp +++ b/src/iidm/NodeBreakerVoltageLevelViews.hpp @@ -84,6 +84,8 @@ class NodeBreakerViewImpl : public voltage_level::NodeBreakerView { void traverse(unsigned long node, const Traverser& traverser) const override; + void traverse(stdcxx::const_range& nodes, const Traverser& traverser) const override; + public: explicit NodeBreakerViewImpl(NodeBreakerVoltageLevel& voltageLevel); @@ -121,6 +123,8 @@ class BusBreakerViewImpl : public voltage_level::BusBreakerView { unsigned long getSwitchCount() const override; + void traverse(const Bus& bus, Traverser& traverser) override; + public: explicit BusBreakerViewImpl(NodeBreakerVoltageLevel& voltageLevel); diff --git a/src/iidm/util/Networks.cpp b/src/iidm/util/Networks.cpp index df42d0278..f29ffc3d8 100644 --- a/src/iidm/util/Networks.cpp +++ b/src/iidm/util/Networks.cpp @@ -28,13 +28,13 @@ stdcxx::CReference getEquivalentTerminal(const VoltageLevel& voltageLe VoltageLevel::NodeBreakerView::Traverser traverser = [&equivalentTerminal, &voltageLevel](unsigned long /*node1*/, const stdcxx::Reference& sw, unsigned long node2) { if (sw && sw.get().isOpen()) { - return false; + return math::TraverseResult::TERMINATE_PATH; } const auto& terminal = voltageLevel.getNodeBreakerView().getTerminal(node2); if (terminal) { equivalentTerminal = terminal; } - return !terminal; + return terminal ? math::TraverseResult::TERMINATE_TRAVERSER : math::TraverseResult::CONTINUE; }; voltageLevel.getNodeBreakerView().traverse(node, traverser); diff --git a/src/iidm/util/NodeBreakerTopology.cpp b/src/iidm/util/NodeBreakerTopology.cpp new file mode 100644 index 000000000..c282f2b2e --- /dev/null +++ b/src/iidm/util/NodeBreakerTopology.cpp @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2022, 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/. + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace powsybl { + +namespace iidm { + +namespace NodeBreakerTopology { + +unsigned long newStandardConnection(BusbarSection& bb) { + unsigned long n = bb.getTerminal().getNodeBreakerView().getNode(); + VoltageLevel::NodeBreakerView& topo = bb.getTerminal().getVoltageLevel().getNodeBreakerView(); + + const long& oldCount = topo.getMaximumNodeIndex() + 1L; + topo.newDisconnector() + .setId(stdcxx::format("disconnector %1%-%2%", bb.getId(), oldCount)) + .setNode1(n) + .setNode2(oldCount) + .add(); + topo.newBreaker() + .setId(stdcxx::format("breaker %1%-%2%", bb.getId(), oldCount + 1)) + .setNode1(oldCount) + .setNode2(oldCount + 1) + .add(); + + return oldCount + 1; +} + +void removeIsolatedSwitches(voltage_level::NodeBreakerView& topo) { + const auto& filter = [&topo](unsigned int node) { + return static_cast(topo.getTerminal(node)); + }; + stdcxx::const_range nodesWithTerminal = topo.getNodes() | boost::adaptors::filtered(filter); + + std::vector> encounteredSwitches; + voltage_level::NodeBreakerView::Traverser traverser = [&encounteredSwitches](unsigned long /*node1*/, const stdcxx::Reference& sw, unsigned long /*node2*/) { + encounteredSwitches.emplace_back(std::ref(sw.get())); // the traversing started from a terminal, thus the switch is not isolated + return math::TraverseResult::CONTINUE; // if n2 has a terminal, we could also choose to stop as it will be or has already been traversed + }; + topo.traverse(nodesWithTerminal, traverser); + + const auto& filterNotEncounteredSwitches = [&encounteredSwitches](const Switch& sw) { + auto it = std::find_if(encounteredSwitches.begin(), encounteredSwitches.end(), [&sw](const std::reference_wrapper& swInList) { + return stdcxx::areSame(sw, swInList.get()); + }); + return it == encounteredSwitches.end(); + }; + for (const Switch& sw : topo.getSwitches() | boost::adaptors::filtered(filterNotEncounteredSwitches)) { + topo.removeSwitch(sw.getId()); + } +} + +} // namespace NodeBreakerTopology + +} // namespace iidm + +} // namespace powsybl diff --git a/test/iidm/CMakeLists.txt b/test/iidm/CMakeLists.txt index eca01abbb..8bc4dfa40 100644 --- a/test/iidm/CMakeLists.txt +++ b/test/iidm/CMakeLists.txt @@ -60,6 +60,7 @@ set(UNIT_TEST_SOURCES extensions/SlackTerminalTest.cpp util/SVTest.cpp + util/NodeBreakerTopologyTest.cpp util/TerminalFinderTest.cpp ) diff --git a/test/iidm/NetworkFactory.cpp b/test/iidm/NetworkFactory.cpp index e3b3b55a9..ddabbe156 100644 --- a/test/iidm/NetworkFactory.cpp +++ b/test/iidm/NetworkFactory.cpp @@ -8,6 +8,9 @@ #include "NetworkFactory.hpp" #include +#include +#include +#include #include #include #include @@ -121,6 +124,82 @@ Network createNetwork() { return network; } +Network createNetworkTest1() { + Network network("network", "test"); + Substation& substation1 = network.newSubstation() + .setId("substation1") + .setCountry(Country::FR) + .setTso("TSO1") + .setGeographicalTags({"region1"}) + .add(); + VoltageLevel& voltageLevel1 = substation1.newVoltageLevel() + .setId("voltageLevel1") + .setNominalV(400) + .setTopologyKind(TopologyKind::NODE_BREAKER) + .add(); + VoltageLevel::NodeBreakerView& topology1 = voltageLevel1.getNodeBreakerView(); + BusbarSection& voltageLevel1BusbarSection1 = topology1.newBusbarSection() + .setId("voltageLevel1BusbarSection1") + .setNode(0) + .add(); + BusbarSection& voltageLevel1BusbarSection2 = topology1.newBusbarSection() + .setId("voltageLevel1BusbarSection2") + .setNode(1) + .add(); + topology1.newBreaker() + .setId("voltageLevel1Breaker1") + .setRetained(true) + .setOpen(false) + .setNode1(voltageLevel1BusbarSection1.getTerminal().getNodeBreakerView().getNode()) + .setNode2(voltageLevel1BusbarSection2.getTerminal().getNodeBreakerView().getNode()) + .add(); + Load& load1 = voltageLevel1.newLoad() + .setId("load1") + .setNode(2) + .setP0(10) + .setQ0(3) + .add(); + topology1.newDisconnector() + .setId("load1Disconnector1") + .setOpen(false) + .setNode1(load1.getTerminal().getNodeBreakerView().getNode()) + .setNode2(3) + .add(); + topology1.newDisconnector() + .setId("load1Breaker1") + .setOpen(false) + .setNode1(3) + .setNode2(voltageLevel1BusbarSection1.getTerminal().getNodeBreakerView().getNode()) + .add(); + Generator& generator1 = voltageLevel1.newGenerator() + .setId("generator1") + .setEnergySource(EnergySource::NUCLEAR) + .setMinP(200.0) + .setMaxP(900.0) + .setVoltageRegulatorOn(true) + .setTargetP(900.0) + .setTargetV(380.0) + .setNode(5) + .add(); + generator1.newReactiveCapabilityCurve() + .beginPoint().setP(200.0).setMinQ(300.0).setMaxQ(500.0).endPoint() + .beginPoint().setP(900.0).setMinQ(300.0).setMaxQ(500.0).endPoint() + .add(); + topology1.newDisconnector() + .setId("generator1Disconnector1") + .setOpen(false) + .setNode1(generator1.getTerminal().getNodeBreakerView().getNode()) + .setNode2(6) + .add(); + topology1.newDisconnector() + .setId("generator1Breaker1") + .setOpen(false) + .setNode1(6) + .setNode2(voltageLevel1BusbarSection2.getTerminal().getNodeBreakerView().getNode()) + .add(); + return network; +} + Terminal& getTerminalFromNetwork2() { if(network2.getSubstationCount() == 0) { Substation& s = network2.newSubstation() diff --git a/test/iidm/NetworkFactory.hpp b/test/iidm/NetworkFactory.hpp index 967b5239b..3a99a21f3 100644 --- a/test/iidm/NetworkFactory.hpp +++ b/test/iidm/NetworkFactory.hpp @@ -23,6 +23,8 @@ Network createHvdcConverterStationTestNetwork(); Network createNetwork(); +Network createNetworkTest1(); + Terminal& getTerminalFromNetwork2(); Network createDanglingLineNetwork(); diff --git a/test/iidm/NodeBreakerVoltageLevelTest.cpp b/test/iidm/NodeBreakerVoltageLevelTest.cpp index 92196a396..cb4cfd99e 100644 --- a/test/iidm/NodeBreakerVoltageLevelTest.cpp +++ b/test/iidm/NodeBreakerVoltageLevelTest.cpp @@ -615,7 +615,7 @@ BOOST_AUTO_TEST_CASE(NodeBreakerViewTest) { POWSYBL_ASSERT_THROW(voltageLevel.getNodeBreakerView().getNode1("UNKNOWN"), PowsyblException, "Switch 'UNKNOWN' not found in the voltage level 'VL2'"); VoltageLevel::NodeBreakerView::Traverser traverser = [=](unsigned long /*node1*/, const stdcxx::Reference& /*sw*/, unsigned long node2) { - return (node2 < (NODE_COUNT - 1)); + return (node2 < (NODE_COUNT - 1)) ? math::TraverseResult::CONTINUE : math::TraverseResult::TERMINATE_TRAVERSER; }; voltageLevel.getNodeBreakerView().traverse(0, traverser); diff --git a/test/iidm/util/NodeBreakerTopologyTest.cpp b/test/iidm/util/NodeBreakerTopologyTest.cpp new file mode 100644 index 000000000..2d183bb26 --- /dev/null +++ b/test/iidm/util/NodeBreakerTopologyTest.cpp @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2022, 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/. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "../NetworkFactory.hpp" + +namespace powsybl { + +namespace iidm { + +BOOST_AUTO_TEST_SUITE(NodeBreakerTopologyTestSuite) + +BOOST_AUTO_TEST_CASE(removeIsolatedSwitches) { + Network network = createNetworkTest1(); + + VoltageLevel& vl = network.getVoltageLevel("voltageLevel1"); + VoltageLevel::NodeBreakerView& topo = vl.getNodeBreakerView(); + + BOOST_CHECK(topo.getSwitch("load1Disconnector1")); + BOOST_CHECK(topo.getSwitch("load1Breaker1")); + BOOST_CHECK_EQUAL(5, topo.getSwitchCount()); + + // remove the load + vl.getConnectable("load1").get().remove(); + BOOST_CHECK(!vl.getConnectable("load1")); + + // remove the switch connected to the bus bar + topo.removeSwitch("load1Breaker1"); + BOOST_CHECK(!topo.getSwitch("load1Breaker1")); + + // The connecting switch of the load is now isolated: remove it + NodeBreakerTopology::removeIsolatedSwitches(topo); + + BOOST_CHECK(!topo.getSwitch("load1Disconnector1")); + BOOST_CHECK(!topo.getSwitch("load1Breaker1")); + // 2 switches have been removed + BOOST_CHECK_EQUAL(3, topo.getSwitchCount()); +} + +BOOST_AUTO_TEST_CASE(newStandardConnection) { + Network network = createNetworkTest1(); + + VoltageLevel& vl = network.getVoltageLevel("voltageLevel1"); + VoltageLevel::NodeBreakerView& topo = vl.getNodeBreakerView(); + + unsigned long initialSwitchCount = topo.getSwitchCount(); + + BusbarSection& bb = topo.getBusbarSection("voltageLevel1BusbarSection1"); + unsigned long connectionNode = NodeBreakerTopology::newStandardConnection(bb); + + const Load& load = vl.newLoad() + .setId("load2") + .setP0(10) + .setQ0(0) + .setNode(connectionNode) + .add(); + + // Check the new load is correctly connected to the bus corresponding to the bus bar. + BOOST_CHECK(stdcxx::areSame(bb.getTerminal().getBusView().getBus().get(), load.getTerminal().getBusView().getBus().get())); + BOOST_CHECK_EQUAL(initialSwitchCount + 2, topo.getSwitchCount()); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace iidm + +} // namespace powsybl diff --git a/test/math/UndirectedGraphTest.cpp b/test/math/UndirectedGraphTest.cpp index 02c78c13b..fe6ef28e4 100644 --- a/test/math/UndirectedGraphTest.cpp +++ b/test/math/UndirectedGraphTest.cpp @@ -308,15 +308,44 @@ BOOST_AUTO_TEST_CASE(traverse) { graph.addEdge(4, 5, stdcxx::ref()); graph.addEdge(3, 5, stdcxx::ref()); - Traverser traverser = [](unsigned long /*v1*/, unsigned long e, unsigned long /*v2*/) { - return (e == 3 || e == 4 || e == 6) ? TraverseResult::TERMINATE : TraverseResult::CONTINUE; + const Traverser& traverser = [](unsigned long v1, unsigned long e, unsigned long v2) { + if (v1 == 4 && e == 3 && v2 == 1) { + return TraverseResult::TERMINATE_PATH; + } + if (v1 == 4 && e == 4 && v2 == 2) { + return TraverseResult::TERMINATE_PATH; + } + if (v1 == 5 && e == 6 && v2 == 3) { + return TraverseResult::TERMINATE_PATH; + } + return TraverseResult::CONTINUE; }; - std::vector encountered(graph.getVertexCount(), false); + std::vector encountered(graph.getVertexCount()); + std::fill(encountered.begin(), encountered.end(), false); + std::vector encounteredExpected = {false, false, false, false, true, true}; graph.traverse(5, traverser, encountered); - graph.traverse(5, traverser); + BOOST_CHECK_EQUAL_COLLECTIONS(encountered.begin(), encountered.end(), encounteredExpected.begin(), encounteredExpected.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(expected.cbegin(), expected.cend(), encountered.cbegin(), encountered.cend()); + std::fill(encountered.begin(), encountered.end(), false); + const Traverser& traverser2 = [&](unsigned long v1, unsigned long /*e*/, unsigned long v2) { + encountered[v1] = true; + return v2 == 1 || v2 == 2 || v2 == 3 ? TraverseResult::TERMINATE_PATH : TraverseResult::CONTINUE; + }; + graph.traverse(4, traverser2); + // Only vertex 4 and 5 encountered + std::vector encounteredExpected2 = {false, false, false, false, true, true}; + BOOST_CHECK_EQUAL_COLLECTIONS(encountered.begin(), encountered.end(), encounteredExpected2.begin(), encounteredExpected2.end()); + + const Traverser& traverser3 = [&](unsigned long v1, unsigned long /*e*/, unsigned long v2) { + encountered[v1] = true; + return v2 == 0 ? TraverseResult::TERMINATE_TRAVERSER : TraverseResult::CONTINUE; + }; + std::fill(encountered.begin(), encountered.end(), false); + graph.traverse(5, traverser3, encountered); + // Only vertices on first path encountering 0 are encountered + std::vector encounteredExpected3 = {false, true, false, false, true, true}; + BOOST_CHECK_EQUAL_COLLECTIONS(encountered.begin(), encountered.end(), encounteredExpected3.begin(), encounteredExpected3.end()); } BOOST_AUTO_TEST_SUITE_END() From 68f2ad8991a376f00f73605c4113f6a7bc47b22c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LAIGRE?= Date: Mon, 28 Feb 2022 12:30:45 +0100 Subject: [PATCH 02/11] Move test network to NetworkFactory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien LAIGRE --- test/iidm/NetworkFactory.cpp | 197 +++++++++++++++++++++++++++++++++ test/iidm/NetworkFactory.hpp | 2 + test/iidm/NetworkTest.cpp | 204 +---------------------------------- 3 files changed, 204 insertions(+), 199 deletions(-) diff --git a/test/iidm/NetworkFactory.cpp b/test/iidm/NetworkFactory.cpp index ddabbe156..687b7d2b0 100644 --- a/test/iidm/NetworkFactory.cpp +++ b/test/iidm/NetworkFactory.cpp @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include #include @@ -200,6 +202,201 @@ Network createNetworkTest1() { return network; } +Network createSwitchBBKNetwork() { + Network network("test", "test"); + Substation& substation = network.newSubstation() + .setId("S1") + .setName("S1_NAME") + .setCountry(Country::FR) + .setTso("TSO") + .add(); + + VoltageLevel& vl1 = substation.newVoltageLevel() + .setId("VL1") + .setName("VL1_NAME") + .setTopologyKind(TopologyKind::BUS_BREAKER) + .setNominalV(380.0) + .setLowVoltageLimit(340.0) + .setHighVoltageLimit(420.0) + .add(); + + Bus& vl1Bus1 = vl1.getBusBreakerView().newBus() + .setId("VL1_BUS1") + .add(); + + VoltageLevel& vl2 = substation.newVoltageLevel() + .setId("VL2") + .setName("VL2_NAME") + .setTopologyKind(TopologyKind::BUS_BREAKER) + .setNominalV(225.0) + .setLowVoltageLimit(200.0) + .setHighVoltageLimit(260.0) + .add(); + + Bus& vl2Bus1 = vl2.getBusBreakerView().newBus() + .setId("VL2_BUS1") + .add(); + + substation.newTwoWindingsTransformer() + .setId("2WT_VL1_VL2") + .setVoltageLevel1(vl1.getId()) + .setBus1(vl1Bus1.getId()) + .setConnectableBus1(vl1Bus1.getId()) + .setVoltageLevel2(vl2.getId()) + .setBus2(vl2Bus1.getId()) + .setConnectableBus2(vl2Bus1.getId()) + .setR(3.0) + .setX(33.0) + .setG(1.0) + .setB(0.2) + .setRatedU1(2.0) + .setRatedU2(0.4) + .add(); + + Substation& substation2 = network.newSubstation() + .setId("S2") + .setName("S2_NAME") + .setCountry(Country::ES) + .setTso("TSO2") + .add(); + + VoltageLevel& vl3 = substation2.newVoltageLevel() + .setId("VL3") + .setName("VL3_NAME") + .setTopologyKind(TopologyKind::BUS_BREAKER) + .setNominalV(380.0) + .setLowVoltageLimit(340.0) + .setHighVoltageLimit(420.0) + .add(); + + Bus& vl3Bus1 = vl3.getBusBreakerView().newBus() + .setId("VL3_BUS1") + .add(); + + vl3.newLoad() + .setId("LOAD1") + .setBus(vl3Bus1.getId()) + .setConnectableBus(vl3Bus1.getId()) + .setP0(600.0) + .setQ0(200.0) + .add(); + + Bus& vl3Bus2 = vl3.getBusBreakerView().newBus() + .setId("VL3_BUS2") + .add(); + + vl3.newLoad() + .setId("LOAD2") + .setBus(vl3Bus2.getId()) + .setConnectableBus(vl3Bus2.getId()) + .setP0(500.0) + .setQ0(100.0) + .add(); + + Bus& vl3Bus3 = vl3.getBusBreakerView().newBus() + .setId("VL3_BUS3") + .add(); + + vl3.getBusBreakerView().newSwitch() + .setId("SW1") + .setName("SW1_NAME") + .setBus1(vl3Bus1.getId()) + .setBus2(vl3Bus2.getId()) + .add(); + + vl3.getBusBreakerView().newSwitch() + .setId("SW2") + .setName("SW2_NAME") + .setBus1(vl3Bus2.getId()) + .setBus2(vl3Bus3.getId()) + .add(); + + VoltageLevel& vl4 = substation2.newVoltageLevel() + .setId("VL4") + .setName("VL4_NAME") + .setTopologyKind(TopologyKind::BUS_BREAKER) + .setNominalV(225.0) + .setLowVoltageLimit(200.0) + .setHighVoltageLimit(260.0) + .add(); + + Bus& vl4Bus1 = vl4.getBusBreakerView().newBus() + .setId("VL4_BUS1") + .add(); + + network.newLine() + .setId("VL2_VL4") + .setVoltageLevel1(vl2.getId()) + .setBus1(vl2Bus1.getId()) + .setConnectableBus1(vl2Bus1.getId()) + .setVoltageLevel2(vl4.getId()) + .setBus2(vl4Bus1.getId()) + .setConnectableBus2(vl4Bus1.getId()) + .setR(3.0) + .setX(33.0) + .setG1(1.0) + .setB1(0.2) + .setG2(2.0) + .setB2(0.4) + .add(); + + network.newTieLine() + .setId("TL_VL1_VL3") + .setVoltageLevel1(vl1.getId()) + .setBus1(vl1Bus1.getId()) + .setConnectableBus1(vl1Bus1.getId()) + .setVoltageLevel2(vl3.getId()) + .setBus2(vl3Bus1.getId()) + .setConnectableBus2(vl3Bus1.getId()) + .setUcteXnodeCode("UcteXnodeCode") + .newHalfLine1() + .setId("H1_TL_VL1_VL3") + .setR(6.0) + .setX(66.0) + .setG1(0.2) + .setB1(0.4) + .setG2(0.3) + .setB2(0.5) + .add() + .newHalfLine2() + .setId("H2_TL_VL1_VL3") + .setR(7.0) + .setX(77.0) + .setG1(0.6) + .setB1(0.7) + .setG2(0.9) + .setB2(1.2) + .add() + .add(); + + network.newSubstation() + .setId("S3") + .setName("S3_NAME") + .setCountry(Country::FR) + .setTso("TSO") + .add(); + + network.newSubstation() + .setId("S4") + .add(); + + vl1.newDanglingLine() + .setId("DL1") + .setName("DL1_NAME") + .setBus(vl1Bus1.getId()) + .setConnectableBus(vl1Bus1.getId()) + .setB(1.0) + .setG(2.0) + .setP0(3.0) + .setQ0(4.0) + .setR(5.0) + .setX(6.0) + .setUcteXnodeCode("ucteXnodeCodeTest") + .add(); + + return network; +} + Terminal& getTerminalFromNetwork2() { if(network2.getSubstationCount() == 0) { Substation& s = network2.newSubstation() diff --git a/test/iidm/NetworkFactory.hpp b/test/iidm/NetworkFactory.hpp index 3a99a21f3..3ee4bad3b 100644 --- a/test/iidm/NetworkFactory.hpp +++ b/test/iidm/NetworkFactory.hpp @@ -25,6 +25,8 @@ Network createNetwork(); Network createNetworkTest1(); +Network createSwitchBBKNetwork(); + Terminal& getTerminalFromNetwork2(); Network createDanglingLineNetwork(); diff --git a/test/iidm/NetworkTest.cpp b/test/iidm/NetworkTest.cpp index efd74caa3..91465703c 100644 --- a/test/iidm/NetworkTest.cpp +++ b/test/iidm/NetworkTest.cpp @@ -29,206 +29,12 @@ #include #include "NetworkExtension.hpp" +#include "NetworkFactory.hpp" namespace powsybl { namespace iidm { -Network createTestNetwork() { - Network network("test", "test"); - Substation& substation = network.newSubstation() - .setId("S1") - .setName("S1_NAME") - .setCountry(Country::FR) - .setTso("TSO") - .add(); - - VoltageLevel& vl1 = substation.newVoltageLevel() - .setId("VL1") - .setName("VL1_NAME") - .setTopologyKind(TopologyKind::BUS_BREAKER) - .setNominalV(380.0) - .setLowVoltageLimit(340.0) - .setHighVoltageLimit(420.0) - .add(); - - Bus& vl1Bus1 = vl1.getBusBreakerView().newBus() - .setId("VL1_BUS1") - .add(); - - VoltageLevel& vl2 = substation.newVoltageLevel() - .setId("VL2") - .setName("VL2_NAME") - .setTopologyKind(TopologyKind::BUS_BREAKER) - .setNominalV(225.0) - .setLowVoltageLimit(200.0) - .setHighVoltageLimit(260.0) - .add(); - - Bus& vl2Bus1 = vl2.getBusBreakerView().newBus() - .setId("VL2_BUS1") - .add(); - - substation.newTwoWindingsTransformer() - .setId("2WT_VL1_VL2") - .setVoltageLevel1(vl1.getId()) - .setBus1(vl1Bus1.getId()) - .setConnectableBus1(vl1Bus1.getId()) - .setVoltageLevel2(vl2.getId()) - .setBus2(vl2Bus1.getId()) - .setConnectableBus2(vl2Bus1.getId()) - .setR(3.0) - .setX(33.0) - .setG(1.0) - .setB(0.2) - .setRatedU1(2.0) - .setRatedU2(0.4) - .add(); - - Substation& substation2 = network.newSubstation() - .setId("S2") - .setName("S2_NAME") - .setCountry(Country::ES) - .setTso("TSO2") - .add(); - - VoltageLevel& vl3 = substation2.newVoltageLevel() - .setId("VL3") - .setName("VL3_NAME") - .setTopologyKind(TopologyKind::BUS_BREAKER) - .setNominalV(380.0) - .setLowVoltageLimit(340.0) - .setHighVoltageLimit(420.0) - .add(); - - Bus& vl3Bus1 = vl3.getBusBreakerView().newBus() - .setId("VL3_BUS1") - .add(); - - vl3.newLoad() - .setId("LOAD1") - .setBus(vl3Bus1.getId()) - .setConnectableBus(vl3Bus1.getId()) - .setP0(600.0) - .setQ0(200.0) - .add(); - - Bus& vl3Bus2 = vl3.getBusBreakerView().newBus() - .setId("VL3_BUS2") - .add(); - - vl3.newLoad() - .setId("LOAD2") - .setBus(vl3Bus2.getId()) - .setConnectableBus(vl3Bus2.getId()) - .setP0(500.0) - .setQ0(100.0) - .add(); - - Bus& vl3Bus3 = vl3.getBusBreakerView().newBus() - .setId("VL3_BUS3") - .add(); - - vl3.getBusBreakerView().newSwitch() - .setId("SW1") - .setName("SW1_NAME") - .setBus1(vl3Bus1.getId()) - .setBus2(vl3Bus2.getId()) - .add(); - - vl3.getBusBreakerView().newSwitch() - .setId("SW2") - .setName("SW2_NAME") - .setBus1(vl3Bus2.getId()) - .setBus2(vl3Bus3.getId()) - .add(); - - VoltageLevel& vl4 = substation2.newVoltageLevel() - .setId("VL4") - .setName("VL4_NAME") - .setTopologyKind(TopologyKind::BUS_BREAKER) - .setNominalV(225.0) - .setLowVoltageLimit(200.0) - .setHighVoltageLimit(260.0) - .add(); - - Bus& vl4Bus1 = vl4.getBusBreakerView().newBus() - .setId("VL4_BUS1") - .add(); - - network.newLine() - .setId("VL2_VL4") - .setVoltageLevel1(vl2.getId()) - .setBus1(vl2Bus1.getId()) - .setConnectableBus1(vl2Bus1.getId()) - .setVoltageLevel2(vl4.getId()) - .setBus2(vl4Bus1.getId()) - .setConnectableBus2(vl4Bus1.getId()) - .setR(3.0) - .setX(33.0) - .setG1(1.0) - .setB1(0.2) - .setG2(2.0) - .setB2(0.4) - .add(); - - network.newTieLine() - .setId("TL_VL1_VL3") - .setVoltageLevel1(vl1.getId()) - .setBus1(vl1Bus1.getId()) - .setConnectableBus1(vl1Bus1.getId()) - .setVoltageLevel2(vl3.getId()) - .setBus2(vl3Bus1.getId()) - .setConnectableBus2(vl3Bus1.getId()) - .setUcteXnodeCode("UcteXnodeCode") - .newHalfLine1() - .setId("H1_TL_VL1_VL3") - .setR(6.0) - .setX(66.0) - .setG1(0.2) - .setB1(0.4) - .setG2(0.3) - .setB2(0.5) - .add() - .newHalfLine2() - .setId("H2_TL_VL1_VL3") - .setR(7.0) - .setX(77.0) - .setG1(0.6) - .setB1(0.7) - .setG2(0.9) - .setB2(1.2) - .add() - .add(); - - network.newSubstation() - .setId("S3") - .setName("S3_NAME") - .setCountry(Country::FR) - .setTso("TSO") - .add(); - - network.newSubstation() - .setId("S4") - .add(); - - vl1.newDanglingLine() - .setId("DL1") - .setName("DL1_NAME") - .setBus(vl1Bus1.getId()) - .setConnectableBus(vl1Bus1.getId()) - .setB(1.0) - .setG(2.0) - .setP0(3.0) - .setQ0(4.0) - .setR(5.0) - .setX(6.0) - .setUcteXnodeCode("ucteXnodeCodeTest") - .add(); - - return network; -} - Network createTestNodeBreakerNetwork() { Network network2("test2", "test2"); Substation& substation = network2.newSubstation() @@ -370,7 +176,7 @@ BOOST_AUTO_TEST_CASE(fictitious) { } BOOST_AUTO_TEST_CASE(country) { - Network network = createTestNetwork(); + Network network = createSwitchBBKNetwork(); BOOST_CHECK_EQUAL(4, network.getSubstationCount()); BOOST_CHECK_EQUAL(2, network.getCountryCount()); @@ -383,7 +189,7 @@ BOOST_AUTO_TEST_CASE(country) { } BOOST_AUTO_TEST_CASE(getConnectablesTest) { - Network network = createTestNetwork(); + Network network = createSwitchBBKNetwork(); const Network& cNetwork = network; BOOST_CHECK_EQUAL(2, boost::size(network.getConnectables())); @@ -424,7 +230,7 @@ BOOST_AUTO_TEST_CASE(getConnectablesTest) { } BOOST_AUTO_TEST_CASE(branch) { - Network network = createTestNetwork(); + Network network = createSwitchBBKNetwork(); const Network& cNetwork = network; BOOST_CHECK_EQUAL(3, cNetwork.getBranchCount()); @@ -451,7 +257,7 @@ BOOST_AUTO_TEST_CASE(branch) { BOOST_AUTO_TEST_CASE(views) { //BusBreaker - Network network1 = createTestNetwork(); + Network network1 = createSwitchBBKNetwork(); BOOST_CHECK_EQUAL(2, network1.getSwitchCount()); BOOST_CHECK_EQUAL(2, network1.getBusBreakerView().getSwitchCount()); auto switches = network1.getBusBreakerView().getSwitches(); From 9fa2ddc66b100de513f3e71100902fe18315faee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LAIGRE?= Date: Mon, 28 Feb 2022 12:31:09 +0100 Subject: [PATCH 03/11] Improve coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien LAIGRE --- test/iidm/BusBreakerVoltageLevelTest.cpp | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/iidm/BusBreakerVoltageLevelTest.cpp b/test/iidm/BusBreakerVoltageLevelTest.cpp index 75a5350ff..91b43ae46 100644 --- a/test/iidm/BusBreakerVoltageLevelTest.cpp +++ b/test/iidm/BusBreakerVoltageLevelTest.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include @@ -491,6 +493,34 @@ BOOST_AUTO_TEST_CASE(TestRemoveVoltageLevel) { POWSYBL_ASSERT_THROW(network.getVoltageLevel("VL2"), PowsyblException, "Unable to find to the identifiable 'VL2'"); } +BOOST_AUTO_TEST_CASE(expandBusBranch) { + Network network = createSwitchBBKNetwork(); + VoltageLevel& voltageLevel = network.getVoltageLevel("VL3"); + Bus& b1 = network.getBusBreakerView().getBus("VL3_BUS1"); + Bus& b2 = network.getBusBreakerView().getBus("VL3_BUS2"); + Bus& b3 = network.getBusBreakerView().getBus("VL3_BUS3"); + Switch& sw1 = network.getSwitch("SW1"); + + std::vector> buses; + voltage_level::BusBreakerView::Traverser traverser = [&buses, &sw1](const Bus& /*bus1*/, const stdcxx::Reference& sw, const Bus& bus2) { + if (sw && stdcxx::areSame(sw.get(), sw1)) { + return math::TraverseResult::TERMINATE_PATH; + } + buses.emplace_back(std::ref(bus2)); + return math::TraverseResult::CONTINUE; + }; + + voltageLevel.getBusBreakerView().traverse(b1, traverser); + BOOST_CHECK_EQUAL(0, buses.size()); + + voltageLevel.getBusBreakerView().traverse(b2, traverser); + BOOST_CHECK(stdcxx::areSame(b3, (*buses.begin()).get())); + + buses.clear(); + voltageLevel.getBusBreakerView().traverse(b3, traverser); + BOOST_CHECK(stdcxx::areSame(b2, (*buses.begin()).get())); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace iidm From d55b0a1c6e3863d83e8872a7fa6257b4459825c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LAIGRE?= Date: Mon, 28 Feb 2022 12:31:29 +0100 Subject: [PATCH 04/11] Fix sonar smells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien LAIGRE --- include/powsybl/math/UndirectedGraph.hpp | 2 +- include/powsybl/math/UndirectedGraph.hxx | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/include/powsybl/math/UndirectedGraph.hpp b/include/powsybl/math/UndirectedGraph.hpp index 5c9f31ecf..bdef1080d 100644 --- a/include/powsybl/math/UndirectedGraph.hpp +++ b/include/powsybl/math/UndirectedGraph.hpp @@ -94,7 +94,7 @@ class UndirectedGraph { bool traverse(unsigned long v, const Traverser& traverser) const; - bool traverse(stdcxx::const_range& startingVertices, const Traverser& traverser) const; + bool traverse(const stdcxx::const_range& startingVertices, const Traverser& traverser) const; bool traverse(unsigned long v, const Traverser& traverser, std::vector& encountered) const; diff --git a/include/powsybl/math/UndirectedGraph.hxx b/include/powsybl/math/UndirectedGraph.hxx index 9aac1fe13..2ce09c331 100644 --- a/include/powsybl/math/UndirectedGraph.hxx +++ b/include/powsybl/math/UndirectedGraph.hxx @@ -425,14 +425,12 @@ bool UndirectedGraph::traverse(unsigned long v, const Traverser& traverser } template -bool UndirectedGraph::traverse(stdcxx::const_range& startingVertices, const Traverser& traverser) const { +bool UndirectedGraph::traverse(const stdcxx::const_range& startingVertices, const Traverser& traverser) const { std::vector encountered(m_vertices.size(), false); for (unsigned long startingVertex : startingVertices) { - if (!encountered[startingVertex]) { - if (!traverse(startingVertex, traverser, encountered)) { - return false; - } + if (!encountered[startingVertex] && !traverse(startingVertex, traverser, encountered)) { + return false; } } return true; From 2e9213bfff534994fb9b5cb32e54e7b6d0aa7f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LAIGRE?= Date: Tue, 1 Mar 2022 08:45:19 +0100 Subject: [PATCH 05/11] Fix implementation and add TopologyTraverserTest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien LAIGRE --- include/powsybl/iidm/Terminal.hpp | 2 +- .../iidm/VoltageLevelTopologyTraverser.hpp | 6 +- src/iidm/BusBreakerVoltageLevel.cpp | 66 +++--- src/iidm/BusBreakerVoltageLevel.hpp | 5 +- src/iidm/BusTerminal.cpp | 5 +- src/iidm/BusTerminal.hpp | 2 +- src/iidm/NodeBreakerVoltageLevel.cpp | 57 ++--- src/iidm/NodeBreakerVoltageLevel.hpp | 5 +- src/iidm/NodeTerminal.cpp | 4 +- src/iidm/NodeTerminal.hpp | 2 +- test/iidm/CMakeLists.txt | 1 + test/iidm/NetworkFactory.cpp | 200 ++++++++++++++--- test/iidm/NetworkFactory.hpp | 6 +- test/iidm/TerminalTest.cpp | 8 +- test/iidm/TopologyTraverserTest.cpp | 207 ++++++++++++++++++ 15 files changed, 476 insertions(+), 100 deletions(-) create mode 100644 test/iidm/TopologyTraverserTest.cpp diff --git a/include/powsybl/iidm/Terminal.hpp b/include/powsybl/iidm/Terminal.hpp index 082166097..c0ddf7634 100644 --- a/include/powsybl/iidm/Terminal.hpp +++ b/include/powsybl/iidm/Terminal.hpp @@ -88,7 +88,7 @@ class Terminal : public MultiVariantObject { virtual void traverse(voltage_level::TopologyTraverser& traverser) = 0; - virtual void traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) = 0; + virtual bool traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) = 0; protected: // MultiVariantObject void allocateVariantArrayElement(const std::set& indexes, unsigned long sourceIndex) override; diff --git a/include/powsybl/iidm/VoltageLevelTopologyTraverser.hpp b/include/powsybl/iidm/VoltageLevelTopologyTraverser.hpp index 86c990108..e5cdff73a 100644 --- a/include/powsybl/iidm/VoltageLevelTopologyTraverser.hpp +++ b/include/powsybl/iidm/VoltageLevelTopologyTraverser.hpp @@ -8,6 +8,8 @@ #ifndef POWSYBL_IIDM_VOLTAGELEVELTOPOLOGYTRAVERSER_HPP #define POWSYBL_IIDM_VOLTAGELEVELTOPOLOGYTRAVERSER_HPP +#include + namespace powsybl { namespace iidm { @@ -31,9 +33,9 @@ class TopologyTraverser { TopologyTraverser& operator=(TopologyTraverser&&) noexcept = default; - virtual bool traverse(Terminal& terminal, bool connected) = 0; + virtual math::TraverseResult traverse(Terminal& terminal, bool connected) = 0; - virtual bool traverse(Switch& aSwitch) = 0; + virtual math::TraverseResult traverse(Switch& aSwitch) = 0; }; } // namespace voltage_level diff --git a/src/iidm/BusBreakerVoltageLevel.cpp b/src/iidm/BusBreakerVoltageLevel.cpp index 21890d4b2..ca1ac4f84 100644 --- a/src/iidm/BusBreakerVoltageLevel.cpp +++ b/src/iidm/BusBreakerVoltageLevel.cpp @@ -266,6 +266,11 @@ const TopologyKind& BusBreakerVoltageLevel::getTopologyKind() const { return s_topologyKind; } +math::TraverseResult BusBreakerVoltageLevel::getTraverserResult(TerminalSet& visitedTerminals, BusTerminal& terminal, TopologyTraverser& traverser) { + auto pair = visitedTerminals.insert(terminal); + return pair.second ? traverser.traverse(terminal, true) : math::TraverseResult::TERMINATE_PATH; +} + stdcxx::optional BusBreakerVoltageLevel::getVertex(const std::string& busId, bool throwException) const { checkNotEmpty(busId, "bus id is null"); @@ -366,52 +371,57 @@ void BusBreakerVoltageLevel::traverse(BusTerminal& terminal, VoltageLevel::Topol traverse(terminal, traverser, traversedTerminals); } -void BusBreakerVoltageLevel::traverse(BusTerminal& terminal, VoltageLevel::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const { - if (traversedTerminals.find(terminal) != traversedTerminals.end()) { - return; - } - - TerminalSet nextTerminals; - +bool BusBreakerVoltageLevel::traverse(BusTerminal& terminal, VoltageLevel::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const { // check if we are allowed to traverse the terminal itself - if (traverser.traverse(terminal, terminal.isConnected())) { - traversedTerminals.emplace(terminal); + math::TraverseResult termTraverseResult = getTraverserResult(traversedTerminals, terminal, traverser); + if (termTraverseResult == math::TraverseResult::TERMINATE_TRAVERSER) { + return false; + } + if (termTraverseResult == math::TraverseResult::CONTINUE) { + TerminalSet nextTerminals; addNextTerminals(terminal, nextTerminals); - // then check we can traverse terminal connected to same bus + // then check we can traverse terminals connected to same bus unsigned long v = *getVertex(terminal.getConnectableBusId(), true); - ConfiguredBus& bus = m_graph.getVertexObject(v); - for (Terminal& t : bus.getTerminals()) { - if (!stdcxx::areSame(t, terminal) && traverser.traverse(t, t.isConnected())) { + ConfiguredBus& bus = m_graph.getVertexObject(v).get(); + for (BusTerminal& t : bus.getTerminals()) { + math::TraverseResult tTraverseResult = getTraverserResult(traversedTerminals, t, traverser); + if (tTraverseResult == math::TraverseResult::TERMINATE_TRAVERSER) { + return false; + } + if (tTraverseResult == math::TraverseResult::CONTINUE) { addNextTerminals(t, nextTerminals); } } // then go through other buses of the voltage level - m_graph.traverse(v, [this, &traverser, &traversedTerminals, &nextTerminals](unsigned long /*v1*/, unsigned long e, unsigned long v2) { + bool traversalTerminated = !m_graph.traverse(v, [this, &nextTerminals, &traverser, &traversedTerminals](unsigned long /*v1*/, unsigned long e, unsigned long v2) { Switch& aSwitch = m_graph.getEdgeObject(e); - ConfiguredBus& otherBus = m_graph.getVertexObject(v2); - if (traverser.traverse(aSwitch)) { - if (otherBus.getTerminalCount() == 0) { - return math::TraverseResult::CONTINUE; - } - - BusTerminal& otherTerminal = *otherBus.getTerminals().begin(); - if (traverser.traverse(otherTerminal, otherTerminal.isConnected())) { - traversedTerminals.emplace(otherTerminal); - + const stdcxx::range& otherBusTerminals = m_graph.getVertexObject(v2).get().getTerminals(); + math::TraverseResult switchTraverseResult = traverser.traverse(aSwitch); + if (switchTraverseResult == math::TraverseResult::CONTINUE && !otherBusTerminals.empty()) { + BusTerminal& otherTerminal = *otherBusTerminals.begin(); + math::TraverseResult otherTermTraverseResult = getTraverserResult(traversedTerminals, otherTerminal, traverser); + if (otherTermTraverseResult == math::TraverseResult::CONTINUE) { addNextTerminals(otherTerminal, nextTerminals); - return math::TraverseResult::CONTINUE; } + return otherTermTraverseResult; } - return math::TraverseResult::TERMINATE_PATH; + return switchTraverseResult; }); + if (traversalTerminated) { + return false; + } - for (Terminal& t : nextTerminals) { - t.traverse(traverser, traversedTerminals); + for (Terminal& nextTerminal : nextTerminals) { + if (!nextTerminal.traverse(traverser, traversedTerminals)) { + return false; + } } } + + return true; } } // namespace iidm diff --git a/src/iidm/BusBreakerVoltageLevel.hpp b/src/iidm/BusBreakerVoltageLevel.hpp index 1316fa761..b3570d83e 100644 --- a/src/iidm/BusBreakerVoltageLevel.hpp +++ b/src/iidm/BusBreakerVoltageLevel.hpp @@ -68,7 +68,7 @@ class BusBreakerVoltageLevel : public VoltageLevel { void traverse(BusTerminal& terminal, voltage_level::TopologyTraverser& traverser) const; - void traverse(BusTerminal& terminal, voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const; + bool traverse(BusTerminal& terminal, voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const; protected: // MultiVariantObject void allocateVariantArrayElement(const std::set& indexes, unsigned long sourceIndex) override; @@ -91,6 +91,9 @@ class BusBreakerVoltageLevel : public VoltageLevel { void removeTopology() override; +private: + static math::TraverseResult getTraverserResult(TerminalSet& visitedTerminals, BusTerminal& terminal, TopologyTraverser& traverser); + private: void checkTerminal(Terminal& terminal) const; diff --git a/src/iidm/BusTerminal.cpp b/src/iidm/BusTerminal.cpp index b02f725c3..a68545b65 100644 --- a/src/iidm/BusTerminal.cpp +++ b/src/iidm/BusTerminal.cpp @@ -116,11 +116,10 @@ void BusTerminal::traverse(voltage_level::TopologyTraverser& traverser) { dynamic_cast(getVoltageLevel()).traverse(*this, traverser); } -void BusTerminal::traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) { - dynamic_cast(getVoltageLevel()).traverse(*this, traverser, traversedTerminals); +bool BusTerminal::traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) { + return dynamic_cast(getVoltageLevel()).traverse(*this, traverser, traversedTerminals); } - std::ostream& operator<<(std::ostream& stream, const BusTerminal& busTerminal) { stream << stdcxx::simpleClassName(busTerminal) << "[" << busTerminal.getConnectableBusId() << "]"; diff --git a/src/iidm/BusTerminal.hpp b/src/iidm/BusTerminal.hpp index ae19e82db..61ec36b7d 100644 --- a/src/iidm/BusTerminal.hpp +++ b/src/iidm/BusTerminal.hpp @@ -50,7 +50,7 @@ class BusTerminal : public Terminal { void traverse(voltage_level::TopologyTraverser& traverser) override; - void traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) override; + bool traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) override; public: BusTerminal(VoltageLevel& voltageLevel, const std::string& connectableBusId, bool connected); diff --git a/src/iidm/NodeBreakerVoltageLevel.cpp b/src/iidm/NodeBreakerVoltageLevel.cpp index cd66ca205..57bc83dac 100644 --- a/src/iidm/NodeBreakerVoltageLevel.cpp +++ b/src/iidm/NodeBreakerVoltageLevel.cpp @@ -333,6 +333,11 @@ const TopologyKind& NodeBreakerVoltageLevel::getTopologyKind() const { return s_topologyKind; } +math::TraverseResult NodeBreakerVoltageLevel::getTraverseResult(TerminalSet& visitedTerminals, NodeTerminal& terminal, TopologyTraverser& traverser) { + auto pair = visitedTerminals.insert(terminal); + return pair.second ? traverser.traverse(terminal, true) : math::TraverseResult::TERMINATE_PATH; +} + void NodeBreakerVoltageLevel::invalidateCache() { m_variants.get().getCalculatedBusTopology().invalidateCache(); m_variants.get().getCalculatedBusBreakerTopology().invalidateCache(); @@ -395,42 +400,42 @@ void NodeBreakerVoltageLevel::traverse(NodeTerminal& terminal, VoltageLevel::Top traverse(terminal, traverser, traversedTerminals); } -void NodeBreakerVoltageLevel::traverse(NodeTerminal& terminal, VoltageLevel::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const { - if (traversedTerminals.find(terminal) != traversedTerminals.end()) { - return; +bool NodeBreakerVoltageLevel::traverse(NodeTerminal& terminal, VoltageLevel::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const { + const math::TraverseResult& termTraverseResult = getTraverseResult(traversedTerminals, terminal, traverser); + if (termTraverseResult == math::TraverseResult::TERMINATE_TRAVERSER) { + return false; } - - if (traverser.traverse(terminal, true)) { - traversedTerminals.emplace(terminal); - - unsigned long node = terminal.getNode(); + if (termTraverseResult == math::TraverseResult::CONTINUE) { TerminalSet nextTerminals; - addNextTerminals(terminal, nextTerminals); - m_graph.traverse(node, [this, &traverser, &traversedTerminals, &nextTerminals](unsigned long /*v1*/, unsigned long e, unsigned long v2) { - const stdcxx::Reference& aSwitch = m_graph.getEdgeObject(e); - const stdcxx::Reference& otherTerminal = m_graph.getVertexObject(v2); - if (!aSwitch // internal connection case - || traverser.traverse(aSwitch)) { - if (!otherTerminal) { - return math::TraverseResult::CONTINUE; - } - if (traverser.traverse(otherTerminal.get(), true)) { - traversedTerminals.emplace(otherTerminal.get()); - - addNextTerminals(otherTerminal.get(), nextTerminals); - return math::TraverseResult::CONTINUE; + unsigned long node = terminal.getNode(); + bool traverseTerminated = !m_graph.traverse(node, [this, &traverser, &traversedTerminals, &nextTerminals](unsigned long /*v1*/, unsigned long e, unsigned long v2) { + const auto& aSwitch = m_graph.getEdgeObject(e); + const auto& otherTerminal = m_graph.getVertexObject(v2); + const math::TraverseResult& edgeTraverseResult = aSwitch ? traverser.traverse(aSwitch) : math::TraverseResult::CONTINUE; // internal connection case + if (edgeTraverseResult == math::TraverseResult::CONTINUE && otherTerminal) { + math::TraverseResult otherTermTraverseResult = getTraverseResult(traversedTerminals, otherTerminal, traverser); + if (otherTermTraverseResult == math::TraverseResult::CONTINUE) { + addNextTerminals(otherTerminal, nextTerminals); } - return math::TraverseResult::TERMINATE_PATH; + return otherTermTraverseResult; } - return math::TraverseResult::TERMINATE_PATH; + return edgeTraverseResult; }); - for (auto nextTerminal : nextTerminals) { - nextTerminal.get().traverse(traverser, traversedTerminals); + if (traverseTerminated) { + return false; + } + + for (Terminal& nextTerminal : nextTerminals) { + if (!nextTerminal.traverse(traverser, traversedTerminals)) { + return false; + } } } + + return true; } } // namespace iidm diff --git a/src/iidm/NodeBreakerVoltageLevel.hpp b/src/iidm/NodeBreakerVoltageLevel.hpp index 264f31420..9f5b57f97 100644 --- a/src/iidm/NodeBreakerVoltageLevel.hpp +++ b/src/iidm/NodeBreakerVoltageLevel.hpp @@ -66,7 +66,7 @@ class NodeBreakerVoltageLevel : public VoltageLevel { void traverse(NodeTerminal& terminal, VoltageLevel::TopologyTraverser& traverser) const; - void traverse(NodeTerminal& terminal, VoltageLevel::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const; + bool traverse(NodeTerminal& terminal, VoltageLevel::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const; public: NodeBreakerVoltageLevel(const std::string& id, const std::string& name, bool fictitious, const stdcxx::Reference& substation, @@ -97,6 +97,9 @@ class NodeBreakerVoltageLevel : public VoltageLevel { private: // VoltageLevel void removeTopology() override; +private: + static math::TraverseResult getTraverseResult(TerminalSet& visitedTerminals, NodeTerminal& terminal, TopologyTraverser& traverser); + private: void checkTerminal(Terminal& terminal) const; diff --git a/src/iidm/NodeTerminal.cpp b/src/iidm/NodeTerminal.cpp index ae3105508..9247a13ff 100644 --- a/src/iidm/NodeTerminal.cpp +++ b/src/iidm/NodeTerminal.cpp @@ -139,8 +139,8 @@ void NodeTerminal::traverse(voltage_level::TopologyTraverser& traverser) { dynamic_cast(getVoltageLevel()).traverse(*this, traverser); } -void NodeTerminal::traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) { - dynamic_cast(getVoltageLevel()).traverse(*this, traverser, traversedTerminals); +bool NodeTerminal::traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) { + return dynamic_cast(getVoltageLevel()).traverse(*this, traverser, traversedTerminals); } } // namespace iidm diff --git a/src/iidm/NodeTerminal.hpp b/src/iidm/NodeTerminal.hpp index be8c1a93c..faf2d94ec 100644 --- a/src/iidm/NodeTerminal.hpp +++ b/src/iidm/NodeTerminal.hpp @@ -48,7 +48,7 @@ class NodeTerminal : public Terminal { void traverse(voltage_level::TopologyTraverser& traverser) override; - void traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) override; + bool traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) override; public: NodeTerminal(VoltageLevel& voltageLevel, unsigned long node); diff --git a/test/iidm/CMakeLists.txt b/test/iidm/CMakeLists.txt index 8bc4dfa40..64ea86448 100644 --- a/test/iidm/CMakeLists.txt +++ b/test/iidm/CMakeLists.txt @@ -43,6 +43,7 @@ set(UNIT_TEST_SOURCES SubstationTest.cpp TerminalTest.cpp TopologyLevelTest.cpp + TopologyTraverserTest.cpp ThreeWindingsTransformerTest.cpp TieLineTest.cpp TwoWindingsTransformerTest.cpp diff --git a/test/iidm/NetworkFactory.cpp b/test/iidm/NetworkFactory.cpp index 687b7d2b0..ba61dc431 100644 --- a/test/iidm/NetworkFactory.cpp +++ b/test/iidm/NetworkFactory.cpp @@ -202,6 +202,150 @@ Network createNetworkTest1() { return network; } +Network createMixedNodeBreakerBusBreakerNetwork() { + Network network = createNodeBreakerNetwork(); + Substation& s3 = network.newSubstation() + .setId("S3") + .setCountry(Country::FR) + .add(); + VoltageLevel& vl3 = s3.newVoltageLevel() + .setId("VL3") + .setNominalV(400.0) + .setTopologyKind(TopologyKind::BUS_BREAKER) + .add(); + vl3.getBusBreakerView().newBus() + .setId("B1") + .add(); + vl3.newLoad() + .setId("LD2") + .setConnectableBus("B1") + .setBus("B1") + .setP0(1.0) + .setQ0(1.0) + .add(); + network.getVoltageLevel("VL2").getNodeBreakerView().newBreaker() + .setId("BR5") + .setNode1(0) + .setNode2(4) + .setOpen(false) + .add(); + network.newLine() + .setId("L2") + .setVoltageLevel1("VL2") + .setNode1(4) + .setVoltageLevel2("VL3") + .setConnectableBus2("B1") + .setBus2("B1") + .setR(1.0) + .setX(1.0) + .setG1(0.0) + .setB1(0.0) + .setG2(0.0) + .setB2(0.0) + .add(); + return network; +} + +Network createNodeBreakerNetwork() { + Network network("test", "test"); + Substation& s1 = network.newSubstation() + .setId("S1") + .setCountry(Country::FR) + .add(); + VoltageLevel& vl1 = s1.newVoltageLevel() + .setId("VL1") + .setNominalV(400.0) + .setTopologyKind(TopologyKind::NODE_BREAKER) + .add(); + vl1.getNodeBreakerView().newBusbarSection() + .setId("BBS1") + .setNode(0) + .add(); + vl1.newGenerator() + .setId("G") + .setNode(4) + .setMaxP(100.0) + .setMinP(50.0) + .setTargetP(100.0) + .setTargetV(400.0) + .setVoltageRegulatorOn(true) + .add(); + vl1.getNodeBreakerView().newInternalConnection() + .setNode1(1) + .setNode2(4) + .add(); + vl1.getNodeBreakerView().newDisconnector() + .setId("BR1") + .setNode1(0) + .setNode2(1) + .setOpen(false) + .add(); + vl1.getNodeBreakerView().newDisconnector() + .setId("D1") + .setNode1(0) + .setNode2(2) + .setOpen(false) + .add(); + vl1.getNodeBreakerView().newBreaker() + .setId("BR2") + .setNode1(2) + .setNode2(3) + .setOpen(false) + .add(); + + Substation& s2 = network.newSubstation() + .setId("S2") + .setCountry(Country::FR) + .add(); + VoltageLevel& vl2 = s2.newVoltageLevel() + .setId("VL2") + .setNominalV(400.0) + .setTopologyKind(TopologyKind::NODE_BREAKER) + .add(); + vl2.getNodeBreakerView().newBusbarSection() + .setId("BBS2") + .setNode(0) + .add(); + vl2.newLoad() + .setId("LD") + .setNode(1) + .setP0(1) + .setQ0(1) + .add(); + vl2.getNodeBreakerView().newDisconnector() + .setId("BR3") + .setNode1(0) + .setNode2(1) + .setOpen(false) + .add(); + vl2.getNodeBreakerView().newDisconnector() + .setId("D2") + .setNode1(0) + .setNode2(2) + .setOpen(false) + .add(); + vl2.getNodeBreakerView().newBreaker() + .setId("BR4") + .setNode1(2) + .setNode2(3) + .setOpen(false) + .add(); + network.newLine() + .setId("L1") + .setVoltageLevel1("VL1") + .setNode1(3) + .setVoltageLevel2("VL2") + .setNode2(3) + .setR(1.0) + .setX(1.0) + .setG1(0.0) + .setB1(0.0) + .setG2(0.0) + .setB2(0.0) + .add(); + return network; +} + Network createSwitchBBKNetwork() { Network network("test", "test"); Substation& substation = network.newSubstation() @@ -397,34 +541,6 @@ Network createSwitchBBKNetwork() { return network; } -Terminal& getTerminalFromNetwork2() { - if(network2.getSubstationCount() == 0) { - Substation& s = network2.newSubstation() - .setId("S") - .setCountry(Country::FR) - .add(); - - VoltageLevel& vl = s.newVoltageLevel() - .setId("VL") - .setTopologyKind(TopologyKind::NODE_BREAKER) - .setNominalV(400.0) - .setLowVoltageLimit(380.0) - .setHighVoltageLimit(420.0) - .add(); - - vl.newLoad() - .setId("LOAD1") - .setNode(0) - .setName("LOAD1_NAME") - .setLoadType(LoadType::UNDEFINED) - .setP0(50.0) - .setQ0(40.0) - .add(); - } - - return network2.getLoad("LOAD1").getTerminal(); -} - Network createComponentsTestNetworkBB() { Network network("testBB", "testBB"); Substation& substation = network.newSubstation() @@ -1173,6 +1289,34 @@ Network createComponentsTestNetworkNB() { return network; } +Terminal& getTerminalFromNetwork2() { + if(network2.getSubstationCount() == 0) { + Substation& s = network2.newSubstation() + .setId("S") + .setCountry(Country::FR) + .add(); + + VoltageLevel& vl = s.newVoltageLevel() + .setId("VL") + .setTopologyKind(TopologyKind::NODE_BREAKER) + .setNominalV(400.0) + .setLowVoltageLimit(380.0) + .setHighVoltageLimit(420.0) + .add(); + + vl.newLoad() + .setId("LOAD1") + .setNode(0) + .setName("LOAD1_NAME") + .setLoadType(LoadType::UNDEFINED) + .setP0(50.0) + .setQ0(40.0) + .add(); + } + + return network2.getLoad("LOAD1").getTerminal(); +} + } // namespace iidm } // namespace powsybl diff --git a/test/iidm/NetworkFactory.hpp b/test/iidm/NetworkFactory.hpp index 3ee4bad3b..749aaecdf 100644 --- a/test/iidm/NetworkFactory.hpp +++ b/test/iidm/NetworkFactory.hpp @@ -21,16 +21,18 @@ Network createComponentsTestNetworkNB(); Network createHvdcConverterStationTestNetwork(); +Network createMixedNodeBreakerBusBreakerNetwork(); + Network createNetwork(); Network createNetworkTest1(); +Network createNodeBreakerNetwork(); + Network createSwitchBBKNetwork(); Terminal& getTerminalFromNetwork2(); -Network createDanglingLineNetwork(); - } // namespace iidm } // namespace powsybl diff --git a/test/iidm/TerminalTest.cpp b/test/iidm/TerminalTest.cpp index f26ef0996..e46d5848a 100644 --- a/test/iidm/TerminalTest.cpp +++ b/test/iidm/TerminalTest.cpp @@ -22,14 +22,14 @@ BOOST_AUTO_TEST_SUITE(TerminalTestSuite) class CustomTopologyTraverser : public VoltageLevel::TopologyTraverser { public: // VoltageLevel::TopologyTraverser - bool traverse(Terminal& terminal, bool /*connected*/) override { + math::TraverseResult traverse(Terminal& terminal, bool /*connected*/) override { m_traversedConnectables.insert(terminal.getConnectable().get().getId()); - return m_traverseTerminals; + return m_traverseTerminals ? math::TraverseResult::CONTINUE : math::TraverseResult::TERMINATE_PATH; } - bool traverse(Switch& aSwitch) override { + math::TraverseResult traverse(Switch& aSwitch) override { m_traversedSwitches.insert(aSwitch.getId()); - return m_traverseSwitches; + return m_traverseSwitches ? math::TraverseResult::CONTINUE : math::TraverseResult::TERMINATE_PATH; } public: diff --git a/test/iidm/TopologyTraverserTest.cpp b/test/iidm/TopologyTraverserTest.cpp new file mode 100644 index 000000000..071f991b8 --- /dev/null +++ b/test/iidm/TopologyTraverserTest.cpp @@ -0,0 +1,207 @@ +/** + * Copyright (c) 2022, 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/. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "NetworkFactory.hpp" + +namespace std { + +std::ostream& operator<<(std::ostream& stream, const std::pair& ip) { + stream << ip.first << " " << ip.second; + return stream; +} + +} // namespace std + +namespace powsybl { + +namespace iidm { + +using IdPos = std::pair; + +using IdPosSet = std::set>; + +class CustomTopologyTraverser : public voltage_level::TopologyTraverser { +public: + using SwitchTest = std::function; + + using TerminalTest = std::function; + +public: // voltage_level::TopologyTraverser + math::TraverseResult traverse(Terminal& terminal, bool /*connected*/) override { + auto pair = m_visited.insert(terminal); + if (!pair.second) { + BOOST_FAIL("Traversing an already visited terminal"); + } + return m_terminalTest(terminal); + } + + math::TraverseResult traverse(Switch& aSwitch) override { + return m_switchTest(aSwitch); + } + +public: + CustomTopologyTraverser(TerminalSet& visited, const SwitchTest& switchTest, const TerminalTest& terminalTest) : + m_visited(visited), + m_switchTest(switchTest), + m_terminalTest(terminalTest) { + } + +private: + TerminalSet& m_visited; + + SwitchTest m_switchTest; + + TerminalTest m_terminalTest; +}; + +static int indexOfTerminal(const Terminal& terminal) { + const auto& allTerminals = terminal.getConnectable().get().getTerminals(); + auto it = std::find_if(allTerminals.begin(), allTerminals.end(), [&terminal](const std::reference_wrapper& term) { + return stdcxx::areSame(terminal, term.get()); + }); + return it != allTerminals.end() ? it - allTerminals.begin() : -1; +} + +IdPosSet getVisitedList(Terminal& start, const CustomTopologyTraverser::SwitchTest& switchTest, const CustomTopologyTraverser::TerminalTest& terminalTest) { + TerminalSet visited; + + CustomTopologyTraverser traverser(visited, switchTest, terminalTest); + start.traverse(traverser); + + IdPosSet visitedInfos; + std::transform(visited.begin(), visited.end(), std::inserter(visitedInfos,visitedInfos.begin()), [](const std::reference_wrapper& terminal) { + return std::make_pair(terminal.get().getConnectable().get().getId(), indexOfTerminal(terminal.get())); + }); + + return visitedInfos; +} + +IdPosSet getVisitedList(Terminal& start, const CustomTopologyTraverser::SwitchTest& switchTest) { + const CustomTopologyTraverser::TerminalTest& terminalTest = [](Terminal& /*Terminal*/) { + return math::TraverseResult::CONTINUE; + }; + return getVisitedList(start, switchTest, terminalTest); +} + +IdPosSet getVisitedList(Terminal& start) { + const CustomTopologyTraverser::SwitchTest& switchTest = [](Switch& /*sw*/) { + return math::TraverseResult::CONTINUE; + }; + return getVisitedList(start, switchTest); +} + +BOOST_AUTO_TEST_SUITE(TopologyTraverserTestSuite) + +BOOST_AUTO_TEST_CASE(test1) { + Network network = createNodeBreakerNetwork(); + Terminal& start = network.getGenerator("G").getTerminal(); + const auto& res = getVisitedList(start); + + IdPosSet expected = {{"G", 0}, {"BBS1", 0}, {"L1", 0}, {"L1", 1}, {"BBS2", 0}, {"LD", 0}}; + + BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), res.begin(), res.end()); +} + +BOOST_AUTO_TEST_CASE(test2) { + Network network = createNodeBreakerNetwork(); + Terminal& start = network.getVoltageLevel("VL1").getNodeBreakerView().getBusbarSection("BBS1").get().getTerminal(); + const auto& res = getVisitedList(start, [](Switch& sw) { + return (!sw.isOpen() && sw.getKind() != SwitchKind::BREAKER) ? math::TraverseResult::CONTINUE : math::TraverseResult::TERMINATE_PATH; + }); + + IdPosSet expected = { {"BBS1", 0}, {"G", 0} }; + + BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), res.begin(), res.end()); +} + +BOOST_AUTO_TEST_CASE(test3) { + Network network = createMixedNodeBreakerBusBreakerNetwork(); + Terminal& start = network.getGenerator("G").getTerminal(); + const auto& visited1 = getVisitedList(start); + IdPosSet expected1 = { {"BBS1", 0}, {"G", 0}, {"L1", 0}, + {"L1", 1}, {"BBS2", 0}, {"LD", 0}, {"L2", 0}, + {"L2", 1}, {"LD2", 0} }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected1.begin(), expected1.end(), visited1.begin(), visited1.end()); + + const auto& visited2 = getVisitedList(start, [](Switch& /*sw*/) { return math::TraverseResult::CONTINUE; }, [](Terminal& terminal) { + return terminal.getConnectable().get().getId() == "L2" ? math::TraverseResult::TERMINATE_PATH : math::TraverseResult::CONTINUE; + }); + IdPosSet expected2 = { {"G", 0}, {"BBS1", 0}, {"L1", 0}, {"L1", 1}, + {"BBS2", 0}, {"LD", 0}, {"L2", 0} }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected2.begin(), expected2.end(), visited2.begin(), visited2.end()); + + const auto& visited3 = getVisitedList(network.getLoad("LD2").getTerminal(), [](Switch& /*sw*/) { return math::TraverseResult::CONTINUE; }, [](Terminal& terminal) { + return terminal.getConnectable().get().getId() == "L2" ? math::TraverseResult::TERMINATE_PATH : math::TraverseResult::CONTINUE; + }); + IdPosSet expected3 = { {"LD2", 0}, {"L2", 1} }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected3.begin(), expected3.end(), visited3.begin(), visited3.end()); +} + +BOOST_AUTO_TEST_CASE(test4) { + Network network = powsybl::network::EurostagFactory::createTutorial1Network(); + Terminal& start = network.getGenerator("GEN").getTerminal(); + const auto& res = getVisitedList(start); + + IdPosSet expected = { {"GEN", 0}, {"NGEN_NHV1", 0}, {"NGEN_NHV1", 1}, + {"NHV1_NHV2_1", 0}, {"NHV1_NHV2_2", 0}, {"NHV1_NHV2_1", 1}, + {"NHV1_NHV2_2", 1}, {"NHV2_NLOAD", 0}, {"NHV2_NLOAD", 1}, {"LOAD", 0} }; + + BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), res.begin(), res.end()); +} + +BOOST_AUTO_TEST_CASE(test5) { + Network network = powsybl::network::EurostagFactory::createTutorial1Network(); + // Duplicate 2wt to go from VLGEN to VLHV1 even if traverser stops at one of them + TwoWindingsTransformer& transformer = network.getTwoWindingsTransformer("NGEN_NHV1"); + TwoWindingsTransformer& duplicatedTransformer = network.getSubstation("P1") + .newTwoWindingsTransformer() + .setId("duplicate") + .setVoltageLevel1("VLGEN").setBus1("NGEN") + .setVoltageLevel2("VLHV1").setBus2("NHV1") + .setRatedU1(transformer.getRatedU1()) + .setRatedU2(transformer.getRatedU2()) + .setR(transformer.getR()) + .setX(transformer.getX()) + .setG(transformer.getG()) + .setB(transformer.getB()) + .add(); + + Terminal& start = network.getGenerator("GEN").getTerminal(); + const auto& res = getVisitedList(start, [](Switch& /*sw*/) { return math::TraverseResult::CONTINUE; }, [&duplicatedTransformer](Terminal& terminal) { + return (stdcxx::areSame(terminal.getConnectable().get(), duplicatedTransformer) && terminal.getVoltageLevel().getId() == "VLGEN") ? math::TraverseResult::TERMINATE_PATH : math::TraverseResult::CONTINUE; + }); + IdPosSet expected = { {"GEN", 0}, {"NGEN_NHV1", 0}, {"duplicate", 0}, {"NGEN_NHV1", 1}, + {"NHV1_NHV2_1", 0}, {"NHV1_NHV2_2", 0}, {"duplicate", 1}, {"NHV1_NHV2_1", 1}, + {"NHV1_NHV2_2", 1}, {"NHV2_NLOAD", 0}, {"NHV2_NLOAD", 1}, {"LOAD", 0} }; + + BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), res.begin(), res.end()); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace iidm + +} // namespace powsybl From 1b4f95cc07834588041be65f3c9aafdb233f7a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LAIGRE?= Date: Thu, 31 Mar 2022 15:29:22 +0200 Subject: [PATCH 06/11] Add Terminal::TopologyTraverser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien LAIGRE --- include/powsybl/iidm/Terminal.hpp | 8 +++++--- ...gyTraverser.hpp => TerminalTopologyTraverser.hpp} | 12 ++++++------ include/powsybl/iidm/VoltageLevel.hpp | 3 --- include/powsybl/iidm/VoltageLevelViews.hpp | 10 +++++----- src/iidm/BusBreakerVoltageLevel.cpp | 6 +++--- src/iidm/BusBreakerVoltageLevel.hpp | 6 +++--- src/iidm/BusBreakerVoltageLevelViews.cpp | 2 +- src/iidm/BusBreakerVoltageLevelViews.hpp | 2 +- src/iidm/BusTerminal.cpp | 4 ++-- src/iidm/BusTerminal.hpp | 4 ++-- src/iidm/NodeBreakerVoltageLevel.cpp | 6 +++--- src/iidm/NodeBreakerVoltageLevel.hpp | 6 +++--- src/iidm/NodeBreakerVoltageLevelViews.cpp | 6 +++--- src/iidm/NodeBreakerVoltageLevelViews.hpp | 6 +++--- src/iidm/NodeTerminal.cpp | 4 ++-- src/iidm/NodeTerminal.hpp | 4 ++-- src/iidm/util/Networks.cpp | 2 +- src/iidm/util/NodeBreakerTopology.cpp | 2 +- test/iidm/BusBreakerVoltageLevelTest.cpp | 2 +- test/iidm/NodeBreakerVoltageLevelTest.cpp | 2 +- test/iidm/TerminalTest.cpp | 2 +- test/iidm/TopologyTraverserTest.cpp | 2 +- 22 files changed, 50 insertions(+), 51 deletions(-) rename include/powsybl/iidm/{VoltageLevelTopologyTraverser.hpp => TerminalTopologyTraverser.hpp} (76%) diff --git a/include/powsybl/iidm/Terminal.hpp b/include/powsybl/iidm/Terminal.hpp index c0ddf7634..0ddddecc2 100644 --- a/include/powsybl/iidm/Terminal.hpp +++ b/include/powsybl/iidm/Terminal.hpp @@ -13,9 +13,9 @@ #include #include +#include #include #include -#include #include namespace powsybl { @@ -34,6 +34,8 @@ class Terminal : public MultiVariantObject { using NodeBreakerView = terminal::NodeBreakerView; + using TopologyTraverser = terminal::TopologyTraverser; + public: template ::value>::type> static bool isInstanceOf(const Terminal& terminal); @@ -86,9 +88,9 @@ class Terminal : public MultiVariantObject { Terminal& setQ(double q); - virtual void traverse(voltage_level::TopologyTraverser& traverser) = 0; + virtual void traverse(TopologyTraverser& traverser) = 0; - virtual bool traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) = 0; + virtual bool traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) = 0; protected: // MultiVariantObject void allocateVariantArrayElement(const std::set& indexes, unsigned long sourceIndex) override; diff --git a/include/powsybl/iidm/VoltageLevelTopologyTraverser.hpp b/include/powsybl/iidm/TerminalTopologyTraverser.hpp similarity index 76% rename from include/powsybl/iidm/VoltageLevelTopologyTraverser.hpp rename to include/powsybl/iidm/TerminalTopologyTraverser.hpp index e5cdff73a..c2a20f8b6 100644 --- a/include/powsybl/iidm/VoltageLevelTopologyTraverser.hpp +++ b/include/powsybl/iidm/TerminalTopologyTraverser.hpp @@ -1,12 +1,12 @@ /** - * Copyright (c) 2021, RTE (http://www.rte-france.com) + * Copyright (c) 2022, 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/. */ -#ifndef POWSYBL_IIDM_VOLTAGELEVELTOPOLOGYTRAVERSER_HPP -#define POWSYBL_IIDM_VOLTAGELEVELTOPOLOGYTRAVERSER_HPP +#ifndef POWSYBL_IIDM_TERMINALTOPOLOGYTRAVERSER_HPP +#define POWSYBL_IIDM_TERMINALTOPOLOGYTRAVERSER_HPP #include @@ -17,7 +17,7 @@ namespace iidm { class Switch; class Terminal; -namespace voltage_level { +namespace terminal { class TopologyTraverser { public: @@ -38,10 +38,10 @@ class TopologyTraverser { virtual math::TraverseResult traverse(Switch& aSwitch) = 0; }; -} // namespace voltage_level +} // namespace terminal } // namespace iidm } // namespace powsybl -#endif // POWSYBL_IIDM_VOLTAGELEVELTOPOLOGYTRAVERSER_HPP +#endif // POWSYBL_IIDM_TERMINALTOPOLOGYTRAVERSER_HPP diff --git a/include/powsybl/iidm/VoltageLevel.hpp b/include/powsybl/iidm/VoltageLevel.hpp index 21af8b0a2..f4d662f43 100644 --- a/include/powsybl/iidm/VoltageLevel.hpp +++ b/include/powsybl/iidm/VoltageLevel.hpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -55,8 +54,6 @@ class VoltageLevel : public Container { using NodeBreakerView = voltage_level::NodeBreakerView; - using TopologyTraverser = voltage_level::TopologyTraverser; - public: // Identifiable const Network& getNetwork() const override; diff --git a/include/powsybl/iidm/VoltageLevelViews.hpp b/include/powsybl/iidm/VoltageLevelViews.hpp index fee2bd382..3e3fe19d9 100644 --- a/include/powsybl/iidm/VoltageLevelViews.hpp +++ b/include/powsybl/iidm/VoltageLevelViews.hpp @@ -37,7 +37,7 @@ class BusBreakerView { public: using SwitchAdder = bus_breaker_view::SwitchAdder; - using Traverser = std::function& sw, const Bus& bus2)>; + using TopologyTraverser = std::function& sw, const Bus& bus2)>; public: virtual ~BusBreakerView() noexcept = default; @@ -80,7 +80,7 @@ class BusBreakerView { virtual void removeSwitch(const std::string& switchId) = 0; - virtual void traverse(const Bus& bus, Traverser& traverser) = 0; + virtual void traverse(const Bus& bus, TopologyTraverser& traverser) = 0; }; class BusView { @@ -108,7 +108,7 @@ class NodeBreakerView { using SwitchAdder = node_breaker_view::SwitchAdder; - using Traverser = std::function& sw, unsigned long node2)>; + using TopologyTraverser = std::function& sw, unsigned long node2)>; public: virtual ~NodeBreakerView() noexcept = default; @@ -177,9 +177,9 @@ class NodeBreakerView { virtual void removeSwitch(const std::string& switchId) = 0; - virtual void traverse(unsigned long node, const Traverser& traverser) const = 0; + virtual void traverse(unsigned long node, const TopologyTraverser& traverser) const = 0; - virtual void traverse(stdcxx::const_range& nodes, const Traverser& traverser) const = 0; + virtual void traverse(stdcxx::const_range& nodes, const TopologyTraverser& traverser) const = 0; }; } // namespace voltage_level diff --git a/src/iidm/BusBreakerVoltageLevel.cpp b/src/iidm/BusBreakerVoltageLevel.cpp index ca1ac4f84..ba508de75 100644 --- a/src/iidm/BusBreakerVoltageLevel.cpp +++ b/src/iidm/BusBreakerVoltageLevel.cpp @@ -266,7 +266,7 @@ const TopologyKind& BusBreakerVoltageLevel::getTopologyKind() const { return s_topologyKind; } -math::TraverseResult BusBreakerVoltageLevel::getTraverserResult(TerminalSet& visitedTerminals, BusTerminal& terminal, TopologyTraverser& traverser) { +math::TraverseResult BusBreakerVoltageLevel::getTraverserResult(TerminalSet& visitedTerminals, BusTerminal& terminal, Terminal::TopologyTraverser& traverser) { auto pair = visitedTerminals.insert(terminal); return pair.second ? traverser.traverse(terminal, true) : math::TraverseResult::TERMINATE_PATH; } @@ -366,12 +366,12 @@ void BusBreakerVoltageLevel::removeTopology() { removeAllBuses(); } -void BusBreakerVoltageLevel::traverse(BusTerminal& terminal, VoltageLevel::TopologyTraverser& traverser) const { +void BusBreakerVoltageLevel::traverse(BusTerminal& terminal, Terminal::TopologyTraverser& traverser) const { TerminalSet traversedTerminals; traverse(terminal, traverser, traversedTerminals); } -bool BusBreakerVoltageLevel::traverse(BusTerminal& terminal, VoltageLevel::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const { +bool BusBreakerVoltageLevel::traverse(BusTerminal& terminal, Terminal::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const { // check if we are allowed to traverse the terminal itself math::TraverseResult termTraverseResult = getTraverserResult(traversedTerminals, terminal, traverser); if (termTraverseResult == math::TraverseResult::TERMINATE_TRAVERSER) { diff --git a/src/iidm/BusBreakerVoltageLevel.hpp b/src/iidm/BusBreakerVoltageLevel.hpp index b3570d83e..289a5e74b 100644 --- a/src/iidm/BusBreakerVoltageLevel.hpp +++ b/src/iidm/BusBreakerVoltageLevel.hpp @@ -66,9 +66,9 @@ class BusBreakerVoltageLevel : public VoltageLevel { Switch& addSwitch(std::unique_ptr&& ptrSwitch, const std::string& busId1, const std::string& busId2); - void traverse(BusTerminal& terminal, voltage_level::TopologyTraverser& traverser) const; + void traverse(BusTerminal& terminal, Terminal::TopologyTraverser& traverser) const; - bool traverse(BusTerminal& terminal, voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const; + bool traverse(BusTerminal& terminal, Terminal::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const; protected: // MultiVariantObject void allocateVariantArrayElement(const std::set& indexes, unsigned long sourceIndex) override; @@ -92,7 +92,7 @@ class BusBreakerVoltageLevel : public VoltageLevel { void removeTopology() override; private: - static math::TraverseResult getTraverserResult(TerminalSet& visitedTerminals, BusTerminal& terminal, TopologyTraverser& traverser); + static math::TraverseResult getTraverserResult(TerminalSet& visitedTerminals, BusTerminal& terminal, Terminal::TopologyTraverser& traverser); private: void checkTerminal(Terminal& terminal) const; diff --git a/src/iidm/BusBreakerVoltageLevelViews.cpp b/src/iidm/BusBreakerVoltageLevelViews.cpp index 996378190..78f8c5cab 100644 --- a/src/iidm/BusBreakerVoltageLevelViews.cpp +++ b/src/iidm/BusBreakerVoltageLevelViews.cpp @@ -125,7 +125,7 @@ void BusBreakerViewImpl::removeSwitch(const std::string& switchId) { m_voltageLevel.removeSwitch(switchId); } -void BusBreakerViewImpl::traverse(const Bus& bus, Traverser& traverser) { +void BusBreakerViewImpl::traverse(const Bus& bus, TopologyTraverser& traverser) { math::Traverser graphTraverser = [this, &traverser](unsigned long v1, unsigned long e, unsigned long v2) { const auto& graph = m_voltageLevel.getGraph(); return traverser(graph.getVertexObject(v1), graph.getEdgeObject(e), graph.getVertexObject(v2)); diff --git a/src/iidm/BusBreakerVoltageLevelViews.hpp b/src/iidm/BusBreakerVoltageLevelViews.hpp index 0a9a82b9d..034a93383 100644 --- a/src/iidm/BusBreakerVoltageLevelViews.hpp +++ b/src/iidm/BusBreakerVoltageLevelViews.hpp @@ -59,7 +59,7 @@ class BusBreakerViewImpl : public voltage_level::BusBreakerView { void removeSwitch(const std::string& switchId) override; - void traverse(const Bus& bus, Traverser& traverser) override; + void traverse(const Bus& bus, TopologyTraverser& traverser) override; public: explicit BusBreakerViewImpl(BusBreakerVoltageLevel& voltageLevel); diff --git a/src/iidm/BusTerminal.cpp b/src/iidm/BusTerminal.cpp index a68545b65..da246b37b 100644 --- a/src/iidm/BusTerminal.cpp +++ b/src/iidm/BusTerminal.cpp @@ -112,11 +112,11 @@ BusTerminal& BusTerminal::setConnected(bool connected) { return *this; } -void BusTerminal::traverse(voltage_level::TopologyTraverser& traverser) { +void BusTerminal::traverse(TopologyTraverser& traverser) { dynamic_cast(getVoltageLevel()).traverse(*this, traverser); } -bool BusTerminal::traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) { +bool BusTerminal::traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) { return dynamic_cast(getVoltageLevel()).traverse(*this, traverser, traversedTerminals); } diff --git a/src/iidm/BusTerminal.hpp b/src/iidm/BusTerminal.hpp index 61ec36b7d..f02d4a0b6 100644 --- a/src/iidm/BusTerminal.hpp +++ b/src/iidm/BusTerminal.hpp @@ -48,9 +48,9 @@ class BusTerminal : public Terminal { bool isConnected() const override; - void traverse(voltage_level::TopologyTraverser& traverser) override; + void traverse(TopologyTraverser& traverser) override; - bool traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) override; + bool traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) override; public: BusTerminal(VoltageLevel& voltageLevel, const std::string& connectableBusId, bool connected); diff --git a/src/iidm/NodeBreakerVoltageLevel.cpp b/src/iidm/NodeBreakerVoltageLevel.cpp index 57bc83dac..2edb32497 100644 --- a/src/iidm/NodeBreakerVoltageLevel.cpp +++ b/src/iidm/NodeBreakerVoltageLevel.cpp @@ -333,7 +333,7 @@ const TopologyKind& NodeBreakerVoltageLevel::getTopologyKind() const { return s_topologyKind; } -math::TraverseResult NodeBreakerVoltageLevel::getTraverseResult(TerminalSet& visitedTerminals, NodeTerminal& terminal, TopologyTraverser& traverser) { +math::TraverseResult NodeBreakerVoltageLevel::getTraverseResult(TerminalSet& visitedTerminals, NodeTerminal& terminal, Terminal::TopologyTraverser& traverser) { auto pair = visitedTerminals.insert(terminal); return pair.second ? traverser.traverse(terminal, true) : math::TraverseResult::TERMINATE_PATH; } @@ -395,12 +395,12 @@ void NodeBreakerVoltageLevel::removeTopology() { m_switches.clear(); } -void NodeBreakerVoltageLevel::traverse(NodeTerminal& terminal, VoltageLevel::TopologyTraverser& traverser) const { +void NodeBreakerVoltageLevel::traverse(NodeTerminal& terminal, Terminal::TopologyTraverser& traverser) const { TerminalSet traversedTerminals; traverse(terminal, traverser, traversedTerminals); } -bool NodeBreakerVoltageLevel::traverse(NodeTerminal& terminal, VoltageLevel::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const { +bool NodeBreakerVoltageLevel::traverse(NodeTerminal& terminal, Terminal::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const { const math::TraverseResult& termTraverseResult = getTraverseResult(traversedTerminals, terminal, traverser); if (termTraverseResult == math::TraverseResult::TERMINATE_TRAVERSER) { return false; diff --git a/src/iidm/NodeBreakerVoltageLevel.hpp b/src/iidm/NodeBreakerVoltageLevel.hpp index 9f5b57f97..b4c868ad3 100644 --- a/src/iidm/NodeBreakerVoltageLevel.hpp +++ b/src/iidm/NodeBreakerVoltageLevel.hpp @@ -64,9 +64,9 @@ class NodeBreakerVoltageLevel : public VoltageLevel { void invalidateCache() override; - void traverse(NodeTerminal& terminal, VoltageLevel::TopologyTraverser& traverser) const; + void traverse(NodeTerminal& terminal, Terminal::TopologyTraverser& traverser) const; - bool traverse(NodeTerminal& terminal, VoltageLevel::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const; + bool traverse(NodeTerminal& terminal, Terminal::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const; public: NodeBreakerVoltageLevel(const std::string& id, const std::string& name, bool fictitious, const stdcxx::Reference& substation, @@ -98,7 +98,7 @@ class NodeBreakerVoltageLevel : public VoltageLevel { void removeTopology() override; private: - static math::TraverseResult getTraverseResult(TerminalSet& visitedTerminals, NodeTerminal& terminal, TopologyTraverser& traverser); + static math::TraverseResult getTraverseResult(TerminalSet& visitedTerminals, NodeTerminal& terminal, Terminal::TopologyTraverser& traverser); private: void checkTerminal(Terminal& terminal) const; diff --git a/src/iidm/NodeBreakerVoltageLevelViews.cpp b/src/iidm/NodeBreakerVoltageLevelViews.cpp index c239d9b5b..47745607c 100644 --- a/src/iidm/NodeBreakerVoltageLevelViews.cpp +++ b/src/iidm/NodeBreakerVoltageLevelViews.cpp @@ -109,7 +109,7 @@ void BusBreakerViewImpl::removeSwitch(const std::string& /*switchId*/) { throw AssertionError("Not implemented"); } -void BusBreakerViewImpl::traverse(const Bus& /*bus*/, Traverser& /*traverser*/) { +void BusBreakerViewImpl::traverse(const Bus& /*bus*/, TopologyTraverser& /*traverser*/) { throw AssertionError("Not implemented"); } @@ -315,7 +315,7 @@ void NodeBreakerViewImpl::removeSwitch(const std::string& switchId) { m_voltageLevel.removeSwitch(switchId); } -void NodeBreakerViewImpl::traverse(unsigned long node, const Traverser& traverser) const { +void NodeBreakerViewImpl::traverse(unsigned long node, const TopologyTraverser& traverser) const { math::Traverser graphTraverser = [this, &traverser](unsigned long v1, unsigned long e, unsigned long v2) { return traverser(v1, m_voltageLevel.getGraph().getEdgeObject(e), v2); }; @@ -323,7 +323,7 @@ void NodeBreakerViewImpl::traverse(unsigned long node, const Traverser& traverse m_voltageLevel.getGraph().traverse(node, graphTraverser); } -void NodeBreakerViewImpl::traverse(stdcxx::const_range& nodes, const Traverser& traverser) const { +void NodeBreakerViewImpl::traverse(stdcxx::const_range& nodes, const TopologyTraverser& traverser) const { powsybl::math::Traverser graphTraverser = [this, &traverser](unsigned long v1, unsigned long e, unsigned long v2) { return traverser(v1, m_voltageLevel.getGraph().getEdgeObject(e), v2); }; diff --git a/src/iidm/NodeBreakerVoltageLevelViews.hpp b/src/iidm/NodeBreakerVoltageLevelViews.hpp index d69a07c94..0b7de1572 100644 --- a/src/iidm/NodeBreakerVoltageLevelViews.hpp +++ b/src/iidm/NodeBreakerVoltageLevelViews.hpp @@ -82,9 +82,9 @@ class NodeBreakerViewImpl : public voltage_level::NodeBreakerView { void removeSwitch(const std::string& switchId) override; - void traverse(unsigned long node, const Traverser& traverser) const override; + void traverse(unsigned long node, const TopologyTraverser& traverser) const override; - void traverse(stdcxx::const_range& nodes, const Traverser& traverser) const override; + void traverse(stdcxx::const_range& nodes, const TopologyTraverser& traverser) const override; public: explicit NodeBreakerViewImpl(NodeBreakerVoltageLevel& voltageLevel); @@ -123,7 +123,7 @@ class BusBreakerViewImpl : public voltage_level::BusBreakerView { unsigned long getSwitchCount() const override; - void traverse(const Bus& bus, Traverser& traverser) override; + void traverse(const Bus& bus, TopologyTraverser& traverser) override; public: explicit BusBreakerViewImpl(NodeBreakerVoltageLevel& voltageLevel); diff --git a/src/iidm/NodeTerminal.cpp b/src/iidm/NodeTerminal.cpp index 9247a13ff..6d71ecd07 100644 --- a/src/iidm/NodeTerminal.cpp +++ b/src/iidm/NodeTerminal.cpp @@ -135,11 +135,11 @@ NodeTerminal& NodeTerminal::setV(double v) { return *this; } -void NodeTerminal::traverse(voltage_level::TopologyTraverser& traverser) { +void NodeTerminal::traverse(TopologyTraverser& traverser) { dynamic_cast(getVoltageLevel()).traverse(*this, traverser); } -bool NodeTerminal::traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) { +bool NodeTerminal::traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) { return dynamic_cast(getVoltageLevel()).traverse(*this, traverser, traversedTerminals); } diff --git a/src/iidm/NodeTerminal.hpp b/src/iidm/NodeTerminal.hpp index faf2d94ec..e1f6d9e76 100644 --- a/src/iidm/NodeTerminal.hpp +++ b/src/iidm/NodeTerminal.hpp @@ -46,9 +46,9 @@ class NodeTerminal : public Terminal { bool isConnected() const override; - void traverse(voltage_level::TopologyTraverser& traverser) override; + void traverse(TopologyTraverser& traverser) override; - bool traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) override; + bool traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) override; public: NodeTerminal(VoltageLevel& voltageLevel, unsigned long node); diff --git a/src/iidm/util/Networks.cpp b/src/iidm/util/Networks.cpp index f29ffc3d8..e2ec8b948 100644 --- a/src/iidm/util/Networks.cpp +++ b/src/iidm/util/Networks.cpp @@ -26,7 +26,7 @@ stdcxx::CReference getEquivalentTerminal(const VoltageLevel& voltageLe stdcxx::CReference equivalentTerminal; - VoltageLevel::NodeBreakerView::Traverser traverser = [&equivalentTerminal, &voltageLevel](unsigned long /*node1*/, const stdcxx::Reference& sw, unsigned long node2) { + VoltageLevel::NodeBreakerView::TopologyTraverser traverser = [&equivalentTerminal, &voltageLevel](unsigned long /*node1*/, const stdcxx::Reference& sw, unsigned long node2) { if (sw && sw.get().isOpen()) { return math::TraverseResult::TERMINATE_PATH; } diff --git a/src/iidm/util/NodeBreakerTopology.cpp b/src/iidm/util/NodeBreakerTopology.cpp index c282f2b2e..3b53542e3 100644 --- a/src/iidm/util/NodeBreakerTopology.cpp +++ b/src/iidm/util/NodeBreakerTopology.cpp @@ -50,7 +50,7 @@ void removeIsolatedSwitches(voltage_level::NodeBreakerView& topo) { stdcxx::const_range nodesWithTerminal = topo.getNodes() | boost::adaptors::filtered(filter); std::vector> encounteredSwitches; - voltage_level::NodeBreakerView::Traverser traverser = [&encounteredSwitches](unsigned long /*node1*/, const stdcxx::Reference& sw, unsigned long /*node2*/) { + voltage_level::NodeBreakerView::TopologyTraverser traverser = [&encounteredSwitches](unsigned long /*node1*/, const stdcxx::Reference& sw, unsigned long /*node2*/) { encounteredSwitches.emplace_back(std::ref(sw.get())); // the traversing started from a terminal, thus the switch is not isolated return math::TraverseResult::CONTINUE; // if n2 has a terminal, we could also choose to stop as it will be or has already been traversed }; diff --git a/test/iidm/BusBreakerVoltageLevelTest.cpp b/test/iidm/BusBreakerVoltageLevelTest.cpp index 91b43ae46..2a79b3915 100644 --- a/test/iidm/BusBreakerVoltageLevelTest.cpp +++ b/test/iidm/BusBreakerVoltageLevelTest.cpp @@ -502,7 +502,7 @@ BOOST_AUTO_TEST_CASE(expandBusBranch) { Switch& sw1 = network.getSwitch("SW1"); std::vector> buses; - voltage_level::BusBreakerView::Traverser traverser = [&buses, &sw1](const Bus& /*bus1*/, const stdcxx::Reference& sw, const Bus& bus2) { + voltage_level::BusBreakerView::TopologyTraverser traverser = [&buses, &sw1](const Bus& /*bus1*/, const stdcxx::Reference& sw, const Bus& bus2) { if (sw && stdcxx::areSame(sw.get(), sw1)) { return math::TraverseResult::TERMINATE_PATH; } diff --git a/test/iidm/NodeBreakerVoltageLevelTest.cpp b/test/iidm/NodeBreakerVoltageLevelTest.cpp index cb4cfd99e..d2092c603 100644 --- a/test/iidm/NodeBreakerVoltageLevelTest.cpp +++ b/test/iidm/NodeBreakerVoltageLevelTest.cpp @@ -614,7 +614,7 @@ BOOST_AUTO_TEST_CASE(NodeBreakerViewTest) { POWSYBL_ASSERT_THROW(voltageLevel.getNodeBreakerView().getNode1("UNKNOWN"), PowsyblException, "Switch 'UNKNOWN' not found in the voltage level 'VL2'"); - VoltageLevel::NodeBreakerView::Traverser traverser = [=](unsigned long /*node1*/, const stdcxx::Reference& /*sw*/, unsigned long node2) { + VoltageLevel::NodeBreakerView::TopologyTraverser traverser = [=](unsigned long /*node1*/, const stdcxx::Reference& /*sw*/, unsigned long node2) { return (node2 < (NODE_COUNT - 1)) ? math::TraverseResult::CONTINUE : math::TraverseResult::TERMINATE_TRAVERSER; }; voltageLevel.getNodeBreakerView().traverse(0, traverser); diff --git a/test/iidm/TerminalTest.cpp b/test/iidm/TerminalTest.cpp index e46d5848a..98fda1f44 100644 --- a/test/iidm/TerminalTest.cpp +++ b/test/iidm/TerminalTest.cpp @@ -20,7 +20,7 @@ namespace iidm { BOOST_AUTO_TEST_SUITE(TerminalTestSuite) -class CustomTopologyTraverser : public VoltageLevel::TopologyTraverser { +class CustomTopologyTraverser : public Terminal::TopologyTraverser { public: // VoltageLevel::TopologyTraverser math::TraverseResult traverse(Terminal& terminal, bool /*connected*/) override { m_traversedConnectables.insert(terminal.getConnectable().get().getId()); diff --git a/test/iidm/TopologyTraverserTest.cpp b/test/iidm/TopologyTraverserTest.cpp index 071f991b8..1f6975479 100644 --- a/test/iidm/TopologyTraverserTest.cpp +++ b/test/iidm/TopologyTraverserTest.cpp @@ -43,7 +43,7 @@ using IdPos = std::pair; using IdPosSet = std::set>; -class CustomTopologyTraverser : public voltage_level::TopologyTraverser { +class CustomTopologyTraverser : public Terminal::TopologyTraverser { public: using SwitchTest = std::function; From 8c5a58eef8083402acf8aa338540d30a356004cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LAIGRE?= Date: Thu, 31 Mar 2022 16:59:51 +0200 Subject: [PATCH 07/11] Review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien LAIGRE --- include/powsybl/iidm/VoltageLevelViews.hpp | 2 +- src/iidm/BusBreakerVoltageLevel.cpp | 6 ++++-- src/iidm/BusBreakerVoltageLevelViews.cpp | 8 ++++---- src/iidm/BusBreakerVoltageLevelViews.hpp | 2 +- src/iidm/BusTerminal.cpp | 6 ++++-- src/iidm/NodeBreakerVoltageLevel.cpp | 6 ++++-- src/iidm/NodeBreakerVoltageLevelViews.cpp | 4 ++-- src/iidm/NodeBreakerVoltageLevelViews.hpp | 2 +- src/iidm/NodeTerminal.cpp | 6 ++++-- src/iidm/util/Networks.cpp | 3 ++- 10 files changed, 27 insertions(+), 18 deletions(-) diff --git a/include/powsybl/iidm/VoltageLevelViews.hpp b/include/powsybl/iidm/VoltageLevelViews.hpp index 3e3fe19d9..e81d03224 100644 --- a/include/powsybl/iidm/VoltageLevelViews.hpp +++ b/include/powsybl/iidm/VoltageLevelViews.hpp @@ -80,7 +80,7 @@ class BusBreakerView { virtual void removeSwitch(const std::string& switchId) = 0; - virtual void traverse(const Bus& bus, TopologyTraverser& traverser) = 0; + virtual void traverse(const Bus& bus, const TopologyTraverser& traverser) = 0; }; class BusView { diff --git a/src/iidm/BusBreakerVoltageLevel.cpp b/src/iidm/BusBreakerVoltageLevel.cpp index ba508de75..8fffa9c52 100644 --- a/src/iidm/BusBreakerVoltageLevel.cpp +++ b/src/iidm/BusBreakerVoltageLevel.cpp @@ -267,8 +267,10 @@ const TopologyKind& BusBreakerVoltageLevel::getTopologyKind() const { } math::TraverseResult BusBreakerVoltageLevel::getTraverserResult(TerminalSet& visitedTerminals, BusTerminal& terminal, Terminal::TopologyTraverser& traverser) { - auto pair = visitedTerminals.insert(terminal); - return pair.second ? traverser.traverse(terminal, true) : math::TraverseResult::TERMINATE_PATH; + if (visitedTerminals.insert(terminal).second) { + return traverser.traverse(terminal, true); + } + return math::TraverseResult::TERMINATE_PATH; } stdcxx::optional BusBreakerVoltageLevel::getVertex(const std::string& busId, bool throwException) const { diff --git a/src/iidm/BusBreakerVoltageLevelViews.cpp b/src/iidm/BusBreakerVoltageLevelViews.cpp index 78f8c5cab..35af0a404 100644 --- a/src/iidm/BusBreakerVoltageLevelViews.cpp +++ b/src/iidm/BusBreakerVoltageLevelViews.cpp @@ -125,13 +125,13 @@ void BusBreakerViewImpl::removeSwitch(const std::string& switchId) { m_voltageLevel.removeSwitch(switchId); } -void BusBreakerViewImpl::traverse(const Bus& bus, TopologyTraverser& traverser) { - math::Traverser graphTraverser = [this, &traverser](unsigned long v1, unsigned long e, unsigned long v2) { - const auto& graph = m_voltageLevel.getGraph(); +void BusBreakerViewImpl::traverse(const Bus& bus, const TopologyTraverser& traverser) { + const auto& graph = m_voltageLevel.getGraph(); + math::Traverser graphTraverser = [&graph, &traverser](unsigned long v1, unsigned long e, unsigned long v2) { return traverser(graph.getVertexObject(v1), graph.getEdgeObject(e), graph.getVertexObject(v2)); }; - m_voltageLevel.getGraph().traverse(*m_voltageLevel.getVertex(bus.getId(), true), graphTraverser); + graph.traverse(*m_voltageLevel.getVertex(bus.getId(), true), graphTraverser); } BusViewImpl::BusViewImpl(BusBreakerVoltageLevel& voltageLevel) : diff --git a/src/iidm/BusBreakerVoltageLevelViews.hpp b/src/iidm/BusBreakerVoltageLevelViews.hpp index 034a93383..c9798580f 100644 --- a/src/iidm/BusBreakerVoltageLevelViews.hpp +++ b/src/iidm/BusBreakerVoltageLevelViews.hpp @@ -59,7 +59,7 @@ class BusBreakerViewImpl : public voltage_level::BusBreakerView { void removeSwitch(const std::string& switchId) override; - void traverse(const Bus& bus, TopologyTraverser& traverser) override; + void traverse(const Bus& bus, const TopologyTraverser& traverser) override; public: explicit BusBreakerViewImpl(BusBreakerVoltageLevel& voltageLevel); diff --git a/src/iidm/BusTerminal.cpp b/src/iidm/BusTerminal.cpp index da246b37b..054679814 100644 --- a/src/iidm/BusTerminal.cpp +++ b/src/iidm/BusTerminal.cpp @@ -113,11 +113,13 @@ BusTerminal& BusTerminal::setConnected(bool connected) { } void BusTerminal::traverse(TopologyTraverser& traverser) { - dynamic_cast(getVoltageLevel()).traverse(*this, traverser); + auto& voltageLevel = dynamic_cast(getVoltageLevel()); + voltageLevel.traverse(*this, traverser); } bool BusTerminal::traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) { - return dynamic_cast(getVoltageLevel()).traverse(*this, traverser, traversedTerminals); + auto& voltageLevel = dynamic_cast(getVoltageLevel()); + return voltageLevel.traverse(*this, traverser, traversedTerminals); } std::ostream& operator<<(std::ostream& stream, const BusTerminal& busTerminal) { diff --git a/src/iidm/NodeBreakerVoltageLevel.cpp b/src/iidm/NodeBreakerVoltageLevel.cpp index 2edb32497..59c04d547 100644 --- a/src/iidm/NodeBreakerVoltageLevel.cpp +++ b/src/iidm/NodeBreakerVoltageLevel.cpp @@ -334,8 +334,10 @@ const TopologyKind& NodeBreakerVoltageLevel::getTopologyKind() const { } math::TraverseResult NodeBreakerVoltageLevel::getTraverseResult(TerminalSet& visitedTerminals, NodeTerminal& terminal, Terminal::TopologyTraverser& traverser) { - auto pair = visitedTerminals.insert(terminal); - return pair.second ? traverser.traverse(terminal, true) : math::TraverseResult::TERMINATE_PATH; + if (visitedTerminals.insert(terminal).second) { + return traverser.traverse(terminal, true); + } + return math::TraverseResult::TERMINATE_PATH; } void NodeBreakerVoltageLevel::invalidateCache() { diff --git a/src/iidm/NodeBreakerVoltageLevelViews.cpp b/src/iidm/NodeBreakerVoltageLevelViews.cpp index 47745607c..f85f43a75 100644 --- a/src/iidm/NodeBreakerVoltageLevelViews.cpp +++ b/src/iidm/NodeBreakerVoltageLevelViews.cpp @@ -109,8 +109,8 @@ void BusBreakerViewImpl::removeSwitch(const std::string& /*switchId*/) { throw AssertionError("Not implemented"); } -void BusBreakerViewImpl::traverse(const Bus& /*bus*/, TopologyTraverser& /*traverser*/) { - throw AssertionError("Not implemented"); +void BusBreakerViewImpl::traverse(const Bus& /*bus*/, const TopologyTraverser& /*traverser*/) { + throw PowsyblException("Not supported in a node/breaker topology"); } BusViewImpl::BusViewImpl(NodeBreakerVoltageLevel& voltageLevel) : diff --git a/src/iidm/NodeBreakerVoltageLevelViews.hpp b/src/iidm/NodeBreakerVoltageLevelViews.hpp index 0b7de1572..b92248368 100644 --- a/src/iidm/NodeBreakerVoltageLevelViews.hpp +++ b/src/iidm/NodeBreakerVoltageLevelViews.hpp @@ -123,7 +123,7 @@ class BusBreakerViewImpl : public voltage_level::BusBreakerView { unsigned long getSwitchCount() const override; - void traverse(const Bus& bus, TopologyTraverser& traverser) override; + void traverse(const Bus& bus, const TopologyTraverser& traverser) override; public: explicit BusBreakerViewImpl(NodeBreakerVoltageLevel& voltageLevel); diff --git a/src/iidm/NodeTerminal.cpp b/src/iidm/NodeTerminal.cpp index 6d71ecd07..ee5879178 100644 --- a/src/iidm/NodeTerminal.cpp +++ b/src/iidm/NodeTerminal.cpp @@ -136,11 +136,13 @@ NodeTerminal& NodeTerminal::setV(double v) { } void NodeTerminal::traverse(TopologyTraverser& traverser) { - dynamic_cast(getVoltageLevel()).traverse(*this, traverser); + auto& voltageLevel = dynamic_cast(getVoltageLevel()); + voltageLevel.traverse(*this, traverser); } bool NodeTerminal::traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) { - return dynamic_cast(getVoltageLevel()).traverse(*this, traverser, traversedTerminals); + auto& voltageLevel = dynamic_cast(getVoltageLevel()); + return voltageLevel.traverse(*this, traverser, traversedTerminals); } } // namespace iidm diff --git a/src/iidm/util/Networks.cpp b/src/iidm/util/Networks.cpp index e2ec8b948..b67639b12 100644 --- a/src/iidm/util/Networks.cpp +++ b/src/iidm/util/Networks.cpp @@ -33,8 +33,9 @@ stdcxx::CReference getEquivalentTerminal(const VoltageLevel& voltageLe const auto& terminal = voltageLevel.getNodeBreakerView().getTerminal(node2); if (terminal) { equivalentTerminal = terminal; + return math::TraverseResult::TERMINATE_TRAVERSER; } - return terminal ? math::TraverseResult::TERMINATE_TRAVERSER : math::TraverseResult::CONTINUE; + return math::TraverseResult::CONTINUE; }; voltageLevel.getNodeBreakerView().traverse(node, traverser); From 203947f53e961a1f36f04f1c74b64f0cc9d8833b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LAIGRE?= Date: Thu, 31 Mar 2022 17:05:50 +0200 Subject: [PATCH 08/11] Use include dir introduced 7a605d19eda73ecd37b0de01a7a051ba0df83f93 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien LAIGRE --- test/iidm/util/NodeBreakerTopologyTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/iidm/util/NodeBreakerTopologyTest.cpp b/test/iidm/util/NodeBreakerTopologyTest.cpp index 2d183bb26..d7740447b 100644 --- a/test/iidm/util/NodeBreakerTopologyTest.cpp +++ b/test/iidm/util/NodeBreakerTopologyTest.cpp @@ -14,7 +14,7 @@ #include #include -#include "../NetworkFactory.hpp" +#include "NetworkFactory.hpp" namespace powsybl { From e7472688e26ba693a9abd1ced38f0da9e246e9d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LAIGRE?= Date: Thu, 31 Mar 2022 17:34:43 +0200 Subject: [PATCH 09/11] Simplify NodeBreakerTopology::removeIsolatedSwitches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien LAIGRE --- src/iidm/util/NodeBreakerTopology.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/iidm/util/NodeBreakerTopology.cpp b/src/iidm/util/NodeBreakerTopology.cpp index 3b53542e3..0868df574 100644 --- a/src/iidm/util/NodeBreakerTopology.cpp +++ b/src/iidm/util/NodeBreakerTopology.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include @@ -49,18 +49,15 @@ void removeIsolatedSwitches(voltage_level::NodeBreakerView& topo) { }; stdcxx::const_range nodesWithTerminal = topo.getNodes() | boost::adaptors::filtered(filter); - std::vector> encounteredSwitches; - voltage_level::NodeBreakerView::TopologyTraverser traverser = [&encounteredSwitches](unsigned long /*node1*/, const stdcxx::Reference& sw, unsigned long /*node2*/) { - encounteredSwitches.emplace_back(std::ref(sw.get())); // the traversing started from a terminal, thus the switch is not isolated + std::set encounteredSwitchIds; + voltage_level::NodeBreakerView::TopologyTraverser traverser = [&encounteredSwitchIds](unsigned long /*node1*/, const stdcxx::Reference& sw, unsigned long /*node2*/) { + encounteredSwitchIds.emplace(sw.get().getId()); // the traversing started from a terminal, thus the switch is not isolated return math::TraverseResult::CONTINUE; // if n2 has a terminal, we could also choose to stop as it will be or has already been traversed }; topo.traverse(nodesWithTerminal, traverser); - const auto& filterNotEncounteredSwitches = [&encounteredSwitches](const Switch& sw) { - auto it = std::find_if(encounteredSwitches.begin(), encounteredSwitches.end(), [&sw](const std::reference_wrapper& swInList) { - return stdcxx::areSame(sw, swInList.get()); - }); - return it == encounteredSwitches.end(); + const auto& filterNotEncounteredSwitches = [&encounteredSwitchIds](const Switch& sw) { + return encounteredSwitchIds.find(sw.getId()) == encounteredSwitchIds.end(); }; for (const Switch& sw : topo.getSwitches() | boost::adaptors::filtered(filterNotEncounteredSwitches)) { topo.removeSwitch(sw.getId()); From 1aed1dbfaf7507378a73278d928c558f493dfdfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LAIGRE?= Date: Tue, 24 May 2022 10:43:14 +0200 Subject: [PATCH 10/11] Make all traverse methods return a bool (backport of Java PR 2044) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien LAIGRE --- include/powsybl/iidm/Terminal.hpp | 2 +- src/iidm/BusBreakerVoltageLevel.cpp | 4 ++-- src/iidm/BusBreakerVoltageLevel.hpp | 2 +- src/iidm/BusTerminal.cpp | 4 ++-- src/iidm/BusTerminal.hpp | 2 +- src/iidm/NodeBreakerVoltageLevel.cpp | 4 ++-- src/iidm/NodeBreakerVoltageLevel.hpp | 2 +- src/iidm/NodeTerminal.cpp | 4 ++-- src/iidm/NodeTerminal.hpp | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/powsybl/iidm/Terminal.hpp b/include/powsybl/iidm/Terminal.hpp index 0ddddecc2..e1579eb03 100644 --- a/include/powsybl/iidm/Terminal.hpp +++ b/include/powsybl/iidm/Terminal.hpp @@ -88,7 +88,7 @@ class Terminal : public MultiVariantObject { Terminal& setQ(double q); - virtual void traverse(TopologyTraverser& traverser) = 0; + virtual bool traverse(TopologyTraverser& traverser) = 0; virtual bool traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) = 0; diff --git a/src/iidm/BusBreakerVoltageLevel.cpp b/src/iidm/BusBreakerVoltageLevel.cpp index 8fffa9c52..6268a1a43 100644 --- a/src/iidm/BusBreakerVoltageLevel.cpp +++ b/src/iidm/BusBreakerVoltageLevel.cpp @@ -368,9 +368,9 @@ void BusBreakerVoltageLevel::removeTopology() { removeAllBuses(); } -void BusBreakerVoltageLevel::traverse(BusTerminal& terminal, Terminal::TopologyTraverser& traverser) const { +bool BusBreakerVoltageLevel::traverse(BusTerminal& terminal, Terminal::TopologyTraverser& traverser) const { TerminalSet traversedTerminals; - traverse(terminal, traverser, traversedTerminals); + return traverse(terminal, traverser, traversedTerminals); } bool BusBreakerVoltageLevel::traverse(BusTerminal& terminal, Terminal::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const { diff --git a/src/iidm/BusBreakerVoltageLevel.hpp b/src/iidm/BusBreakerVoltageLevel.hpp index 289a5e74b..228fa66f8 100644 --- a/src/iidm/BusBreakerVoltageLevel.hpp +++ b/src/iidm/BusBreakerVoltageLevel.hpp @@ -66,7 +66,7 @@ class BusBreakerVoltageLevel : public VoltageLevel { Switch& addSwitch(std::unique_ptr&& ptrSwitch, const std::string& busId1, const std::string& busId2); - void traverse(BusTerminal& terminal, Terminal::TopologyTraverser& traverser) const; + bool traverse(BusTerminal& terminal, Terminal::TopologyTraverser& traverser) const; bool traverse(BusTerminal& terminal, Terminal::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const; diff --git a/src/iidm/BusTerminal.cpp b/src/iidm/BusTerminal.cpp index 054679814..936110678 100644 --- a/src/iidm/BusTerminal.cpp +++ b/src/iidm/BusTerminal.cpp @@ -112,9 +112,9 @@ BusTerminal& BusTerminal::setConnected(bool connected) { return *this; } -void BusTerminal::traverse(TopologyTraverser& traverser) { +bool BusTerminal::traverse(TopologyTraverser& traverser) { auto& voltageLevel = dynamic_cast(getVoltageLevel()); - voltageLevel.traverse(*this, traverser); + return voltageLevel.traverse(*this, traverser); } bool BusTerminal::traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) { diff --git a/src/iidm/BusTerminal.hpp b/src/iidm/BusTerminal.hpp index f02d4a0b6..f994e0d20 100644 --- a/src/iidm/BusTerminal.hpp +++ b/src/iidm/BusTerminal.hpp @@ -48,7 +48,7 @@ class BusTerminal : public Terminal { bool isConnected() const override; - void traverse(TopologyTraverser& traverser) override; + bool traverse(TopologyTraverser& traverser) override; bool traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) override; diff --git a/src/iidm/NodeBreakerVoltageLevel.cpp b/src/iidm/NodeBreakerVoltageLevel.cpp index 59c04d547..ce5aa9ed9 100644 --- a/src/iidm/NodeBreakerVoltageLevel.cpp +++ b/src/iidm/NodeBreakerVoltageLevel.cpp @@ -397,9 +397,9 @@ void NodeBreakerVoltageLevel::removeTopology() { m_switches.clear(); } -void NodeBreakerVoltageLevel::traverse(NodeTerminal& terminal, Terminal::TopologyTraverser& traverser) const { +bool NodeBreakerVoltageLevel::traverse(NodeTerminal& terminal, Terminal::TopologyTraverser& traverser) const { TerminalSet traversedTerminals; - traverse(terminal, traverser, traversedTerminals); + return traverse(terminal, traverser, traversedTerminals); } bool NodeBreakerVoltageLevel::traverse(NodeTerminal& terminal, Terminal::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const { diff --git a/src/iidm/NodeBreakerVoltageLevel.hpp b/src/iidm/NodeBreakerVoltageLevel.hpp index b4c868ad3..93374a3a4 100644 --- a/src/iidm/NodeBreakerVoltageLevel.hpp +++ b/src/iidm/NodeBreakerVoltageLevel.hpp @@ -64,7 +64,7 @@ class NodeBreakerVoltageLevel : public VoltageLevel { void invalidateCache() override; - void traverse(NodeTerminal& terminal, Terminal::TopologyTraverser& traverser) const; + bool traverse(NodeTerminal& terminal, Terminal::TopologyTraverser& traverser) const; bool traverse(NodeTerminal& terminal, Terminal::TopologyTraverser& traverser, TerminalSet& traversedTerminals) const; diff --git a/src/iidm/NodeTerminal.cpp b/src/iidm/NodeTerminal.cpp index ee5879178..24af6e260 100644 --- a/src/iidm/NodeTerminal.cpp +++ b/src/iidm/NodeTerminal.cpp @@ -135,9 +135,9 @@ NodeTerminal& NodeTerminal::setV(double v) { return *this; } -void NodeTerminal::traverse(TopologyTraverser& traverser) { +bool NodeTerminal::traverse(TopologyTraverser& traverser) { auto& voltageLevel = dynamic_cast(getVoltageLevel()); - voltageLevel.traverse(*this, traverser); + return voltageLevel.traverse(*this, traverser); } bool NodeTerminal::traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) { diff --git a/src/iidm/NodeTerminal.hpp b/src/iidm/NodeTerminal.hpp index e1f6d9e76..754214b97 100644 --- a/src/iidm/NodeTerminal.hpp +++ b/src/iidm/NodeTerminal.hpp @@ -46,7 +46,7 @@ class NodeTerminal : public Terminal { bool isConnected() const override; - void traverse(TopologyTraverser& traverser) override; + bool traverse(TopologyTraverser& traverser) override; bool traverse(TopologyTraverser& traverser, TerminalSet& traversedTerminals) override; From 5ba48044cbff45ef8d19d9010771a60e702ed87e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LAIGRE?= Date: Tue, 24 May 2022 18:09:20 +0200 Subject: [PATCH 11/11] Add tck tests of java PR 1880 (#388) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien LAIGRE --- test/iidm/TopologyTraverserTest.cpp | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/iidm/TopologyTraverserTest.cpp b/test/iidm/TopologyTraverserTest.cpp index 1f6975479..a63fe5e1c 100644 --- a/test/iidm/TopologyTraverserTest.cpp +++ b/test/iidm/TopologyTraverserTest.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "NetworkFactory.hpp" @@ -200,6 +201,51 @@ BOOST_AUTO_TEST_CASE(test5) { BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), res.begin(), res.end()); } +BOOST_AUTO_TEST_CASE(testTerminateTraverser) { + Network network = createMixedNodeBreakerBusBreakerNetwork(); + Terminal& startGNbv = network.getGenerator("G").getTerminal(); + const auto& visited1 = getVisitedList(startGNbv, + [](Switch& sw) { return sw.getId() == "BR2" ? math::TraverseResult::TERMINATE_TRAVERSER : math::TraverseResult::CONTINUE; }); + IdPosSet expectedVisited1 = { {"BBS1", 0}, {"G", 0} }; + BOOST_CHECK_EQUAL_COLLECTIONS(expectedVisited1.begin(), expectedVisited1.end(), visited1.begin(), visited1.end()); + + const auto& visited2 = getVisitedList(startGNbv, + [](Switch& /*sw*/) { return math::TraverseResult::CONTINUE; }, + [](Terminal& /*terminal*/) { return math::TraverseResult::TERMINATE_TRAVERSER; }); + IdPosSet expectedVisited2 = { {"G", 0} }; + BOOST_CHECK_EQUAL_COLLECTIONS(expectedVisited2.begin(), expectedVisited2.end(), visited2.begin(), visited2.end()); + + const auto& visited3 = getVisitedList(startGNbv, + [](Switch& /*sw*/) { return math::TraverseResult::CONTINUE; }, + [](Terminal& terminal) { return stdcxx::isInstanceOf(terminal.getConnectable()) ? math::TraverseResult::TERMINATE_TRAVERSER : math::TraverseResult::CONTINUE; }); + IdPosSet expectedVisited3 = { {"BBS1", 0}, {"G", 0} }; + BOOST_CHECK_EQUAL_COLLECTIONS(expectedVisited3.begin(), expectedVisited3.end(), visited3.begin(), visited3.end()); + + Terminal& startLBbv = network.getLoad("LD2").getTerminal(); + const auto& visited4 = getVisitedList(startLBbv, + [](Switch& /*sw*/) { return math::TraverseResult::CONTINUE; }, + [](Terminal& /*terminal*/) { return math::TraverseResult::TERMINATE_TRAVERSER; }); + IdPosSet expectedVisited4 = { {"LD2", 0} }; + BOOST_CHECK_EQUAL_COLLECTIONS(expectedVisited4.begin(), expectedVisited4.end(), visited4.begin(), visited4.end()); + + const auto& visited5 = getVisitedList(startLBbv, + [](Switch& /*sw*/) { return math::TraverseResult::CONTINUE; }, + [](Terminal& terminal) { return terminal.getConnectable().get().getId() == "L2" ? math::TraverseResult::TERMINATE_TRAVERSER : math::TraverseResult::CONTINUE; }); + IdPosSet expectedVisited5 = { {"LD2", 0}, {"L2", 1} }; + BOOST_CHECK_EQUAL_COLLECTIONS(expectedVisited5.begin(), expectedVisited5.end(), visited5.begin(), visited5.end()); +} + +BOOST_AUTO_TEST_CASE(testTraversalOrder) { + Network network = powsybl::network::FictitiousSwitchFactory::create(); + const auto& visited = getVisitedList(network.getGenerator("CB").getTerminal(), + [](Switch& /*sw*/) { return math::TraverseResult::CONTINUE; }); + IdPosSet expectedVisited = { {"CB", 0}, {"O", 0}, {"P", 0}, {"CF", 0}, + {"CH", 0}, {"CC", 0}, {"CD", 0}, {"CE", 0}, + {"CJ", 1}, {"CI", 1}, {"CG", 0}, {"CJ", 0}, + {"D", 0}, {"CI", 0} }; + BOOST_CHECK_EQUAL_COLLECTIONS(expectedVisited.begin(), expectedVisited.end(), visited.begin(), visited.end()); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace iidm