12#include <unordered_map>
21 frequencies << frequency;
28 if (
auto nodeReal = std::dynamic_pointer_cast<
SimNode<Real>>(topNode))
37 if (
auto nodeReal = std::dynamic_pointer_cast<
SimNode<Real>>(topNode))
40 if (index >
mNodes.capacity())
47 for (
auto topNode : topNodes)
52 if (
auto powerCompComplex =
55 if (
auto powerCompReal =
62template <
typename VarType>
67 for (
auto simNode : simNodes)
73 auto powerComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp);
75 for (
auto topoNode : powerComp->topologicalNodes())
81 for (
auto comp : components)
88 for (
auto nodePF : systemPF.
mNodes) {
92 node->setInitialVoltage(
101 if (
auto genPF = std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
105 auto terminal = comp->terminals()[0];
106 terminal->setPower(-genPF->getApparentPower());
109 auto terminal = comp->terminals()[0];
110 terminal->setPower(-genPF->getApparentPower());
118 if (
auto powerCompComplex =
122 if (
auto powerCompReal =
131 for (
auto comp : components)
135template <
typename Type>
137 if (index <
mNodes.size()) {
138 auto topoNode =
mNodes[index];
139 auto node = std::dynamic_pointer_cast<Type>(topoNode);
147template <
typename Type>
149 for (
auto topoNode :
mNodes) {
150 if (topoNode->name() == name) {
151 auto node = std::dynamic_pointer_cast<Type>(topoNode);
162 std::map<String, String, std::less<>> objTypeMap;
165 objTypeMap[
node->name()] =
node->type();
168 objTypeMap[comp->name()] = comp->type();
173template <
typename VarType>
174void SystemTopology::multiplyPowerComps(
Int numberCopies) {
178 for (
int copy = 0; copy < numberCopies; copy++) {
179 std::unordered_map<typename SimNode<VarType>::Ptr,
182 String copySuffix =
"_" + std::to_string(copy + 2);
186 for (
size_t nNode = 0; nNode <
mNodes.size(); nNode++) {
193 nodeMap[nodePtr] = nodePtr;
198 nodeMap[nodePtr] = nodeCpy;
199 newNodes.push_back(nodeCpy);
205 auto comp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(genComp);
208 auto copy = comp->clone(comp->name() + copySuffix);
210 throw SystemError(
"copy() not implemented for " + comp->name());
214 for (
UInt nNode = 0; nNode < comp->terminalNumber(); nNode++) {
215 nodeCopies.push_back(nodeMap[comp->node(nNode)]);
217 copy->connect(nodeCopies);
220 for (
UInt nTerminal = 0; nTerminal < comp->terminalNumber();
222 copy->terminal(nTerminal)->setPower(comp->terminal(nTerminal)->power());
224 newComponents.push_back(copy);
227 for (
auto node : newNodes)
229 for (
auto comp : newComponents)
235 multiplyPowerComps<Real>(numCopies);
236 multiplyPowerComps<Complex>(numCopies);
248 if ((*it)->name() == name) {
252 comps.erase(std::remove(comps.begin(), comps.end(), *it), comps.end());
266 auto powerComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp);
271 const auto terminals = powerComp->topologicalTerminals();
272 return std::any_of(terminals.begin(), terminals.end(),
274 return terminal && terminal->topologicalNodes() == node;
278void SystemTopology::removeComponentsConnectedTo(
284 removedComponents.push_back(*it);
294 for (
const auto &removed : removedComponents) {
295 comps.erase(std::remove(comps.begin(), comps.end(), removed),
300 for (
const auto &removed : removedComponents) {
310 if ((*it)->name() == name && !(*it)->isGround()) {
311 removeComponentsConnectedTo(*it);
320template <
typename VarType>
322 std::unordered_map<typename SimNode<VarType>::Ptr,
int> subnet;
324 if (numberSubnets == 1) {
325 splitSystems.push_back(*
this);
327 std::vector<IdentifiedObject::List> components(numberSubnets);
328 std::vector<TopologicalNode::List> nodes(numberSubnets);
332 auto pnode = std::dynamic_pointer_cast<SimNode<VarType>>(
node);
333 if (!pnode ||
node->isGround())
336 nodes[subnet[pnode]].push_back(
node);
341 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
348 components[0].push_back(comp);
351 for (
UInt nodeIdx = 0; nodeIdx < pcomp->terminalNumber(); nodeIdx++) {
352 if (!pcomp->node(nodeIdx)->isGround()) {
353 components[subnet[pcomp->node(nodeIdx)]].push_back(comp);
358 for (
int currentNet = 0; currentNet < numberSubnets; currentNet++) {
360 components[currentNet]);
365template <
typename VarType>
368 std::unordered_map<typename SimNode<VarType>::Ptr,
373 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
377 for (
UInt nodeIdx1 = 0; nodeIdx1 < pcomp->terminalNumberConnected();
379 for (
UInt nodeIdx2 = 0; nodeIdx2 < nodeIdx1; nodeIdx2++) {
380 auto node1 = pcomp->node(nodeIdx1);
381 auto node2 = pcomp->node(nodeIdx2);
382 if (node1->isGround() || node2->isGround())
385 neighbours[node1].push_back(node2);
386 neighbours[node2].push_back(node1);
392 size_t totalNodes =
mNodes.size();
393 for (
auto tnode :
mNodes) {
394 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
395 if (!
node || tnode->isGround()) {
400 while (subnet.size() != totalNodes) {
401 std::list<typename SimNode<VarType>::Ptr> nextSet;
403 for (
auto tnode :
mNodes) {
404 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
405 if (!
node || tnode->isGround())
408 if (subnet.find(
node) == subnet.end()) {
409 nextSet.push_back(
node);
413 while (!nextSet.empty()) {
414 auto node = nextSet.front();
417 subnet[
node] = currentNet;
418 for (
auto neighbour : neighbours[
node]) {
419 if (subnet.find(neighbour) == subnet.end())
420 nextSet.push_back(neighbour);
435 g.set(
"splines",
"polyline");
438 n = g.addNode(
node->uid());
440 std::stringstream label, tooltip;
442 tooltip <<
node->uid();
444 label <<
"<FONT POINT-SIZE=\"12\"><B>" <<
node->name()
445 <<
"</B></FONT><BR/>";
447 double phase = 180.0 /
M_PI * std::arg(
node->initialSingleVoltage());
448 double mag = std::abs(
node->initialSingleVoltage());
450 const char *suffixes[] = {
"",
"k",
"M",
"G"};
453 for (s = 0; s < 3 && mag > 1000; s++)
456 if (
node->initialSingleVoltage() !=
Complex(0, 0)) {
457 label << std::setprecision(2) << std::fixed;
458 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">";
459 label <<
"(" << mag <<
" " << suffixes[s] <<
"V > " << phase <<
"°)";
463 n->
set(
"xlabel", label.str(),
true);
464 n->
set(
"tooltip", tooltip.str(),
true);
465 n->
set(
"fillcolor", phase == 0 ?
"red" :
"black");
466 n->
set(
"fixedsize",
"true");
467 n->
set(
"width",
"0.15");
468 n->
set(
"height",
"0.15");
469 n->
set(
"shape",
"point");
472 std::map<String, String> compColorMap;
480 if (!(topoComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp)))
483 c = g.addNode(topoComp->uid());
485 auto type = topoComp->type();
486 auto name = topoComp->name();
488 std::stringstream label, tooltip;
490 label <<
"<FONT POINT-SIZE=\"12\"><B>" << name <<
"</B></FONT><BR/>";
491 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">" << type
493 if (topoComp->description() !=
"") {
494 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">"
495 << topoComp->description() <<
"</FONT>";
498 tooltip <<
"Attributes:";
499 for (
auto it : topoComp->attributes()) {
500 tooltip << std::endl << it.first <<
": " << it.second->toString();
503 if (compColorMap.find(type) != compColorMap.end()) {
505 String(
"/paired9/") + std::to_string(1 + compColorMap.size() % 9);
508 c->
set(
"color", compColorMap[type]);
509 c->
set(
"label", label.str(),
true);
510 c->
set(
"tooltip", tooltip.str(),
true);
511 c->
set(
"style",
"rounded,filled,bold");
513 if (type.find(
"Line") == std::string::npos) {
514 c->
set(
"shape",
"rectangle");
515 c->
set(
"fillcolor",
"gray93");
517 c->
set(
"shape",
"plaintext");
518 c->
set(
"fillcolor",
"transparent");
521 for (
auto term : topoComp->topologicalTerminals()) {
522 n = g.node(term->topologicalNodes()->uid());
526 g.addEdge(term->uid(), c, n);
533String SystemTopology::render() {
534 auto graph = this->topologyGraph();
535 std::stringstream ss;
536 graph.render(ss,
"neato",
"svg");
541void SystemTopology::renderToFile(
String filename) {
542 std::ofstream ofstr(filename);
543 this->topologyGraph().render(ofstr,
"neato",
"svg");
548template void SystemTopology::multiplyPowerComps<Real>(
Int numberCopies);
549template void SystemTopology::multiplyPowerComps<Complex>(
Int numberCopies);
550template std::shared_ptr<TopologicalNode>
552template std::shared_ptr<TopologicalNode>
554template std::shared_ptr<SimNode<Real>>
556template std::shared_ptr<SimNode<Complex>>
558template std::shared_ptr<SimNode<Real>>
560template std::shared_ptr<SimNode<Complex>>
569 std::unordered_map<
typename CPS::SimNode<Real>::Ptr,
int> &subnet);
571 std::unordered_map<
typename CPS::SimNode<Complex>::Ptr,
int> &subnet);
573 std::vector<CPS::SystemTopology> &splitSystems);
575 std::vector<CPS::SystemTopology> &splitSystems);
static bool isConnectedTo(const IdentifiedObject::Ptr &comp, const TopologicalNode::Ptr &node)
void set(const String &key, const String &value, bool html=false)
std::shared_ptr< IdentifiedObject > Ptr
std::shared_ptr< SimNode< VarType > > Ptr
Base class for all components that are transmitting power.
std::shared_ptr< SimPowerComp< VarType > > Ptr
void removeNode(const String &name)
Remove node and all components connected to it.
void addNodes(const TopologicalNode::List &topNodes)
Add multiple nodes.
Real mSystemFrequency
System frequency.
IdentifiedObject::List mComponents
List of network components.
std::shared_ptr< Type > node(UInt index)
Returns TopologicalNode by index in node list.
void initWithPowerflow(const SystemTopology &systemPF, CPS::Domain domain)
Initialize nodes and SG power from PowerFlow.
void removeComponent(const String &name)
Remove system component.
void addNode(TopologicalNode::Ptr topNode)
Adds node and initializes frequencies.
std::map< String, String, std::less<> > listIdObjects() const
void addTearComponent(IdentifiedObject::Ptr component)
Adds component and initializes frequencies.
std::shared_ptr< Type > component(const String &name)
Returns Component by name.
void componentsAtNodeList()
TopologicalNode::List mNodes
List of network nodes.
Matrix initFrequency(Real frequency) const
void reset()
Reset state of components.
void addNodeAt(TopologicalNode::Ptr topNode, UInt index)
Adds node at specified position and initializes frequencies.
void addComponents(const IdentifiedObject::List &components)
Add multiple components.
Matrix mFrequencies
List of considered network frequencies.
void connectComponentToNodes(typename SimPowerComp< VarType >::Ptr component, typename SimNode< VarType >::List simNodes)
Connect component to simNodes.
void addComponent(IdentifiedObject::Ptr component)
Adds component and initializes frequencies.
void multiply(Int numberCopies)
Copy the whole topology the given number of times and add the resulting components and nodes to the t...
void splitSubnets(std::vector< CPS::SystemTopology > &splitSystems)
IdentifiedObject::List mTearComponents
SystemTopology()
Do not use this constructor.
void addTearComponents(const IdentifiedObject::List &components)
Add multiple components.
int checkTopologySubnets(std::unordered_map< typename CPS::SimNode< VarType >::Ptr, int > &subnet)
std::map< TopologicalNode::Ptr, TopologicalPowerComp::List > mComponentsAtNode
Map of network components connected to network nodes.
PhaseType phaseType() const
std::shared_ptr< TopologicalNode > Ptr
MatrixComp initialVoltage() const
std::shared_ptr< TopologicalPowerComp > Ptr
std::shared_ptr< TopologicalTerminal > Ptr
static std::shared_ptr< SimNode< VarType > > make(Args &&...args)
Eigen::Matrix< Real, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor > Matrix
Dense matrix for real numbers.
std::complex< Real > Complex