Skip to content

Commit

Permalink
Fix implementation and add TopologyTraverserTest
Browse files Browse the repository at this point in the history
Signed-off-by: Sébastien LAIGRE <[email protected]>
  • Loading branch information
sebalaig committed Mar 14, 2022
1 parent c46cddb commit eb5d179
Show file tree
Hide file tree
Showing 15 changed files with 476 additions and 100 deletions.
2 changes: 1 addition & 1 deletion include/powsybl/iidm/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsigned long>& indexes, unsigned long sourceIndex) override;
Expand Down
6 changes: 4 additions & 2 deletions include/powsybl/iidm/VoltageLevelTopologyTraverser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#ifndef POWSYBL_IIDM_VOLTAGELEVELTOPOLOGYTRAVERSER_HPP
#define POWSYBL_IIDM_VOLTAGELEVELTOPOLOGYTRAVERSER_HPP

#include <powsybl/math/TraverseResult.hpp>

namespace powsybl {

namespace iidm {
Expand All @@ -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
Expand Down
66 changes: 38 additions & 28 deletions src/iidm/BusBreakerVoltageLevel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsigned long> BusBreakerVoltageLevel::getVertex(const std::string& busId, bool throwException) const {
checkNotEmpty(busId, "bus id is null");

Expand Down Expand Up @@ -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<BusTerminal>& 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& terminal : nextTerminals) {
if (!terminal.traverse(traverser, traversedTerminals)) {
return false;
}
}
}

return true;
}

} // namespace iidm
Expand Down
5 changes: 4 additions & 1 deletion src/iidm/BusBreakerVoltageLevel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsigned long>& indexes, unsigned long sourceIndex) override;
Expand All @@ -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;

Expand Down
5 changes: 2 additions & 3 deletions src/iidm/BusTerminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,10 @@ void BusTerminal::traverse(voltage_level::TopologyTraverser& traverser) {
dynamic_cast<BusBreakerVoltageLevel&>(getVoltageLevel()).traverse(*this, traverser);
}

void BusTerminal::traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) {
dynamic_cast<BusBreakerVoltageLevel&>(getVoltageLevel()).traverse(*this, traverser, traversedTerminals);
bool BusTerminal::traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) {
return dynamic_cast<BusBreakerVoltageLevel&>(getVoltageLevel()).traverse(*this, traverser, traversedTerminals);
}


std::ostream& operator<<(std::ostream& stream, const BusTerminal& busTerminal) {
stream << stdcxx::simpleClassName(busTerminal) << "[" << busTerminal.getConnectableBusId() << "]";

Expand Down
2 changes: 1 addition & 1 deletion src/iidm/BusTerminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
57 changes: 31 additions & 26 deletions src/iidm/NodeBreakerVoltageLevel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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<Switch>& aSwitch = m_graph.getEdgeObject(e);
const stdcxx::Reference<NodeTerminal>& 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
Expand Down
5 changes: 4 additions & 1 deletion src/iidm/NodeBreakerVoltageLevel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>& substation,
Expand Down Expand Up @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions src/iidm/NodeTerminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ void NodeTerminal::traverse(voltage_level::TopologyTraverser& traverser) {
dynamic_cast<NodeBreakerVoltageLevel&>(getVoltageLevel()).traverse(*this, traverser);
}

void NodeTerminal::traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) {
dynamic_cast<NodeBreakerVoltageLevel&>(getVoltageLevel()).traverse(*this, traverser, traversedTerminals);
bool NodeTerminal::traverse(voltage_level::TopologyTraverser& traverser, TerminalSet& traversedTerminals) {
return dynamic_cast<NodeBreakerVoltageLevel&>(getVoltageLevel()).traverse(*this, traverser, traversedTerminals);
}

} // namespace iidm
Expand Down
2 changes: 1 addition & 1 deletion src/iidm/NodeTerminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions test/iidm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ set(UNIT_TEST_SOURCES
SubstationTest.cpp
TerminalTest.cpp
TopologyLevelTest.cpp
TopologyTraverserTest.cpp
ThreeWindingsTransformerTest.cpp
TieLineTest.cpp
TwoWindingsTransformerTest.cpp
Expand Down
Loading

0 comments on commit eb5d179

Please sign in to comment.