Skip to content

Commit

Permalink
Add the ability to move a Connectable (#382)
Browse files Browse the repository at this point in the history
Signed-off-by: Sébastien LAIGRE <[email protected]>
  • Loading branch information
sebalaig committed May 24, 2022
1 parent 5ceda95 commit a5cc01a
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 0 deletions.
25 changes: 25 additions & 0 deletions include/powsybl/iidm/Connectable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ namespace iidm {

class Network;

namespace bus_terminal {

class BusBreakerViewImpl;

} // namespace bus_terminal

namespace node_terminal {

class BusBreakerViewImpl;
class NodeBreakerViewImpl;

} // namespace node_terminal

class Connectable : public Identifiable {
public: // Identifiable
const Network& getNetwork() const override;
Expand Down Expand Up @@ -54,6 +67,18 @@ class Connectable : public Identifiable {

Terminal& getTerminal(unsigned long index);

void move(Terminal& oldTerminal, const std::string& oldConnectionInfo, const std::string& busId, bool connected);

void move(Terminal& oldTerminal, const std::string& oldConnectionInfo, unsigned long node, const std::string& voltageLevelId);

private:
void attachTerminal(Terminal& oldTerminal, const std::string& oldConnectionInfo, VoltageLevel& voltageLevel, std::unique_ptr<Terminal>&& terminal);

friend class bus_terminal::BusBreakerViewImpl;

friend class node_terminal::BusBreakerViewImpl;
friend class node_terminal::NodeBreakerViewImpl;

private:
ConnectableType m_connectableType;

Expand Down
2 changes: 2 additions & 0 deletions include/powsybl/iidm/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class Terminal : public MultiVariantObject {

stdcxx::Reference<Connectable> getConnectable();

virtual const std::string& getConnectionInfo() const = 0;

double getI() const;

virtual const NodeBreakerView& getNodeBreakerView() const = 0;
Expand Down
4 changes: 4 additions & 0 deletions include/powsybl/iidm/TerminalViews.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class BusBreakerView {
virtual stdcxx::Reference<Bus> getConnectableBus() = 0;

virtual void setConnectableBus(const std::string& busId) = 0;

virtual void moveConnectable(const std::string& busId, bool connected) = 0;
};

class BusView {
Expand All @@ -51,6 +53,8 @@ class NodeBreakerView {
virtual ~NodeBreakerView() noexcept = default;

virtual unsigned long getNode() const = 0;

virtual void moveConnectable(unsigned long node, const std::string& voltageLevelId) = 0;
};

} // namespace terminal
Expand Down
5 changes: 5 additions & 0 deletions src/iidm/BusTerminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ BusTerminal::BusView& BusTerminal::getBusView() {
return m_busView;
}

const std::string& BusTerminal::getConnectionInfo() const {
static std::string s_connectionInfo = stdcxx::format("bus %1%, %2%", getBusBreakerView().getConnectableBus().get().getId(), getBusBreakerView().getBus() ? "connected" : "disconnected");
return s_connectionInfo;
}

const BusTerminal::NodeBreakerView& BusTerminal::getNodeBreakerView() const {
throw AssertionError("Not implemented");
}
Expand Down
2 changes: 2 additions & 0 deletions src/iidm/BusTerminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class BusTerminal : public Terminal {

BusView& getBusView() override;

const std::string& getConnectionInfo() const override;

const NodeBreakerView& getNodeBreakerView() const override;

NodeBreakerView& getNodeBreakerView() override;
Expand Down
4 changes: 4 additions & 0 deletions src/iidm/BusTerminalViews.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ stdcxx::Reference<Bus> BusBreakerViewImpl::getConnectableBus() {
return stdcxx::ref<Bus>(voltageLevel.getConfiguredBus(m_terminal.getConnectableBusId(), true));
}

void BusBreakerViewImpl::moveConnectable(const std::string& busId, bool connected) {
m_terminal.getConnectable().get().move(m_terminal, m_terminal.getConnectionInfo(), busId, connected);
}

void BusBreakerViewImpl::setConnectableBus(const std::string& busId) {
checkNotEmpty(busId, "busId is empty");

Expand Down
2 changes: 2 additions & 0 deletions src/iidm/BusTerminalViews.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class BusBreakerViewImpl : public terminal::BusBreakerView {

stdcxx::Reference<Bus> getConnectableBus() override;

void moveConnectable(const std::string& busId, bool connected) override;

void setConnectableBus(const std::string& busId) override;

public:
Expand Down
59 changes: 59 additions & 0 deletions src/iidm/Connectable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <powsybl/iidm/Connectable.hpp>

#include <powsybl/iidm/Network.hpp>
#include <powsybl/iidm/TerminalBuilder.hpp>
#include <powsybl/iidm/VoltageLevel.hpp>

namespace powsybl {
Expand All @@ -34,6 +35,21 @@ Terminal& Connectable::addTerminal(std::unique_ptr<Terminal>&& terminal) {
return *m_terminals.back();
}

void Connectable::attachTerminal(Terminal& oldTerminal, const std::string& /*oldConnectionInfo*/, VoltageLevel& voltageLevel, std::unique_ptr<Terminal>&& terminal) {
// first, attach new terminal to connectable and to voltage level of destination, to ensure that the new terminal is valid
terminal->setConnectable(stdcxx::ref(*this));
voltageLevel.attach(*terminal, false);

// then we can detach the old terminal, as we now know that the new terminal is valid
oldTerminal.getVoltageLevel().detach(oldTerminal);

// replace the old terminal by the new terminal in the connectable
auto it = std::find_if(m_terminals.begin(), m_terminals.end(), [&oldTerminal](const std::unique_ptr<Terminal>& term) {
return stdcxx::areSame(*term, oldTerminal);
});
*it = std::move(terminal);
}

void Connectable::deleteVariantArrayElement(unsigned long index) {
Identifiable::deleteVariantArrayElement(index);

Expand Down Expand Up @@ -84,6 +100,49 @@ std::vector<std::reference_wrapper<Terminal> > Connectable::getTerminals() const
return terminals;
}

void Connectable::move(Terminal& oldTerminal, const std::string& oldConnectionInfo, const std::string& busId, bool connected) {
const auto& bus = getNetwork().getBusBreakerView().getBus(busId);
if (!bus) {
throw PowsyblException(stdcxx::format("Bus '%1%' not found", busId));
}

// check bus topology
if (bus.get().getVoltageLevel().getTopologyKind() != TopologyKind::BUS_BREAKER) {
throw PowsyblException(stdcxx::format("Trying to move connectable %s to bus %s of voltage level %s, which is a node breaker voltage level",
getId(), bus.get().getId(), bus.get().getVoltageLevel().getId()));
}

// create the new terminal and attach it to the voltage level of the given bus and links it to the connectable
std::unique_ptr<Terminal> terminalExt = TerminalBuilder(bus.get().getVoltageLevel(), *this)
.setBus(connected ? bus.get().getId() : "")
.setConnectableBus(bus.get().getId())
.build();

// detach the terminal from its previous voltage level
attachTerminal(oldTerminal, oldConnectionInfo, bus.get().getVoltageLevel(), std::move(terminalExt));
}

void Connectable::move(Terminal& oldTerminal, const std::string& oldConnectionInfo, unsigned long node, const std::string& voltageLevelId) {
const auto& voltageLevel = getNetwork().find<VoltageLevel>(voltageLevelId);
if (! voltageLevel) {
throw PowsyblException(stdcxx::format("Voltage level '%1%' not found", voltageLevelId));
}

// check bus topology
if (voltageLevel.get().getTopologyKind() != TopologyKind::NODE_BREAKER) {
const std::string& msg = stdcxx::format("Trying to move connectable %1% to node %2% of voltage level %3%, which is a bus breaker voltage level", getId(), node, voltageLevel.get().getId());
throw PowsyblException(msg);
}

// create the new terminal and attach it to the given voltage level and to the connectable
std::unique_ptr<Terminal> terminalExt = TerminalBuilder(voltageLevel, *this)
.setNode(node)
.build();

// detach the terminal from its previous voltage level
attachTerminal(oldTerminal, oldConnectionInfo, voltageLevel, std::move(terminalExt));
}

void Connectable::reduceVariantArraySize(unsigned long number) {
Identifiable::reduceVariantArraySize(number);

Expand Down
5 changes: 5 additions & 0 deletions src/iidm/NodeTerminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ const stdcxx::optional<unsigned long>& NodeTerminal::getConnectedComponentNumber
return m_connectedComponentNumber[getNetwork().getVariantIndex()];
}

const std::string& NodeTerminal::getConnectionInfo() const {
static std::string s_connectionInfo = stdcxx::format("bus %1%, %2%", getBusBreakerView().getConnectableBus().get().getId(), getBusBreakerView().getBus() ? "connected" : "disconnected");
return s_connectionInfo;
}

unsigned long NodeTerminal::getNode() const {
return m_node;
}
Expand Down
2 changes: 2 additions & 0 deletions src/iidm/NodeTerminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class NodeTerminal : public Terminal {

BusView& getBusView() override;

const std::string& getConnectionInfo() const override;

const NodeBreakerView& getNodeBreakerView() const override;

NodeBreakerView& getNodeBreakerView() override;
Expand Down
8 changes: 8 additions & 0 deletions src/iidm/NodeTerminalViews.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ stdcxx::Reference<Bus> BusBreakerViewImpl::getConnectableBus() {
return voltageLevel.getCalculatedBusBreakerTopology().getConnectableBus(m_terminal.getNode());
}

void BusBreakerViewImpl::moveConnectable(const std::string& busId, bool connected) {
m_terminal.getConnectable().get().move(m_terminal, m_terminal.getConnectionInfo(), busId, connected);
}

void BusBreakerViewImpl::setConnectableBus(const std::string& /*busId*/) {
throw AssertionError("Not implemented");
}
Expand Down Expand Up @@ -84,6 +88,10 @@ unsigned long NodeBreakerViewImpl::getNode() const {
return m_terminal.getNode();
}

void NodeBreakerViewImpl::moveConnectable(unsigned long node, const std::string& voltageLevelId) {
m_terminal.getConnectable().get().move(m_terminal, m_terminal.getConnectionInfo(), node, voltageLevelId);
}

} // namespace node_terminal

} // namespace iidm
Expand Down
4 changes: 4 additions & 0 deletions src/iidm/NodeTerminalViews.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class BusBreakerViewImpl : public terminal::BusBreakerView {

stdcxx::Reference<Bus> getConnectableBus() override;

void moveConnectable(const std::string& busId, bool connected) override;

void setConnectableBus(const std::string& busId) override;

public:
Expand Down Expand Up @@ -62,6 +64,8 @@ class NodeBreakerViewImpl : public terminal::NodeBreakerView {
public: // NodeBreakerView
unsigned long getNode() const override;

void moveConnectable(unsigned long node, const std::string& voltageLevelId) override;

public:
explicit NodeBreakerViewImpl(NodeTerminal& terminal);

Expand Down
14 changes: 14 additions & 0 deletions test/iidm/NetworkFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,20 @@ Network createMixedTopolyKindNetwork() {
.setQ0(40.0)
.add();

vl3.getBusBreakerView().newBus()
.setId("VL3_BUS2")
.add();

vl3.newLoad()
.setId("LOAD4")
.setBus("VL3_BUS2")
.setConnectableBus("VL3_BUS2")
.setName("LOAD4_NAME")
.setLoadType(LoadType::UNDEFINED)
.setP0(50.0)
.setQ0(40.0)
.add();

return network;
}

Expand Down
31 changes: 31 additions & 0 deletions test/iidm/TerminalTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@

#include <boost/test/unit_test.hpp>

#include <powsybl/PowsyblException.hpp>
#include <powsybl/iidm/Load.hpp>
#include <powsybl/iidm/Network.hpp>
#include <powsybl/iidm/Switch.hpp>
#include <powsybl/iidm/VoltageLevel.hpp>
#include <powsybl/test/AssertionUtils.hpp>

#include "NetworkFactory.hpp"

Expand Down Expand Up @@ -116,6 +118,35 @@ BOOST_AUTO_TEST_CASE(traverseNodeBreaker) {
BOOST_CHECK(partialTraverser.getTraversedSwitches().empty());
}

BOOST_AUTO_TEST_CASE(moveBbk) {
Network network = createMixedTopolyKindNetwork();
Load& load = network.getLoad("LOAD3");

POWSYBL_ASSERT_THROW(load.getTerminal().getBusBreakerView().moveConnectable("wrongBusId", true), PowsyblException, "Bus 'wrongBusId' not found");

BOOST_CHECK(load.getTerminal().isConnected());
load.getTerminal().getBusBreakerView().moveConnectable("VL3_BUS2", false);
BOOST_CHECK(!load.getTerminal().isConnected());

load.getTerminal().getBusBreakerView().moveConnectable("VL3_BUS2", true);
BOOST_CHECK(load.getTerminal().isConnected());
BOOST_CHECK_EQUAL("VL3_BUS2", load.getTerminal().getBusBreakerView().getBus().get().getId());
BOOST_CHECK_EQUAL("VL3_BUS2", load.getTerminal().getBusBreakerView().getConnectableBus().get().getId());
}

BOOST_AUTO_TEST_CASE(moveNbk) {
Network network = createMixedTopolyKindNetwork();
Load& load = network.getLoad("LOAD1");

BOOST_CHECK_EQUAL(2, load.getTerminal().getNodeBreakerView().getNode());

POWSYBL_ASSERT_THROW(load.getTerminal().getNodeBreakerView().moveConnectable(100, "wrongVoltageLevelId"), PowsyblException, "Voltage level 'wrongVoltageLevelId' not found");
POWSYBL_ASSERT_THROW(load.getTerminal().getNodeBreakerView().moveConnectable(100, "VL3"), PowsyblException, "Trying to move connectable LOAD1 to node 100 of voltage level VL3, which is a bus breaker voltage level");

load.getTerminal().getNodeBreakerView().moveConnectable(100, "VL2");
BOOST_CHECK_EQUAL(100, load.getTerminal().getNodeBreakerView().getNode());
}

BOOST_AUTO_TEST_SUITE_END()

} // namespace iidm
Expand Down

0 comments on commit a5cc01a

Please sign in to comment.