Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get switches and internal connections from given node (#391) #422

Open
wants to merge 4 commits into
base: integration/v1.6.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/powsybl/iidm/VoltageLevelViews.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ class NodeBreakerView {

virtual stdcxx::const_range<unsigned long> getNodes() const = 0;

virtual stdcxx::const_range<unsigned long> getNodesInternalConnectedTo(unsigned long node) const = 0;

virtual stdcxx::CReference<Terminal> getOptionalTerminal(unsigned long node) const = 0;

virtual stdcxx::Reference<Terminal> getOptionalTerminal(unsigned long node) = 0;
Expand All @@ -149,6 +151,10 @@ class NodeBreakerView {

virtual stdcxx::range<Switch> getSwitches() = 0;

virtual stdcxx::const_range<Switch> getSwitches(unsigned long node) const = 0;

virtual stdcxx::range<Switch> getSwitches(unsigned long node) = 0;

virtual stdcxx::CReference<Terminal> getTerminal(unsigned long node) const = 0;

virtual stdcxx::Reference<Terminal> getTerminal(unsigned long node) = 0;
Expand Down
18 changes: 14 additions & 4 deletions include/powsybl/math/UndirectedGraph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,29 @@ class UndirectedGraph {

const stdcxx::Reference<E>& getEdgeObject(unsigned long e) const;

const_range<E> getEdgeObjectsConnectedToVertex(unsigned long vertex) const;

const std::vector<unsigned long>& getEdgeConnectedToVertex(unsigned long vertex) const;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we have to keep this method. It seems you backport the IntStream getEdgeConnectedToVertexStream(int v); method, but from my point of view, an S is missing in the name of the method.


const std::vector<unsigned long>& getEdgesConnectedToVertex(unsigned long vertex) const;

const_range<E> getEdgeObjects() const;

range<E> getEdgeObjects();

const_range<E> getEdgeObjects(unsigned long v1, unsigned long v2) const;

const unsigned long& getEdgeVertex1(unsigned long edge) const;

const unsigned long& getEdgeVertex2(unsigned long edge) const;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be discussed: not sure this is a good idea to return a reference here.


const_range<unsigned long> getEdges() const;

unsigned long getMaxVertex() const;

unsigned long getVertex1(unsigned long e) const;
const unsigned long& getVertex1(unsigned long e) const;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be discussed: I think it's not wrong, I had to update that in order to return a range in NodeBreakerViewImpl::getNodesInternalConnectedTo (unless it was gardening...). But maybe NodeBreakerViewImpl::getNodesInternalConnectedTo should return a vector instead ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to think a little bit more about the issue you encountered


unsigned long getVertex2(unsigned long e) const;
const unsigned long& getVertex2(unsigned long e) const;

unsigned long getVertexCapacity() const;

Expand Down Expand Up @@ -148,9 +158,9 @@ class UndirectedGraph<V, E>::Edge {

const stdcxx::Reference<E>& getObject() const;

unsigned long getVertex1() const;
const unsigned long& getVertex1() const;

unsigned long getVertex2() const;
const unsigned long& getVertex2() const;

void setObject(const stdcxx::Reference<E>& object);

Expand Down
42 changes: 37 additions & 5 deletions include/powsybl/math/UndirectedGraph.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ void UndirectedGraph<V, E>::addVertexIfNotPresent(unsigned long v) {
m_availableVertices.erase(it);
}
} else {
for (unsigned int i = m_vertices.size(); i < v; ++i) {
for (auto i = m_vertices.size(); i < v; ++i) {
m_availableVertices.insert(i);
}
m_vertices.resize(v + 1);
Expand Down Expand Up @@ -216,6 +216,26 @@ const stdcxx::Reference<E>& UndirectedGraph<V, E>::getEdgeObject(unsigned long e
return m_edges[e]->getObject();
}

template <typename V, typename E>
typename UndirectedGraph<V, E>::template const_range<E> UndirectedGraph<V, E>::getEdgeObjectsConnectedToVertex(unsigned long vertex) const {
const auto& edgeMapper = [this](const unsigned long& e) -> const stdcxx::Reference<E>& {
return getEdgeObject(e);
};

return getEdgeConnectedToVertex(vertex) | boost::adaptors::transformed(edgeMapper);
}

template <typename V, typename E>
const std::vector<unsigned long>& UndirectedGraph<V, E>::getEdgeConnectedToVertex(unsigned long vertex) const {
checkVertex(vertex);
return getAdjacencyList()[vertex];
}

template <typename V, typename E>
const std::vector<unsigned long>& UndirectedGraph<V, E>::getEdgesConnectedToVertex(unsigned long vertex) const {
return getEdgeConnectedToVertex(vertex);
}

template <typename V, typename E>
typename UndirectedGraph<V, E>::template const_range<E> UndirectedGraph<V, E>::getEdgeObjects() const {
const auto& filter = [](const std::unique_ptr<Edge>& edge) {
Expand Down Expand Up @@ -255,6 +275,18 @@ typename UndirectedGraph<V, E>::template const_range<E> UndirectedGraph<V, E>::g
boost::adaptors::transformed(Edge::map);
}

template <typename V, typename E>
const unsigned long& UndirectedGraph<V, E>::getEdgeVertex1(unsigned long edge) const {
checkEdge(edge);
return m_edges[edge]->getVertex1();
}

template <typename V, typename E>
const unsigned long& UndirectedGraph<V, E>::getEdgeVertex2(unsigned long edge) const {
checkEdge(edge);
return m_edges[edge]->getVertex2();
}

template <typename V, typename E>
typename UndirectedGraph<V, E>::template const_range<unsigned long> UndirectedGraph<V, E>::getEdges() const {
const auto& filter = [this](const unsigned long e) {
Expand All @@ -270,13 +302,13 @@ unsigned long UndirectedGraph<V, E>::getMaxVertex() const {
}

template <typename V, typename E>
unsigned long UndirectedGraph<V, E>::getVertex1(unsigned long e) const {
const unsigned long& UndirectedGraph<V, E>::getVertex1(unsigned long e) const {
checkEdge(e);
return m_edges.at(e).get()->getVertex1();
}

template <typename V, typename E>
unsigned long UndirectedGraph<V, E>::getVertex2(unsigned long e) const {
const unsigned long& UndirectedGraph<V, E>::getVertex2(unsigned long e) const {
checkEdge(e);
return m_edges.at(e).get()->getVertex2();
}
Expand Down Expand Up @@ -500,12 +532,12 @@ const stdcxx::Reference<E>& UndirectedGraph<V, E>::Edge::map(const typename Undi
}

template <typename V, typename E>
unsigned long UndirectedGraph<V, E>::Edge::getVertex1() const {
const unsigned long& UndirectedGraph<V, E>::Edge::getVertex1() const {
return m_vertex1;
}

template <typename V, typename E>
unsigned long UndirectedGraph<V, E>::Edge::getVertex2() const {
const unsigned long& UndirectedGraph<V, E>::Edge::getVertex2() const {
return m_vertex2;
}

Expand Down
1 change: 0 additions & 1 deletion src/iidm/BusBreakerVoltageLevel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ bool BusBreakerVoltageLevel::connect(Terminal& terminal) {
return true;
}


void BusBreakerVoltageLevel::deleteVariantArrayElement(unsigned long index) {
VoltageLevel::deleteVariantArrayElement(index);
m_variants.deleteVariantArrayElement(index);
Expand Down
1 change: 1 addition & 0 deletions src/iidm/BusBreakerVoltageLevel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <set>
#include <string>

#include <powsybl/PowsyblException.hpp>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure you should add this include in a header.

#include <powsybl/iidm/VariantArray.hpp>
#include <powsybl/iidm/VoltageLevel.hpp>
#include <powsybl/math/UndirectedGraph.hpp>
Expand Down
37 changes: 37 additions & 0 deletions src/iidm/NodeBreakerVoltageLevelViews.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,19 @@ stdcxx::const_range<unsigned long> NodeBreakerViewImpl::getNodes() const {
return m_voltageLevel.getGraph().getVertices();
}

stdcxx::const_range<unsigned long> NodeBreakerViewImpl::getNodesInternalConnectedTo(unsigned long node) const {
const auto& isNull = [this](const unsigned long& edge) {
return !static_cast<bool>(m_voltageLevel.getGraph().getEdgeObject(edge));
};

const auto& mapper = [this, node](const unsigned long& edge) -> const unsigned long& {
unsigned long vertex1 = m_voltageLevel.getGraph().getEdgeVertex1(edge);
return vertex1 != node ? m_voltageLevel.getGraph().getEdgeVertex1(edge) : m_voltageLevel.getGraph().getEdgeVertex2(edge);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid this useless call to m_voltageLevel.getGraph().getEdgeVertex1(edge)

};

return m_voltageLevel.getGraph().getEdgeConnectedToVertex(node) | boost::adaptors::filtered(isNull) | boost::adaptors::transformed(mapper);
}

stdcxx::CReference<Terminal> NodeBreakerViewImpl::getOptionalTerminal(unsigned long node) const {
if (m_voltageLevel.getGraph().vertexExists(node)) {
return stdcxx::cref<Terminal>(m_voltageLevel.getGraph().getVertexObject(node));
Expand Down Expand Up @@ -259,6 +272,30 @@ stdcxx::range<Switch> NodeBreakerViewImpl::getSwitches() {
return m_voltageLevel.getGraph().getEdgeObjects() | boost::adaptors::filtered(filter) | boost::adaptors::transformed(mapper);
}

stdcxx::const_range<Switch> NodeBreakerViewImpl::getSwitches(unsigned long node) const {
const auto& notNull = [](const stdcxx::Reference<Switch>& sw) {
return static_cast<bool>(sw);
};

const auto& deref = [](const stdcxx::Reference<Switch>& sw) -> const Switch& {
sebalaig marked this conversation as resolved.
Show resolved Hide resolved
return sw.get();
};

return m_voltageLevel.getGraph().getEdgeObjectsConnectedToVertex(node) | boost::adaptors::filtered(notNull) | boost::adaptors::transformed(deref);
}

stdcxx::range<Switch> NodeBreakerViewImpl::getSwitches(unsigned long node) {
const auto& notNull = [](const stdcxx::Reference<Switch>& sw) {
return static_cast<bool>(sw);
};

const auto& deref = [](const stdcxx::Reference<Switch>& sw) -> Switch& {
return sw.get();
};
sebalaig marked this conversation as resolved.
Show resolved Hide resolved

return m_voltageLevel.getGraph().getEdgeObjectsConnectedToVertex(node) | boost::adaptors::filtered(notNull) | boost::adaptors::transformed(deref);
}

stdcxx::CReference<Terminal> NodeBreakerViewImpl::getTerminal(unsigned long node) const {
return stdcxx::cref(m_voltageLevel.getTerminal(node));
}
Expand Down
6 changes: 6 additions & 0 deletions src/iidm/NodeBreakerVoltageLevelViews.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class NodeBreakerViewImpl : public voltage_level::NodeBreakerView {

stdcxx::const_range<unsigned long> getNodes() const override;

stdcxx::const_range<unsigned long> getNodesInternalConnectedTo(unsigned long node) const override;

stdcxx::CReference<Terminal> getOptionalTerminal(unsigned long node) const override;

stdcxx::Reference<Terminal> getOptionalTerminal(unsigned long node) override;
Expand All @@ -54,6 +56,10 @@ class NodeBreakerViewImpl : public voltage_level::NodeBreakerView {

stdcxx::range<Switch> getSwitches() override;

stdcxx::const_range<Switch> getSwitches(unsigned long node) const override;

stdcxx::range<Switch> getSwitches(unsigned long node) override;

stdcxx::CReference<Terminal> getTerminal(unsigned long node) const override;

stdcxx::Reference<Terminal> getTerminal(unsigned long node) override;
Expand Down
80 changes: 80 additions & 0 deletions test/iidm/NodeBreakerVoltageLevelTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1434,6 +1434,86 @@ BOOST_AUTO_TEST_CASE(testCalculatedBus) {
BOOST_CHECK(!network.getBusBreakerView().getBus("unknownBus"));
}

BOOST_AUTO_TEST_CASE(getSwitches) {
Network network("test", "test");
Substation& s = network.newSubstation()
.setId("S")
.setCountry(Country::FR)
.add();
VoltageLevel& vl = s.newVoltageLevel()
.setId("VL")
.setNominalV(400.0)
.setTopologyKind(TopologyKind::NODE_BREAKER)
.add();
vl.getNodeBreakerView().newBusbarSection()
.setId("BBS1")
.setNode(0)
.add();
vl.getNodeBreakerView().newBusbarSection()
.setId("BBS2")
.setNode(1)
.add();
vl.getNodeBreakerView().newBreaker()
.setId("C")
.setNode1(1)
.setNode2(0)
.setOpen(true)
.add();
vl.getNodeBreakerView().newBreaker()
.setId("B2")
.setNode1(0)
.setNode2(2)
.setOpen(true)
.add();
vl.getNodeBreakerView().newBreaker()
.setId("B1")
.setNode1(2)
.setNode2(3)
.setOpen(false)
.add();
vl.getNodeBreakerView().newBreaker()
.setId("B3")
.setNode1(3)
.setNode2(1)
.setOpen(false)
.add();
vl.newLoad()
.setId("LD")
.setNode(2)
.setP0(1)
.setQ0(1)
.add();

vl.getNodeBreakerView().newInternalConnection().setNode1(2).setNode2(0).add();
vl.getNodeBreakerView().newInternalConnection().setNode1(0).setNode2(1).add();
vl.getNodeBreakerView().newInternalConnection().setNode1(3).setNode2(0).add();

const VoltageLevel& cVl = vl;

auto switches = vl.getNodeBreakerView().getSwitches(0);
const auto& cSwitches = cVl.getNodeBreakerView().getSwitches(0);
BOOST_CHECK_EQUAL(2, boost::size(switches));
BOOST_CHECK_EQUAL(2, boost::size(cSwitches));

for (const std::string& name : {"C", "B2"}) {
const auto& lookup = [&name](const Switch& sw) {
return sw.getId() == name;
};
auto it = std::find_if(switches.begin(), switches.end(), lookup);
BOOST_CHECK(it != switches.end());
}

const auto& internalConnections = vl.getNodeBreakerView().getNodesInternalConnectedTo(0);
BOOST_CHECK_EQUAL(3, boost::size(internalConnections));
for (unsigned long expectedNode : {1, 2, 3}) {
const auto& lookup = [&expectedNode](unsigned long node) {
return node == expectedNode;
};
const auto& it = std::find_if(internalConnections.begin(), internalConnections.end(), lookup);
BOOST_CHECK(it != internalConnections.end());
}
}

BOOST_AUTO_TEST_SUITE_END()

} // namespace iidm
Expand Down
53 changes: 52 additions & 1 deletion test/math/UndirectedGraphTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ BOOST_AUTO_TEST_CASE(getEdgeObject) {
graph.addVertex();
graph.addEdge(0, 1, stdcxx::ref(expected));

const stdcxx::Reference<E>& edge = graph.getEdgeObject(0);
stdcxx::Reference<E> edge = graph.getEdgeObject(0);
BOOST_TEST(stdcxx::areSame(expected, edge.get()));

const auto& objects = graph.getEdgeObjects();
Expand Down Expand Up @@ -348,6 +348,57 @@ BOOST_AUTO_TEST_CASE(traverse) {
BOOST_CHECK_EQUAL_COLLECTIONS(encountered.begin(), encountered.end(), encounteredExpected3.begin(), encounteredExpected3.end());
}

BOOST_AUTO_TEST_CASE(testGetEdgesFromVertex) {
UndirectedGraph<V, E> graph;
graph.addVertex();
graph.addVertex();
graph.addVertex();
graph.addEdge(0, 1, stdcxx::ref<E>());
graph.addEdge(1, 2, stdcxx::ref<E>());

const std::vector<unsigned long>& connectedTo1Ref = {0UL, 1UL};
const std::vector<unsigned long>& connectedTo1 = graph.getEdgesConnectedToVertex(1);
BOOST_CHECK_EQUAL_COLLECTIONS(connectedTo1Ref.begin(), connectedTo1Ref.end(), connectedTo1.begin(), connectedTo1.end());

const std::vector<unsigned long>& connectedTo0Ref = {0UL};
const std::vector<unsigned long>& connectedTo0 = graph.getEdgesConnectedToVertex(0);
BOOST_CHECK_EQUAL_COLLECTIONS(connectedTo0Ref.begin(), connectedTo0Ref.end(), connectedTo0.begin(), connectedTo0.end());
}

BOOST_AUTO_TEST_CASE(testGetEdgeObjectFromVertex) {
UndirectedGraph<V, E> graph;
graph.addVertex();
graph.addVertex();
graph.addVertex();

E arrow01("Arrow01");
E arrow12("Arrow12");
graph.addEdge(0, 1, stdcxx::ref(arrow01));
graph.addEdge(1, 2, stdcxx::ref(arrow12));

const auto& connectedTo0 = graph.getEdgeObjectsConnectedToVertex(0);
BOOST_CHECK_EQUAL(1, boost::size(connectedTo0));
std::vector<std::string> refConnectedTo0 = {"Arrow01"};
for (const std::string& name : refConnectedTo0) {
const auto& lookup = [&name](const stdcxx::Reference<E>& edge) {
return edge.get().getName() == name;
};
auto it = std::find_if(connectedTo0.begin(), connectedTo0.end(), lookup);
BOOST_CHECK(it != connectedTo0.end());
}

const auto& connectedTo1 = graph.getEdgeObjectsConnectedToVertex(1);
BOOST_CHECK_EQUAL(2, boost::size(connectedTo1));
std::vector<std::string> refConnectedTo1 = {"Arrow01", "Arrow12"};
for (const std::string& name : refConnectedTo1) {
const auto& lookup = [&name](const stdcxx::Reference<E>& edge) {
return edge.get().getName() == name;
};
auto it = std::find_if(connectedTo1.begin(), connectedTo1.end(), lookup);
BOOST_CHECK(it != connectedTo1.end());
}
}

BOOST_AUTO_TEST_SUITE_END()

} // namespace math
Expand Down