12 #include <unordered_map>
14 #include <dpsim-models/SP/SP_Ph1_SynchronGenerator.h>
15 #include <dpsim-models/SystemTopology.h>
19 Matrix 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 =
62 template <
typename VarType>
64 typename SimPowerComp<VarType>::Ptr component,
65 typename SimNode<VarType>::List simNodes) {
67 for (
auto simNode : simNodes)
71 void 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) {
89 if (
auto node = this->node<TopologicalNode>(nodePF->name())) {
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) {
104 auto comp = this->component<SimPowerComp<Complex>>(compPF->name());
105 auto terminal = comp->terminals()[0];
106 terminal->setPower(-genPF->getApparentPower());
107 }
else if (domain == CPS::Domain::EMT) {
108 auto comp = this->component<SimPowerComp<Real>>(compPF->name());
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)
135 template <
typename Type>
137 if (index <
mNodes.size()) {
138 auto topoNode =
mNodes[index];
139 auto node = std::dynamic_pointer_cast<Type>(topoNode);
147 template <
typename Type>
149 for (
auto topoNode :
mNodes) {
150 if (topoNode->name() == name) {
151 auto node = std::dynamic_pointer_cast<Type>(topoNode);
161 std::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();
173 template <
typename VarType>
174 void 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++) {
187 auto nodePtr = this->node<SimNode<VarType>>(
static_cast<UInt
>(nNode));
192 if (nodePtr->isGround()) {
193 nodeMap[nodePtr] = nodePtr;
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) {
254 template <
typename VarType>
255 void SystemTopology::splitSubnets(std::vector<SystemTopology> &splitSystems) {
256 std::unordered_map<typename SimNode<VarType>::Ptr,
int> subnet;
257 int numberSubnets = checkTopologySubnets<VarType>(subnet);
258 if (numberSubnets == 1) {
259 splitSystems.push_back(*
this);
261 std::vector<IdentifiedObject::List> components(numberSubnets);
262 std::vector<TopologicalNode::List> nodes(numberSubnets);
266 auto pnode = std::dynamic_pointer_cast<SimNode<VarType>>(
node);
267 if (!pnode ||
node->isGround())
270 nodes[subnet[pnode]].push_back(
node);
275 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
282 components[0].push_back(comp);
285 for (UInt nodeIdx = 0; nodeIdx < pcomp->terminalNumber(); nodeIdx++) {
286 if (!pcomp->node(nodeIdx)->isGround()) {
287 components[subnet[pcomp->node(nodeIdx)]].push_back(comp);
292 for (
int currentNet = 0; currentNet < numberSubnets; currentNet++) {
294 components[currentNet]);
299 template <
typename VarType>
300 int SystemTopology::checkTopologySubnets(
301 std::unordered_map<
typename SimNode<VarType>::Ptr,
int> &subnet) {
302 std::unordered_map<typename SimNode<VarType>::Ptr,
303 typename SimNode<VarType>::List>
307 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
311 for (UInt nodeIdx1 = 0; nodeIdx1 < pcomp->terminalNumberConnected();
313 for (UInt nodeIdx2 = 0; nodeIdx2 < nodeIdx1; nodeIdx2++) {
314 auto node1 = pcomp->node(nodeIdx1);
315 auto node2 = pcomp->node(nodeIdx2);
316 if (node1->isGround() || node2->isGround())
319 neighbours[node1].push_back(node2);
320 neighbours[node2].push_back(node1);
326 size_t totalNodes =
mNodes.size();
327 for (
auto tnode :
mNodes) {
328 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
329 if (!
node || tnode->isGround()) {
334 while (subnet.size() != totalNodes) {
335 std::list<typename SimNode<VarType>::Ptr> nextSet;
337 for (
auto tnode :
mNodes) {
338 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
339 if (!
node || tnode->isGround())
342 if (subnet.find(
node) == subnet.end()) {
343 nextSet.push_back(
node);
347 while (!nextSet.empty()) {
348 auto node = nextSet.front();
351 subnet[
node] = currentNet;
352 for (
auto neighbour : neighbours[
node]) {
353 if (subnet.find(neighbour) == subnet.end())
354 nextSet.push_back(neighbour);
369 g.set(
"splines",
"polyline");
372 n = g.addNode(
node->uid());
374 std::stringstream label, tooltip;
376 tooltip <<
node->uid();
378 label <<
"<FONT POINT-SIZE=\"12\"><B>" <<
node->name()
379 <<
"</B></FONT><BR/>";
381 double phase = 180.0 / M_PI * std::arg(
node->initialSingleVoltage());
382 double mag = std::abs(
node->initialSingleVoltage());
384 const char *suffixes[] = {
"",
"k",
"M",
"G"};
387 for (s = 0; s < 3 && mag > 1000; s++)
390 if (
node->initialSingleVoltage() != Complex(0, 0)) {
391 label << std::setprecision(2) << std::fixed;
392 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">";
393 label <<
"(" << mag <<
" " << suffixes[s] <<
"V > " << phase <<
"°)";
397 n->set(
"xlabel", label.str(),
true);
398 n->set(
"tooltip", tooltip.str(),
true);
399 n->set(
"fillcolor", phase == 0 ?
"red" :
"black");
400 n->set(
"fixedsize",
"true");
401 n->set(
"width",
"0.15");
402 n->set(
"height",
"0.15");
403 n->set(
"shape",
"point");
406 std::map<String, String> compColorMap;
412 TopologicalPowerComp::Ptr topoComp;
414 if (!(topoComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp)))
417 c = g.addNode(topoComp->uid());
419 auto type = topoComp->type();
420 auto name = topoComp->name();
422 std::stringstream label, tooltip;
424 label <<
"<FONT POINT-SIZE=\"12\"><B>" << name <<
"</B></FONT><BR/>";
425 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">" << type <<
"</FONT><BR/>";
426 if (topoComp->description() !=
"") {
427 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">" << topoComp->description() <<
"</FONT>";
430 tooltip <<
"Attributes:";
431 for (
auto it : topoComp->attributes()) {
432 tooltip << std::endl << it.first <<
": " << it.second->toString();
435 if (compColorMap.find(type) != compColorMap.end()) {
437 String(
"/paired9/") + std::to_string(1 + compColorMap.size() % 9);
440 c->set(
"color", compColorMap[type]);
441 c->set(
"label", label.str(),
true);
442 c->set(
"tooltip", tooltip.str(),
true);
443 c->set(
"style",
"rounded,filled,bold");
445 if (type.find(
"Line") == std::string::npos) {
446 c->set(
"shape",
"rectangle");
447 c->set(
"fillcolor",
"gray93");
449 c->set(
"shape",
"plaintext");
450 c->set(
"fillcolor",
"transparent");
453 for (
auto term : topoComp->topologicalTerminals()) {
454 n = g.node(term->topologicalNodes()->uid());
458 g.addEdge(term->uid(), c, n);
465 String SystemTopology::render() {
466 auto graph = this->topologyGraph();
467 std::stringstream ss;
468 graph.render(ss,
"neato",
"svg");
473 void SystemTopology::renderToFile(String filename) {
474 std::ofstream ofstr(filename);
475 this->topologyGraph().render(ofstr,
"neato",
"svg");
480 template void SystemTopology::multiplyPowerComps<Real>(Int numberCopies);
481 template void SystemTopology::multiplyPowerComps<Complex>(Int numberCopies);
482 template std::shared_ptr<TopologicalNode>
483 SystemTopology::node<TopologicalNode>(UInt index);
484 template std::shared_ptr<TopologicalNode>
485 SystemTopology::node<TopologicalNode>(std::string_view name);
486 template std::shared_ptr<SimNode<Real>>
487 SystemTopology::node<SimNode<Real>>(UInt index);
488 template std::shared_ptr<SimNode<Complex>>
489 SystemTopology::node<SimNode<Complex>>(UInt index);
490 template std::shared_ptr<SimNode<Real>>
491 SystemTopology::node<SimNode<Real>>(std::string_view name);
492 template std::shared_ptr<SimNode<Complex>>
493 SystemTopology::node<SimNode<Complex>>(std::string_view name);
494 template void SystemTopology::connectComponentToNodes<Real>(
496 typename SimNode<Real>::List simNodes);
497 template void SystemTopology::connectComponentToNodes<Complex>(
500 template int SystemTopology::checkTopologySubnets<Real>(
501 std::unordered_map<
typename CPS::SimNode<Real>::Ptr,
int> &subnet);
502 template int SystemTopology::checkTopologySubnets<Complex>(
503 std::unordered_map<
typename CPS::SimNode<Complex>::Ptr,
int> &subnet);
504 template void SystemTopology::splitSubnets<Real>(
505 std::vector<CPS::SystemTopology> &splitSystems);
506 template void SystemTopology::splitSubnets<Complex>(
507 std::vector<CPS::SystemTopology> &splitSystems);
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.
TopologicalNode::List mNodes
List of network nodes.
std::shared_ptr< Type > component(const String &name)
Returns Component by name.
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
void addTearComponents(const IdentifiedObject::List &components)
Add multiple components.
std::map< TopologicalNode::Ptr, TopologicalPowerComp::List > mComponentsAtNode
Map of network components connected to network nodes.