12#include <unordered_map>
14#include <dpsim-models/SP/SP_Ph1_SynchronGenerator.h>
15#include <dpsim-models/SystemTopology.h>
19Matrix SystemTopology::initFrequency(Real frequency)
const {
20 Matrix frequencies(1, 1);
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>
64 typename SimPowerComp<VarType>::Ptr
component,
65 typename SimNode<VarType>::List simNodes) {
67 for (
auto simNode : simNodes)
71void SystemTopology::componentsAtNodeList() {
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>(
103 if (domain == CPS::Domain::DP || domain == CPS::Domain::SP) {
105 auto terminal = comp->terminals()[0];
106 terminal->setPower(-genPF->getApparentPower());
107 }
else if (domain == CPS::Domain::EMT) {
109 auto terminal = comp->terminals()[0];
110 terminal->setPower(-genPF->getApparentPower());
118 if (
auto powerCompComplex =
122 if (
auto powerCompReal =
130 const IdentifiedObject::List &components) {
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);
161std::map<String, String, std::less<>> SystemTopology::listIdObjects()
const {
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) {
175 typename SimNode<VarType>::List newNodes;
176 typename SimPowerComp<VarType>::List newComponents;
178 for (
int copy = 0; copy < numberCopies; copy++) {
179 std::unordered_map<typename SimNode<VarType>::Ptr,
180 typename SimNode<VarType>::Ptr>
182 String copySuffix =
"_" + std::to_string(copy + 2);
185 typename SimNode<VarType>::Ptr nodePtr;
186 for (
size_t nNode = 0; nNode <
mNodes.size(); nNode++) {
192 if (nodePtr->isGround()) {
193 nodeMap[nodePtr] = nodePtr;
195 auto nodeCpy = SimNode<VarType>::make(nodePtr->name() + copySuffix,
196 nodePtr->phaseType());
197 nodeCpy->setInitialVoltage(nodePtr->initialVoltage());
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());
213 typename SimNode<VarType>::List nodeCopies;
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) {
257void SystemTopology::removeNode(
const String &name) {
260 if ((*it)->name() == name) {
268template <
typename VarType>
269void SystemTopology::splitSubnets(std::vector<SystemTopology> &splitSystems) {
270 std::unordered_map<typename SimNode<VarType>::Ptr,
int> subnet;
271 int numberSubnets = checkTopologySubnets<VarType>(subnet);
272 if (numberSubnets == 1) {
273 splitSystems.push_back(*
this);
275 std::vector<IdentifiedObject::List> components(numberSubnets);
276 std::vector<TopologicalNode::List> nodes(numberSubnets);
280 auto pnode = std::dynamic_pointer_cast<SimNode<VarType>>(
node);
281 if (!pnode ||
node->isGround())
284 nodes[subnet[pnode]].push_back(
node);
289 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
296 components[0].push_back(comp);
299 for (UInt nodeIdx = 0; nodeIdx < pcomp->terminalNumber(); nodeIdx++) {
300 if (!pcomp->node(nodeIdx)->isGround()) {
301 components[subnet[pcomp->node(nodeIdx)]].push_back(comp);
306 for (
int currentNet = 0; currentNet < numberSubnets; currentNet++) {
308 components[currentNet]);
313template <
typename VarType>
314int SystemTopology::checkTopologySubnets(
315 std::unordered_map<
typename SimNode<VarType>::Ptr,
int> &subnet) {
316 std::unordered_map<typename SimNode<VarType>::Ptr,
317 typename SimNode<VarType>::List>
321 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
325 for (UInt nodeIdx1 = 0; nodeIdx1 < pcomp->terminalNumberConnected();
327 for (UInt nodeIdx2 = 0; nodeIdx2 < nodeIdx1; nodeIdx2++) {
328 auto node1 = pcomp->node(nodeIdx1);
329 auto node2 = pcomp->node(nodeIdx2);
330 if (node1->isGround() || node2->isGround())
333 neighbours[node1].push_back(node2);
334 neighbours[node2].push_back(node1);
340 size_t totalNodes =
mNodes.size();
341 for (
auto tnode :
mNodes) {
342 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
343 if (!
node || tnode->isGround()) {
348 while (subnet.size() != totalNodes) {
349 std::list<typename SimNode<VarType>::Ptr> nextSet;
351 for (
auto tnode :
mNodes) {
352 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
353 if (!
node || tnode->isGround())
356 if (subnet.find(
node) == subnet.end()) {
357 nextSet.push_back(
node);
361 while (!nextSet.empty()) {
362 auto node = nextSet.front();
365 subnet[
node] = currentNet;
366 for (
auto neighbour : neighbours[
node]) {
367 if (subnet.find(neighbour) == subnet.end())
368 nextSet.push_back(neighbour);
381 Graph::Graph g(
"topology", Graph::Type::undirected);
383 g.set(
"splines",
"polyline");
386 n = g.addNode(
node->uid());
388 std::stringstream label, tooltip;
390 tooltip <<
node->uid();
392 label <<
"<FONT POINT-SIZE=\"12\"><B>" <<
node->name()
393 <<
"</B></FONT><BR/>";
395 double phase = 180.0 / M_PI * std::arg(
node->initialSingleVoltage());
396 double mag = std::abs(
node->initialSingleVoltage());
398 const char *suffixes[] = {
"",
"k",
"M",
"G"};
401 for (s = 0; s < 3 && mag > 1000; s++)
404 if (
node->initialSingleVoltage() != Complex(0, 0)) {
405 label << std::setprecision(2) << std::fixed;
406 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">";
407 label <<
"(" << mag <<
" " << suffixes[s] <<
"V > " << phase <<
"°)";
411 n->set(
"xlabel", label.str(),
true);
412 n->set(
"tooltip", tooltip.str(),
true);
413 n->set(
"fillcolor", phase == 0 ?
"red" :
"black");
414 n->set(
"fixedsize",
"true");
415 n->set(
"width",
"0.15");
416 n->set(
"height",
"0.15");
417 n->set(
"shape",
"point");
420 std::map<String, String> compColorMap;
426 TopologicalPowerComp::Ptr topoComp;
428 if (!(topoComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp)))
431 c = g.addNode(topoComp->uid());
433 auto type = topoComp->type();
434 auto name = topoComp->name();
436 std::stringstream label, tooltip;
438 label <<
"<FONT POINT-SIZE=\"12\"><B>" << name <<
"</B></FONT><BR/>";
439 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">" << type
441 if (topoComp->description() !=
"") {
442 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">"
443 << topoComp->description() <<
"</FONT>";
446 tooltip <<
"Attributes:";
447 for (
auto it : topoComp->attributes()) {
448 tooltip << std::endl << it.first <<
": " << it.second->toString();
451 if (compColorMap.find(type) != compColorMap.end()) {
453 String(
"/paired9/") + std::to_string(1 + compColorMap.size() % 9);
456 c->set(
"color", compColorMap[type]);
457 c->set(
"label", label.str(),
true);
458 c->set(
"tooltip", tooltip.str(),
true);
459 c->set(
"style",
"rounded,filled,bold");
461 if (type.find(
"Line") == std::string::npos) {
462 c->set(
"shape",
"rectangle");
463 c->set(
"fillcolor",
"gray93");
465 c->set(
"shape",
"plaintext");
466 c->set(
"fillcolor",
"transparent");
469 for (
auto term : topoComp->topologicalTerminals()) {
470 n = g.node(term->topologicalNodes()->uid());
474 g.addEdge(term->uid(), c, n);
481String SystemTopology::render() {
482 auto graph = this->topologyGraph();
483 std::stringstream ss;
484 graph.render(ss,
"neato",
"svg");
489void SystemTopology::renderToFile(String filename) {
490 std::ofstream ofstr(filename);
491 this->topologyGraph().render(ofstr,
"neato",
"svg");
496template void SystemTopology::multiplyPowerComps<Real>(Int numberCopies);
497template void SystemTopology::multiplyPowerComps<Complex>(Int numberCopies);
498template std::shared_ptr<TopologicalNode>
500template std::shared_ptr<TopologicalNode>
502template std::shared_ptr<SimNode<Real>>
504template std::shared_ptr<SimNode<Complex>>
506template std::shared_ptr<SimNode<Real>>
508template std::shared_ptr<SimNode<Complex>>
511 typename SimPowerComp<Real>::Ptr component,
512 typename SimNode<Real>::List simNodes);
514 typename SimPowerComp<Complex>::Ptr component,
515 typename SimNode<Complex>::List simNodes);
516template int SystemTopology::checkTopologySubnets<Real>(
517 std::unordered_map<
typename CPS::SimNode<Real>::Ptr,
int> &subnet);
518template int SystemTopology::checkTopologySubnets<Complex>(
519 std::unordered_map<
typename CPS::SimNode<Complex>::Ptr,
int> &subnet);
520template void SystemTopology::splitSubnets<Real>(
521 std::vector<CPS::SystemTopology> &splitSystems);
522template void SystemTopology::splitSubnets<Complex>(
523 std::vector<CPS::SystemTopology> &splitSystems);
Base class for all components that are transmitting power.
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.
void addTearComponent(IdentifiedObject::Ptr component)
Adds component and initializes frequencies.
std::shared_ptr< Type > component(const String &name)
Returns Component by name.
TopologicalNode::List mNodes
List of network nodes.
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...
IdentifiedObject::List mTearComponents
SystemTopology()
Do not use this constructor.
void addTearComponents(const IdentifiedObject::List &components)
Add multiple components.
std::map< TopologicalNode::Ptr, TopologicalPowerComp::List > mComponentsAtNode
Map of network components connected to network nodes.