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)
76 auto powerComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp);
78 for (
auto topoNode : powerComp->topologicalNodes())
84 for (
auto comp : components)
91 for (
auto nodePF : systemPF.
mNodes) {
95 node->setInitialVoltage(
104 if (
auto genPF = std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
108 auto terminal = comp->terminals()[0];
109 terminal->setPower(-genPF->getApparentPower());
112 auto terminal = comp->terminals()[0];
113 terminal->setPower(-genPF->getApparentPower());
121 if (
auto powerCompComplex =
125 if (
auto powerCompReal =
134 for (
auto comp : components)
138template <
typename Type>
140 if (index <
mNodes.size()) {
141 auto topoNode =
mNodes[index];
142 auto node = std::dynamic_pointer_cast<Type>(topoNode);
150template <
typename Type>
152 for (
auto topoNode :
mNodes) {
153 if (topoNode->name() == name) {
154 auto node = std::dynamic_pointer_cast<Type>(topoNode);
165 std::map<String, String, std::less<>> objTypeMap;
168 objTypeMap[
node->name()] =
node->type();
171 objTypeMap[comp->name()] = comp->type();
176template <
typename VarType>
177void SystemTopology::multiplyPowerComps(
Int numberCopies) {
181 for (
int copy = 0; copy < numberCopies; copy++) {
182 std::unordered_map<typename SimNode<VarType>::Ptr,
185 String copySuffix =
"_" + std::to_string(copy + 2);
189 for (
size_t nNode = 0; nNode <
mNodes.size(); nNode++) {
196 nodeMap[nodePtr] = nodePtr;
201 nodeMap[nodePtr] = nodeCpy;
202 newNodes.push_back(nodeCpy);
208 auto comp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(genComp);
211 auto copy = comp->clone(comp->name() + copySuffix);
213 throw SystemError(
"copy() not implemented for " + comp->name());
217 for (
UInt nNode = 0; nNode < comp->terminalNumber(); nNode++) {
218 nodeCopies.push_back(nodeMap[comp->node(nNode)]);
220 copy->connect(nodeCopies);
223 for (
UInt nTerminal = 0; nTerminal < comp->terminalNumber();
225 copy->terminal(nTerminal)->setPower(comp->terminal(nTerminal)->power());
227 newComponents.push_back(copy);
230 for (
auto node : newNodes)
232 for (
auto comp : newComponents)
238 multiplyPowerComps<Real>(numCopies);
239 multiplyPowerComps<Complex>(numCopies);
251 if ((*it)->name() == name) {
266 auto powerComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp);
271 const auto terminals = powerComp->topologicalTerminals();
272 return std::any_of(terminals.begin(), terminals.end(),
274 return terminal && terminal->topologicalNodes() == node;
278void SystemTopology::removeComponentsConnectedTo(
284 removedComponents.push_back(*it);
293 for (
const auto &removed : removedComponents) {
303 if ((*it)->name() == name && !(*it)->isGround()) {
304 removeComponentsConnectedTo(*it);
312template <
typename VarType>
314 std::unordered_map<typename SimNode<VarType>::Ptr,
int> subnet;
316 if (numberSubnets == 1) {
317 splitSystems.push_back(*
this);
319 std::vector<IdentifiedObject::List> components(numberSubnets);
320 std::vector<TopologicalNode::List> nodes(numberSubnets);
324 auto pnode = std::dynamic_pointer_cast<SimNode<VarType>>(
node);
325 if (!pnode ||
node->isGround())
328 nodes[subnet[pnode]].push_back(
node);
333 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
340 components[0].push_back(comp);
343 for (
UInt nodeIdx = 0; nodeIdx < pcomp->terminalNumber(); nodeIdx++) {
344 if (!pcomp->node(nodeIdx)->isGround()) {
345 components[subnet[pcomp->node(nodeIdx)]].push_back(comp);
350 for (
int currentNet = 0; currentNet < numberSubnets; currentNet++) {
352 components[currentNet]);
357template <
typename VarType>
360 std::unordered_map<typename SimNode<VarType>::Ptr,
365 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
369 for (
UInt nodeIdx1 = 0; nodeIdx1 < pcomp->terminalNumberConnected();
371 for (
UInt nodeIdx2 = 0; nodeIdx2 < nodeIdx1; nodeIdx2++) {
372 auto node1 = pcomp->node(nodeIdx1);
373 auto node2 = pcomp->node(nodeIdx2);
374 if (node1->isGround() || node2->isGround())
377 neighbours[node1].push_back(node2);
378 neighbours[node2].push_back(node1);
384 size_t totalNodes =
mNodes.size();
385 for (
auto tnode :
mNodes) {
386 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
387 if (!
node || tnode->isGround()) {
392 while (subnet.size() != totalNodes) {
393 std::list<typename SimNode<VarType>::Ptr> nextSet;
395 for (
auto tnode :
mNodes) {
396 auto node = std::dynamic_pointer_cast<SimNode<VarType>>(tnode);
397 if (!
node || tnode->isGround())
400 if (subnet.find(
node) == subnet.end()) {
401 nextSet.push_back(
node);
405 while (!nextSet.empty()) {
406 auto node = nextSet.front();
409 subnet[
node] = currentNet;
410 for (
auto neighbour : neighbours[
node]) {
411 if (subnet.find(neighbour) == subnet.end())
412 nextSet.push_back(neighbour);
427 g.set(
"splines",
"polyline");
430 n = g.addNode(
node->uid());
432 std::stringstream label, tooltip;
434 tooltip <<
node->uid();
436 label <<
"<FONT POINT-SIZE=\"12\"><B>" <<
node->name()
437 <<
"</B></FONT><BR/>";
439 double phase = 180.0 /
M_PI * std::arg(
node->initialSingleVoltage());
440 double mag = std::abs(
node->initialSingleVoltage());
442 const char *suffixes[] = {
"",
"k",
"M",
"G"};
445 for (s = 0; s < 3 && mag > 1000; s++)
448 if (
node->initialSingleVoltage() !=
Complex(0, 0)) {
449 label << std::setprecision(2) << std::fixed;
450 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">";
451 label <<
"(" << mag <<
" " << suffixes[s] <<
"V > " << phase <<
"°)";
455 n->
set(
"xlabel", label.str(),
true);
456 n->
set(
"tooltip", tooltip.str(),
true);
457 n->
set(
"fillcolor", phase == 0 ?
"red" :
"black");
458 n->
set(
"fixedsize",
"true");
459 n->
set(
"width",
"0.15");
460 n->
set(
"height",
"0.15");
461 n->
set(
"shape",
"point");
464 std::map<String, String> compColorMap;
472 if (!(topoComp = std::dynamic_pointer_cast<TopologicalPowerComp>(comp)))
475 c = g.addNode(topoComp->uid());
477 auto type = topoComp->type();
478 auto name = topoComp->name();
480 std::stringstream label, tooltip;
482 label <<
"<FONT POINT-SIZE=\"12\"><B>" << name <<
"</B></FONT><BR/>";
483 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">" << type
485 if (topoComp->description() !=
"") {
486 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">"
487 << topoComp->description() <<
"</FONT>";
490 tooltip <<
"Attributes:";
491 for (
auto it : topoComp->attributes()) {
492 tooltip << std::endl << it.first <<
": " << it.second->toString();
495 if (compColorMap.find(type) != compColorMap.end()) {
497 String(
"/paired9/") + std::to_string(1 + compColorMap.size() % 9);
500 c->
set(
"color", compColorMap[type]);
501 c->
set(
"label", label.str(),
true);
502 c->
set(
"tooltip", tooltip.str(),
true);
503 c->
set(
"style",
"rounded,filled,bold");
505 if (type.find(
"Line") == std::string::npos) {
506 c->
set(
"shape",
"rectangle");
507 c->
set(
"fillcolor",
"gray93");
509 c->
set(
"shape",
"plaintext");
510 c->
set(
"fillcolor",
"transparent");
513 for (
auto term : topoComp->topologicalTerminals()) {
514 n = g.node(term->topologicalNodes()->uid());
518 g.addEdge(term->uid(), c, n);
525String SystemTopology::render() {
526 auto graph = this->topologyGraph();
527 std::stringstream ss;
528 graph.render(ss,
"neato",
"svg");
533void SystemTopology::renderToFile(
String filename) {
534 std::ofstream ofstr(filename);
535 this->topologyGraph().render(ofstr,
"neato",
"svg");
540template void SystemTopology::multiplyPowerComps<Real>(
Int numberCopies);
541template void SystemTopology::multiplyPowerComps<Complex>(
Int numberCopies);
542template std::shared_ptr<TopologicalNode>
544template std::shared_ptr<TopologicalNode>
546template std::shared_ptr<SimNode<Real>>
548template std::shared_ptr<SimNode<Complex>>
550template std::shared_ptr<SimNode<Real>>
552template std::shared_ptr<SimNode<Complex>>
561 std::unordered_map<
typename CPS::SimNode<Real>::Ptr,
int> &subnet);
563 std::unordered_map<
typename CPS::SimNode<Complex>::Ptr,
int> &subnet);
565 std::vector<CPS::SystemTopology> &splitSystems);
567 std::vector<CPS::SystemTopology> &splitSystems);
static bool isConnectedTo(const IdentifiedObject::Ptr &comp, const TopologicalNode::Ptr &node)
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)
Remove node and all components connected to it.
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
std::shared_ptr< TopologicalTerminal > 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