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) {
257template <
typename VarType>
258void SystemTopology::splitSubnets(std::vector<SystemTopology> &splitSystems) {
259 std::unordered_map<typename SimNode<VarType>::Ptr,
int> subnet;
260 int numberSubnets = checkTopologySubnets<VarType>(subnet);
261 if (numberSubnets == 1) {
262 splitSystems.push_back(*
this);
264 std::vector<IdentifiedObject::List> components(numberSubnets);
265 std::vector<TopologicalNode::List> nodes(numberSubnets);
269 auto pnode = std::dynamic_pointer_cast<SimNode<VarType>>(
node);
270 if (!pnode ||
node->isGround())
273 nodes[subnet[pnode]].push_back(
node);
278 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
285 components[0].push_back(comp);
288 for (UInt nodeIdx = 0; nodeIdx < pcomp->terminalNumber(); nodeIdx++) {
289 if (!pcomp->node(nodeIdx)->isGround()) {
290 components[subnet[pcomp->node(nodeIdx)]].push_back(comp);
295 for (
int currentNet = 0; currentNet < numberSubnets; currentNet++) {
297 components[currentNet]);
302template <
typename VarType>
303int SystemTopology::checkTopologySubnets(
304 std::unordered_map<
typename SimNode<VarType>::Ptr,
int> &subnet) {
305 std::unordered_map<typename SimNode<VarType>::Ptr,
306 typename SimNode<VarType>::List>
310 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
314 for (UInt nodeIdx1 = 0; nodeIdx1 < pcomp->terminalNumberConnected();
316 for (UInt nodeIdx2 = 0; nodeIdx2 < nodeIdx1; nodeIdx2++) {
317 auto node1 = pcomp->node(nodeIdx1);
318 auto node2 = pcomp->node(nodeIdx2);
319 if (node1->isGround() || node2->isGround())
322 neighbours[node1].push_back(node2);
323 neighbours[node2].push_back(node1);
329 size_t totalNodes =
mNodes.size();
330 for (
auto tnode :
mNodes) {
331 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
332 if (!
node || tnode->isGround()) {
337 while (subnet.size() != totalNodes) {
338 std::list<typename SimNode<VarType>::Ptr> nextSet;
340 for (
auto tnode :
mNodes) {
341 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
342 if (!
node || tnode->isGround())
345 if (subnet.find(
node) == subnet.end()) {
346 nextSet.push_back(
node);
350 while (!nextSet.empty()) {
351 auto node = nextSet.front();
354 subnet[
node] = currentNet;
355 for (
auto neighbour : neighbours[
node]) {
356 if (subnet.find(neighbour) == subnet.end())
357 nextSet.push_back(neighbour);
370 Graph::Graph g(
"topology", Graph::Type::undirected);
372 g.set(
"splines",
"polyline");
375 n = g.addNode(
node->uid());
377 std::stringstream label, tooltip;
379 tooltip <<
node->uid();
381 label <<
"<FONT POINT-SIZE=\"12\"><B>" <<
node->name()
382 <<
"</B></FONT><BR/>";
384 double phase = 180.0 / M_PI * std::arg(
node->initialSingleVoltage());
385 double mag = std::abs(
node->initialSingleVoltage());
387 const char *suffixes[] = {
"",
"k",
"M",
"G"};
390 for (s = 0; s < 3 && mag > 1000; s++)
393 if (
node->initialSingleVoltage() != Complex(0, 0)) {
394 label << std::setprecision(2) << std::fixed;
395 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">";
396 label <<
"(" << mag <<
" " << suffixes[s] <<
"V > " << phase <<
"°)";
400 n->set(
"xlabel", label.str(),
true);
401 n->set(
"tooltip", tooltip.str(),
true);
402 n->set(
"fillcolor", phase == 0 ?
"red" :
"black");
403 n->set(
"fixedsize",
"true");
404 n->set(
"width",
"0.15");
405 n->set(
"height",
"0.15");
406 n->set(
"shape",
"point");
409 std::map<String, String> compColorMap;
415 TopologicalPowerComp::Ptr topoComp;
417 if (!(topoComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp)))
420 c = g.addNode(topoComp->uid());
422 auto type = topoComp->type();
423 auto name = topoComp->name();
425 std::stringstream label, tooltip;
427 label <<
"<FONT POINT-SIZE=\"12\"><B>" << name <<
"</B></FONT><BR/>";
428 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">" << type
430 if (topoComp->description() !=
"") {
431 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">"
432 << topoComp->description() <<
"</FONT>";
435 tooltip <<
"Attributes:";
436 for (
auto it : topoComp->attributes()) {
437 tooltip << std::endl << it.first <<
": " << it.second->toString();
440 if (compColorMap.find(type) != compColorMap.end()) {
442 String(
"/paired9/") + std::to_string(1 + compColorMap.size() % 9);
445 c->set(
"color", compColorMap[type]);
446 c->set(
"label", label.str(),
true);
447 c->set(
"tooltip", tooltip.str(),
true);
448 c->set(
"style",
"rounded,filled,bold");
450 if (type.find(
"Line") == std::string::npos) {
451 c->set(
"shape",
"rectangle");
452 c->set(
"fillcolor",
"gray93");
454 c->set(
"shape",
"plaintext");
455 c->set(
"fillcolor",
"transparent");
458 for (
auto term : topoComp->topologicalTerminals()) {
459 n = g.node(term->topologicalNodes()->uid());
463 g.addEdge(term->uid(), c, n);
470String SystemTopology::render() {
471 auto graph = this->topologyGraph();
472 std::stringstream ss;
473 graph.render(ss,
"neato",
"svg");
478void SystemTopology::renderToFile(String filename) {
479 std::ofstream ofstr(filename);
480 this->topologyGraph().render(ofstr,
"neato",
"svg");
485template void SystemTopology::multiplyPowerComps<Real>(Int numberCopies);
486template void SystemTopology::multiplyPowerComps<Complex>(Int numberCopies);
487template std::shared_ptr<TopologicalNode>
489template std::shared_ptr<TopologicalNode>
491template std::shared_ptr<SimNode<Real>>
493template std::shared_ptr<SimNode<Complex>>
495template std::shared_ptr<SimNode<Real>>
497template std::shared_ptr<SimNode<Complex>>
500 typename SimPowerComp<Real>::Ptr component,
501 typename SimNode<Real>::List simNodes);
503 typename SimPowerComp<Complex>::Ptr component,
504 typename SimNode<Complex>::List simNodes);
505template int SystemTopology::checkTopologySubnets<Real>(
506 std::unordered_map<
typename CPS::SimNode<Real>::Ptr,
int> &subnet);
507template int SystemTopology::checkTopologySubnets<Complex>(
508 std::unordered_map<
typename CPS::SimNode<Complex>::Ptr,
int> &subnet);
509template void SystemTopology::splitSubnets<Real>(
510 std::vector<CPS::SystemTopology> &splitSystems);
511template void SystemTopology::splitSubnets<Complex>(
512 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.