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)
76 auto powerComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp);
78 for (
auto topoNode : powerComp->topologicalNodes())
84 for (
auto comp : components)
91 for (
auto nodePF : systemPF.
mNodes) {
95 node->setInitialVoltage(
104 if (
auto genPF = std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
110 auto terminal = comp->terminals()[0];
111 terminal->setPower(-genPF->getApparentPower());
116 auto terminal = comp->terminals()[0];
117 terminal->setPower(-genPF->getApparentPower());
125 if (
auto powerCompComplex =
129 if (
auto powerCompReal =
138 for (
auto comp : components)
142template <
typename Type>
144 if (index <
mNodes.size()) {
145 auto topoNode =
mNodes[index];
146 auto node = std::dynamic_pointer_cast<Type>(topoNode);
154template <
typename Type>
156 for (
auto topoNode :
mNodes) {
157 if (topoNode->name() == name) {
158 auto node = std::dynamic_pointer_cast<Type>(topoNode);
169 std::map<String, String, std::less<>> objTypeMap;
172 objTypeMap[
node->name()] =
node->type();
175 objTypeMap[comp->name()] = comp->type();
180template <
typename VarType>
181void SystemTopology::multiplyPowerComps(
Int numberCopies) {
185 for (
int copy = 0; copy < numberCopies; copy++) {
186 std::unordered_map<typename SimNode<VarType>::Ptr,
189 String copySuffix =
"_" + std::to_string(copy + 2);
193 for (
size_t nNode = 0; nNode <
mNodes.size(); nNode++) {
200 nodeMap[nodePtr] = nodePtr;
205 nodeMap[nodePtr] = nodeCpy;
206 newNodes.push_back(nodeCpy);
212 auto comp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(genComp);
215 auto copy = comp->clone(comp->name() + copySuffix);
217 throw SystemError(
"copy() not implemented for " + comp->name());
221 for (
UInt nNode = 0; nNode < comp->terminalNumber(); nNode++) {
222 nodeCopies.push_back(nodeMap[comp->node(nNode)]);
224 copy->connect(nodeCopies);
227 for (
UInt nTerminal = 0; nTerminal < comp->terminalNumber();
229 copy->terminal(nTerminal)->setPower(comp->terminal(nTerminal)->power());
231 newComponents.push_back(copy);
234 for (
auto node : newNodes)
236 for (
auto comp : newComponents)
242 multiplyPowerComps<Real>(numCopies);
243 multiplyPowerComps<Complex>(numCopies);
255 if ((*it)->name() == name) {
270 auto powerComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp);
275 const auto terminals = powerComp->topologicalTerminals();
276 return std::any_of(terminals.begin(), terminals.end(),
278 return terminal && terminal->topologicalNodes() == node;
282void SystemTopology::removeComponentsConnectedTo(
288 removedComponents.push_back(*it);
297 for (
const auto &removed : removedComponents) {
307 if ((*it)->name() == name && !(*it)->isGround()) {
308 removeComponentsConnectedTo(*it);
316template <
typename VarType>
318 std::unordered_map<typename SimNode<VarType>::Ptr,
int> subnet;
320 if (numberSubnets == 1) {
321 splitSystems.push_back(*
this);
323 std::vector<IdentifiedObject::List> components(numberSubnets);
324 std::vector<TopologicalNode::List> nodes(numberSubnets);
328 auto pnode = std::dynamic_pointer_cast<SimNode<VarType>>(
node);
329 if (!pnode ||
node->isGround())
332 nodes[subnet[pnode]].push_back(
node);
337 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
344 components[0].push_back(comp);
347 for (
UInt nodeIdx = 0; nodeIdx < pcomp->terminalNumber(); nodeIdx++) {
348 if (!pcomp->node(nodeIdx)->isGround()) {
349 components[subnet[pcomp->node(nodeIdx)]].push_back(comp);
354 for (
int currentNet = 0; currentNet < numberSubnets; currentNet++) {
356 components[currentNet]);
361template <
typename VarType>
364 std::unordered_map<typename SimNode<VarType>::Ptr,
369 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
373 for (
UInt nodeIdx1 = 0; nodeIdx1 < pcomp->terminalNumberConnected();
375 for (
UInt nodeIdx2 = 0; nodeIdx2 < nodeIdx1; nodeIdx2++) {
376 auto node1 = pcomp->node(nodeIdx1);
377 auto node2 = pcomp->node(nodeIdx2);
378 if (node1->isGround() || node2->isGround())
381 neighbours[node1].push_back(node2);
382 neighbours[node2].push_back(node1);
388 size_t totalNodes =
mNodes.size();
389 for (
auto tnode :
mNodes) {
390 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
391 if (!
node || tnode->isGround()) {
396 while (subnet.size() != totalNodes) {
397 std::list<typename SimNode<VarType>::Ptr> nextSet;
399 for (
auto tnode :
mNodes) {
400 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
401 if (!
node || tnode->isGround())
404 if (subnet.find(
node) == subnet.end()) {
405 nextSet.push_back(
node);
409 while (!nextSet.empty()) {
410 auto node = nextSet.front();
413 subnet[
node] = currentNet;
414 for (
auto neighbour : neighbours[
node]) {
415 if (subnet.find(neighbour) == subnet.end())
416 nextSet.push_back(neighbour);
431 g.set(
"splines",
"polyline");
434 n = g.addNode(
node->uid());
436 std::stringstream label, tooltip;
438 tooltip <<
node->uid();
440 label <<
"<FONT POINT-SIZE=\"12\"><B>" <<
node->name()
441 <<
"</B></FONT><BR/>";
443 double phase = 180.0 /
M_PI * std::arg(
node->initialSingleVoltage());
444 double mag = std::abs(
node->initialSingleVoltage());
446 const char *suffixes[] = {
"",
"k",
"M",
"G"};
449 for (s = 0; s < 3 && mag > 1000; s++)
452 if (
node->initialSingleVoltage() !=
Complex(0, 0)) {
453 label << std::setprecision(2) << std::fixed;
454 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">";
455 label <<
"(" << mag <<
" " << suffixes[s] <<
"V > " << phase <<
"°)";
459 n->
set(
"xlabel", label.str(),
true);
460 n->
set(
"tooltip", tooltip.str(),
true);
461 n->
set(
"fillcolor", phase == 0 ?
"red" :
"black");
462 n->
set(
"fixedsize",
"true");
463 n->
set(
"width",
"0.15");
464 n->
set(
"height",
"0.15");
465 n->
set(
"shape",
"point");
468 std::map<String, String> compColorMap;
476 if (!(topoComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp)))
479 c = g.addNode(topoComp->uid());
481 auto type = topoComp->type();
482 auto name = topoComp->name();
484 std::stringstream label, tooltip;
486 label <<
"<FONT POINT-SIZE=\"12\"><B>" << name <<
"</B></FONT><BR/>";
487 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">" << type
489 if (topoComp->description() !=
"") {
490 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">"
491 << topoComp->description() <<
"</FONT>";
494 tooltip <<
"Attributes:";
495 for (
auto it : topoComp->attributes()) {
496 tooltip << std::endl << it.first <<
": " << it.second->toString();
499 if (compColorMap.find(type) != compColorMap.end()) {
501 String(
"/paired9/") + std::to_string(1 + compColorMap.size() % 9);
504 c->
set(
"color", compColorMap[type]);
505 c->
set(
"label", label.str(),
true);
506 c->
set(
"tooltip", tooltip.str(),
true);
507 c->
set(
"style",
"rounded,filled,bold");
509 if (type.find(
"Line") == std::string::npos) {
510 c->
set(
"shape",
"rectangle");
511 c->
set(
"fillcolor",
"gray93");
513 c->
set(
"shape",
"plaintext");
514 c->
set(
"fillcolor",
"transparent");
517 for (
auto term : topoComp->topologicalTerminals()) {
518 n = g.node(term->topologicalNodes()->uid());
522 g.addEdge(term->uid(), c, n);
529String SystemTopology::render() {
530 auto graph = this->topologyGraph();
531 std::stringstream ss;
532 graph.render(ss,
"neato",
"svg");
537void SystemTopology::renderToFile(
String filename) {
538 std::ofstream ofstr(filename);
539 this->topologyGraph().render(ofstr,
"neato",
"svg");
544template void SystemTopology::multiplyPowerComps<Real>(
Int numberCopies);
545template void SystemTopology::multiplyPowerComps<Complex>(
Int numberCopies);
546template std::shared_ptr<TopologicalNode>
548template std::shared_ptr<TopologicalNode>
550template std::shared_ptr<SimNode<Real>>
552template std::shared_ptr<SimNode<Complex>>
554template std::shared_ptr<SimNode<Real>>
556template std::shared_ptr<SimNode<Complex>>
565 std::unordered_map<
typename CPS::SimNode<Real>::Ptr,
int> &subnet);
567 std::unordered_map<
typename CPS::SimNode<Complex>::Ptr,
int> &subnet);
569 std::vector<CPS::SystemTopology> &splitSystems);
571 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