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)
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>(
105 auto terminal = comp->terminals()[0];
106 terminal->setPower(-genPF->getApparentPower());
109 auto terminal = comp->terminals()[0];
110 terminal->setPower(-genPF->getApparentPower());
118 if (
auto powerCompComplex =
122 if (
auto powerCompReal =
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);
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) {
178 for (
int copy = 0; copy < numberCopies; copy++) {
179 std::unordered_map<typename SimNode<VarType>::Ptr,
182 String copySuffix =
"_" + std::to_string(copy + 2);
186 for (
size_t nNode = 0; nNode <
mNodes.size(); nNode++) {
193 nodeMap[nodePtr] = nodePtr;
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());
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) {
260 if ((*it)->name() == name) {
268template <
typename VarType>
270 std::unordered_map<typename SimNode<VarType>::Ptr,
int> 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>
316 std::unordered_map<typename SimNode<VarType>::Ptr,
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);
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;
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>>
517 std::unordered_map<
typename CPS::SimNode<Real>::Ptr,
int> &subnet);
519 std::unordered_map<
typename CPS::SimNode<Complex>::Ptr,
int> &subnet);
521 std::vector<CPS::SystemTopology> &splitSystems);
523 std::vector<CPS::SystemTopology> &splitSystems);
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)
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
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