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);
246 template <
typename VarType>
247 void SystemTopology::splitSubnets(std::vector<SystemTopology> &splitSystems) {
248 std::unordered_map<typename SimNode<VarType>::Ptr,
int> subnet;
249 int numberSubnets = checkTopologySubnets<VarType>(subnet);
250 if (numberSubnets == 1) {
251 splitSystems.push_back(*
this);
253 std::vector<IdentifiedObject::List> components(numberSubnets);
254 std::vector<TopologicalNode::List> nodes(numberSubnets);
258 auto pnode = std::dynamic_pointer_cast<SimNode<VarType>>(
node);
259 if (!pnode ||
node->isGround())
262 nodes[subnet[pnode]].push_back(
node);
267 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
274 components[0].push_back(comp);
277 for (UInt nodeIdx = 0; nodeIdx < pcomp->terminalNumber(); nodeIdx++) {
278 if (!pcomp->node(nodeIdx)->isGround()) {
279 components[subnet[pcomp->node(nodeIdx)]].push_back(comp);
284 for (
int currentNet = 0; currentNet < numberSubnets; currentNet++) {
286 components[currentNet]);
291 template <
typename VarType>
292 int SystemTopology::checkTopologySubnets(
293 std::unordered_map<
typename SimNode<VarType>::Ptr,
int> &subnet) {
294 std::unordered_map<typename SimNode<VarType>::Ptr,
295 typename SimNode<VarType>::List>
299 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
303 for (UInt nodeIdx1 = 0; nodeIdx1 < pcomp->terminalNumberConnected();
305 for (UInt nodeIdx2 = 0; nodeIdx2 < nodeIdx1; nodeIdx2++) {
306 auto node1 = pcomp->node(nodeIdx1);
307 auto node2 = pcomp->node(nodeIdx2);
308 if (node1->isGround() || node2->isGround())
311 neighbours[node1].push_back(node2);
312 neighbours[node2].push_back(node1);
318 size_t totalNodes =
mNodes.size();
319 for (
auto tnode :
mNodes) {
320 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
321 if (!
node || tnode->isGround()) {
326 while (subnet.size() != totalNodes) {
327 std::list<typename SimNode<VarType>::Ptr> nextSet;
329 for (
auto tnode :
mNodes) {
330 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
331 if (!
node || tnode->isGround())
334 if (subnet.find(
node) == subnet.end()) {
335 nextSet.push_back(
node);
339 while (!nextSet.empty()) {
340 auto node = nextSet.front();
343 subnet[
node] = currentNet;
344 for (
auto neighbour : neighbours[
node]) {
345 if (subnet.find(neighbour) == subnet.end())
346 nextSet.push_back(neighbour);
361 g.set(
"splines",
"polyline");
364 n = g.addNode(
node->uid());
366 std::stringstream label, tooltip;
368 tooltip <<
node->uid();
370 label <<
"<FONT POINT-SIZE=\"12\"><B>" <<
node->name()
371 <<
"</B></FONT><BR/>";
373 double phase = 180.0 / M_PI * std::arg(
node->initialSingleVoltage());
374 double mag = std::abs(
node->initialSingleVoltage());
376 const char *suffixes[] = {
"",
"k",
"M",
"G"};
379 for (s = 0; s < 3 && mag > 1000; s++)
382 if (
node->initialSingleVoltage() != Complex(0, 0)) {
383 label << std::setprecision(2) << std::fixed;
384 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">";
385 label <<
"(" << mag <<
" " << suffixes[s] <<
"V > " << phase <<
"°)";
389 n->set(
"xlabel", label.str(),
true);
390 n->set(
"tooltip", tooltip.str(),
true);
391 n->set(
"fillcolor", phase == 0 ?
"red" :
"black");
392 n->set(
"fixedsize",
"true");
393 n->set(
"width",
"0.15");
394 n->set(
"height",
"0.15");
395 n->set(
"shape",
"point");
398 std::map<String, String> compColorMap;
404 TopologicalPowerComp::Ptr topoComp;
406 if (!(topoComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp)))
409 c = g.addNode(topoComp->uid());
411 auto type = topoComp->type();
412 auto name = topoComp->name();
414 std::stringstream label, tooltip;
416 label <<
"<FONT POINT-SIZE=\"12\"><B>" << name <<
"</B></FONT><BR/>";
417 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">" << type <<
"</FONT>";
419 tooltip <<
"Attributes:";
420 for (
auto it : topoComp->attributes()) {
421 tooltip << std::endl << it.first <<
": " << it.second->toString();
424 if (compColorMap.find(type) != compColorMap.end()) {
426 String(
"/paired9/") + std::to_string(1 + compColorMap.size() % 9);
429 c->set(
"color", compColorMap[type]);
430 c->set(
"label", label.str(),
true);
431 c->set(
"tooltip", tooltip.str(),
true);
432 c->set(
"style",
"rounded,filled,bold");
434 if (type.find(
"Line") == std::string::npos) {
435 c->set(
"shape",
"rectangle");
436 c->set(
"fillcolor",
"gray93");
438 c->set(
"shape",
"plaintext");
439 c->set(
"fillcolor",
"transparent");
442 for (
auto term : topoComp->topologicalTerminals()) {
443 n = g.node(term->topologicalNodes()->uid());
447 g.addEdge(term->uid(), c, n);
454 String SystemTopology::render() {
455 auto graph = this->topologyGraph();
456 std::stringstream ss;
457 graph.render(ss,
"neato",
"svg");
462 void SystemTopology::renderToFile(String filename) {
463 std::ofstream ofstr(filename);
464 this->topologyGraph().render(ofstr,
"neato",
"svg");
469 template void SystemTopology::multiplyPowerComps<Real>(Int numberCopies);
470 template void SystemTopology::multiplyPowerComps<Complex>(Int numberCopies);
471 template std::shared_ptr<TopologicalNode>
472 SystemTopology::node<TopologicalNode>(UInt index);
473 template std::shared_ptr<TopologicalNode>
474 SystemTopology::node<TopologicalNode>(std::string_view name);
475 template std::shared_ptr<SimNode<Real>>
476 SystemTopology::node<SimNode<Real>>(UInt index);
477 template std::shared_ptr<SimNode<Complex>>
478 SystemTopology::node<SimNode<Complex>>(UInt index);
479 template std::shared_ptr<SimNode<Real>>
480 SystemTopology::node<SimNode<Real>>(std::string_view name);
481 template std::shared_ptr<SimNode<Complex>>
482 SystemTopology::node<SimNode<Complex>>(std::string_view name);
483 template void SystemTopology::connectComponentToNodes<Real>(
485 typename SimNode<Real>::List simNodes);
486 template void SystemTopology::connectComponentToNodes<Complex>(
489 template int SystemTopology::checkTopologySubnets<Real>(
490 std::unordered_map<
typename CPS::SimNode<Real>::Ptr,
int> &subnet);
491 template int SystemTopology::checkTopologySubnets<Complex>(
492 std::unordered_map<
typename CPS::SimNode<Complex>::Ptr,
int> &subnet);
493 template void SystemTopology::splitSubnets<Real>(
494 std::vector<CPS::SystemTopology> &splitSystems);
495 template void SystemTopology::splitSubnets<Complex>(
496 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 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.