DPsim
Loading...
Searching...
No Matches
Reader.cpp
1/* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
2 * EONERC, RWTH Aachen University
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7 *********************************************************************************/
8
9#include <CIMExceptions.hpp>
10#include <CIMModel.hpp>
11#include <IEC61970.hpp>
12#include <memory>
13
14#define READER_CPP
15#include <dpsim-models/CIM/Reader.h>
16
17using namespace CPS;
18using namespace CPS::CIM;
19using CIMPP::UnitMultiplier;
20
21Reader::Reader(String name, Logger::Level logLevel,
22 Logger::Level componentLogLevel) {
23 mSLog = Logger::get(name + "_CIM", logLevel);
24
25 mModel = new CIMModel();
26 mModel->setDependencyCheckOff();
27 mComponentLogLevel = componentLogLevel;
28}
29
30Reader::~Reader() { delete mModel; }
31
32SystemTopology Reader::loadCIM(Real systemFrequency,
33 const std::list<CPS::String> &filenamesString,
34 Domain domain, PhaseType phase,
35 GeneratorType genType) {
36 std::list<fs::path> filenames;
37 for (auto f : filenamesString)
38 filenames.emplace_back(f);
39
40 return loadCIM(systemFrequency, filenames, domain, phase, genType);
41}
42
43// #### shunt component settings ####
46 mShuntCapacitorValue = v;
47 mSetShuntCapacitor = true;
48}
49
51 mShuntConductanceValue = v;
52 mSetShuntConductance = true;
53}
54
57 mUseProtectionSwitches = value;
58}
59
60Real Reader::unitValue(Real value, CIMPP::UnitMultiplier mult) {
61 switch (mult) {
62 case UnitMultiplier::p:
63 value *= 1e-12;
64 break;
65 case UnitMultiplier::n:
66 value *= 1e-9;
67 break;
68 case UnitMultiplier::micro:
69 value *= 1e-6;
70 break;
71 case UnitMultiplier::m:
72 value *= 1e-3;
73 break;
74 case UnitMultiplier::c:
75 value *= 1e-2;
76 break;
77 case UnitMultiplier::d:
78 value *= 1e-1;
79 break;
80 case UnitMultiplier::k:
81 value *= 1e3;
82 break;
83 case UnitMultiplier::M:
84 value *= 1e6;
85 break;
86 case UnitMultiplier::G:
87 value *= 1e9;
88 break;
89 case UnitMultiplier::T:
90 value *= 1e12;
91 break;
92 default:
93 break;
94 }
95 return value;
96}
97
98TopologicalPowerComp::Ptr Reader::mapComponent(BaseClass *obj) {
99 if (CIMPP::ACLineSegment *line = dynamic_cast<CIMPP::ACLineSegment *>(obj))
100 return mapACLineSegment(line);
101 if (CIMPP::EnergyConsumer *consumer =
102 dynamic_cast<CIMPP::EnergyConsumer *>(obj))
103 return mapEnergyConsumer(consumer);
104 if (CIMPP::PowerTransformer *trans =
105 dynamic_cast<CIMPP::PowerTransformer *>(obj))
106 return mapPowerTransformer(trans);
107 if (CIMPP::SynchronousMachine *syncMachine =
108 dynamic_cast<CIMPP::SynchronousMachine *>(obj))
109 return mapSynchronousMachine(syncMachine);
110 if (CIMPP::ExternalNetworkInjection *extnet =
111 dynamic_cast<CIMPP::ExternalNetworkInjection *>(obj))
112 return mapExternalNetworkInjection(extnet);
113 if (CIMPP::EquivalentShunt *shunt =
114 dynamic_cast<CIMPP::EquivalentShunt *>(obj))
115 return mapEquivalentShunt(shunt);
116
117 return nullptr;
118}
119
120void Reader::addFiles(const fs::path &filename) {
121 if (!mModel->addCIMFile(filename.string()))
122 SPDLOG_LOGGER_ERROR(mSLog, "Failed to read file {}", filename);
123}
124
125void Reader::addFiles(const std::list<fs::path> &filenames) {
126 for (auto filename : filenames)
127 addFiles(filename);
128}
129
130void Reader::parseFiles() {
131 try {
132 mModel->parseFiles();
133 } catch (...) {
134 SPDLOG_LOGGER_ERROR(mSLog, "Failed to parse CIM files");
135 return;
136 }
137
138 SPDLOG_LOGGER_INFO(
139 mSLog,
140 "#### List of TopologicalNodes, associated Terminals and Equipment");
141 for (auto obj : mModel->Objects) {
142 if (CIMPP::TopologicalNode *topNode =
143 dynamic_cast<CIMPP::TopologicalNode *>(obj)) {
144 if (mDomain == Domain::EMT)
145 processTopologicalNode<Real>(topNode);
146 else
147 processTopologicalNode<Complex>(topNode);
148 }
149 }
150
151 // Collect voltage state variables associated to nodes that are used
152 // for various components.
153 SPDLOG_LOGGER_INFO(mSLog,
154 "#### List of Node voltages and Terminal power flow data");
155 for (auto obj : mModel->Objects) {
156 // Check if object is of class SvVoltage
157 if (CIMPP::SvVoltage *volt = dynamic_cast<CIMPP::SvVoltage *>(obj)) {
158 processSvVoltage(volt);
159 }
160 // Check if object is of class SvPowerFlow
161 else if (CIMPP::SvPowerFlow *flow =
162 dynamic_cast<CIMPP::SvPowerFlow *>(obj)) {
163 processSvPowerFlow(flow);
164 }
165 }
166
167 SPDLOG_LOGGER_INFO(mSLog, "#### Create other components");
168 for (auto obj : mModel->Objects) {
169
170 // Check if object is not TopologicalNode, SvVoltage or SvPowerFlow
171 if (!dynamic_cast<CIMPP::TopologicalNode *>(obj) &&
172 !dynamic_cast<CIMPP::SvVoltage *>(obj) &&
173 !dynamic_cast<CIMPP::SvPowerFlow *>(obj)) {
174
175 if (CIMPP::IdentifiedObject *idObj =
176 dynamic_cast<CIMPP::IdentifiedObject *>(obj)) {
177
178 // Check if object is already in equipment list
179 if (mPowerflowEquipment.find(idObj->mRID) ==
180 mPowerflowEquipment.end()) {
181 TopologicalPowerComp::Ptr comp = mapComponent(obj);
182 if (comp)
183 mPowerflowEquipment.insert(std::make_pair(comp->uid(), comp));
184 }
185 }
186 }
187 }
188
189 SPDLOG_LOGGER_INFO(mSLog, "#### Check topology for unconnected components");
190 for (auto pfe : mPowerflowEquipment) {
191 auto c = pfe.second;
192
193 if (mDomain == Domain::EMT) {
194 if (SimPowerComp<Real>::Ptr powercomp =
195 std::dynamic_pointer_cast<SimPowerComp<Real>>(c)) {
196 if (powercomp->terminalNumberConnected() < powercomp->terminalNumber())
197 throw InvalidTopology();
198 }
199 } else {
200 if (SimPowerComp<Complex>::Ptr powercomp =
201 std::dynamic_pointer_cast<SimPowerComp<Complex>>(c)) {
202 if (powercomp->terminalNumberConnected() < powercomp->terminalNumber())
203 throw InvalidTopology();
204 }
205 }
206 }
207}
208
209SystemTopology Reader::loadCIM(Real systemFrequency, const fs::path &filename,
210 Domain domain, PhaseType phase,
211 GeneratorType genType) {
212 mFrequency = systemFrequency;
213 mOmega = 2 * PI * mFrequency;
214 mDomain = domain;
215 mPhase = phase;
216 mGeneratorType = genType;
217 addFiles(filename);
218 parseFiles();
219 return systemTopology();
220}
221
222SystemTopology Reader::loadCIM(Real systemFrequency,
223 const std::list<fs::path> &filenames,
224 Domain domain, PhaseType phase,
225 GeneratorType genType) {
226 mFrequency = systemFrequency;
227 mOmega = 2 * PI * mFrequency;
228 mDomain = domain;
229 mPhase = phase;
230 mGeneratorType = genType;
231 addFiles(filenames);
232 parseFiles();
233 return systemTopology();
234}
235
236void Reader::processSvVoltage(CIMPP::SvVoltage *volt) {
237 CIMPP::TopologicalNode *node = volt->TopologicalNode;
238 if (!node) {
239 SPDLOG_LOGGER_WARN(
240 mSLog, "SvVoltage references missing Topological Node, ignoring");
241 return;
242 }
243 auto search = mPowerflowNodes.find(node->mRID);
244 if (search == mPowerflowNodes.end()) {
245 SPDLOG_LOGGER_WARN(mSLog,
246 "SvVoltage references Topological Node {}"
247 " missing from mTopNodes, ignoring",
248 node->mRID);
249 return;
250 }
251
252 Real voltageAbs = Reader::unitValue(volt->v.value, UnitMultiplier::k);
253
254 try {
255 SPDLOG_LOGGER_INFO(mSLog, " Angle={}", (float)volt->angle.value);
256 } catch (ReadingUninitializedField *e) {
257 volt->angle.value = 0;
258 std::cerr << "Uninitialized Angle for SVVoltage at "
259 << volt->TopologicalNode->name << ".Setting default value of "
260 << volt->angle.value << std::endl;
261 }
262 Real voltagePhase = volt->angle.value * PI / 180;
263 mPowerflowNodes[node->mRID]->setInitialVoltage(
264 std::polar<Real>(voltageAbs, voltagePhase));
265
266 SPDLOG_LOGGER_INFO(
267 mSLog, "Node {} MatrixNodeIndex {}: {} V, {} deg",
268 mPowerflowNodes[node->mRID]->uid(),
269 mPowerflowNodes[node->mRID]->matrixNodeIndex(),
270 std::abs(mPowerflowNodes[node->mRID]->initialSingleVoltage()),
271 std::arg(mPowerflowNodes[node->mRID]->initialSingleVoltage()) * 180 / PI);
272}
273
274void Reader::processSvPowerFlow(CIMPP::SvPowerFlow *flow) {
275 CIMPP::Terminal *term = flow->Terminal;
276
277 mPowerflowTerminals[term->mRID]->setPower(
278 Complex(Reader::unitValue(flow->p.value, UnitMultiplier::M),
279 Reader::unitValue(flow->q.value, UnitMultiplier::M)));
280
281 SPDLOG_LOGGER_WARN(mSLog, "Terminal {}: {} W + j {} Var", term->mRID,
282 mPowerflowTerminals[term->mRID]->singleActivePower(),
283 mPowerflowTerminals[term->mRID]->singleReactivePower());
284}
285
286SystemTopology Reader::systemTopology() {
287 SystemTopology system(mFrequency);
288
289 for (auto comp : mPowerflowEquipment) {
290 system.addComponent(comp.second);
291 // TODO support Real
292 if (SimPowerComp<Complex>::Ptr powercomp =
293 std::dynamic_pointer_cast<SimPowerComp<Complex>>(comp.second)) {
294 for (auto term : powercomp->topologicalTerminals()) {
295 TopologicalNode::Ptr node = term->topologicalNodes();
296 //TopologicalNode::Ptr node = powercomp->topologicalTerminals().back()->topologicalNodes();
297 if (system.mComponentsAtNode.find(node) ==
298 system.mComponentsAtNode.end()) {
299 TopologicalPowerComp::List complist;
300 complist.push_back(powercomp);
301 system.mComponentsAtNode.insert(std::make_pair(node, complist));
302 } else {
303 system.mComponentsAtNode[node].push_back(powercomp);
304 }
305 }
306 }
307 }
308
309 system.mNodes.resize(mPowerflowNodes.size());
310
311 for (auto node : mPowerflowNodes) {
312 // The index of the node in the list should not matter anymore
313 //system.mNodes[node.second->matrixNodeIndex()] = node.second;
314 system.addNodeAt(node.second, node.second->matrixNodeIndex());
315 }
316
317 return system;
318}
319
320Matrix::Index Reader::mapTopologicalNode(String mrid) {
321 auto search = mPowerflowNodes.find(mrid);
322 if (search == mPowerflowNodes.end()) {
323 return -1;
324 }
325 return search->second->matrixNodeIndex();
326}
327
328TopologicalPowerComp::Ptr
329Reader::mapEnergyConsumer(CIMPP::EnergyConsumer *consumer) {
330 SPDLOG_LOGGER_INFO(mSLog, " Found EnergyConsumer {}", consumer->name);
331 if (mDomain == Domain::EMT) {
332 if (mPhase == PhaseType::ABC) {
333 return std::make_shared<EMT::Ph3::RXLoad>(consumer->mRID, consumer->name,
334 mComponentLogLevel);
335 } else {
336 SPDLOG_LOGGER_INFO(mSLog, " RXLoad for EMT not implemented yet");
337 return std::make_shared<DP::Ph1::RXLoad>(consumer->mRID, consumer->name,
338 mComponentLogLevel);
339 }
340 } else if (mDomain == Domain::SP) {
341 auto load = std::make_shared<SP::Ph1::Load>(consumer->mRID, consumer->name,
342 mComponentLogLevel);
343
344 // P and Q values will be set according to SvPowerFlow data
345 load->modifyPowerFlowBusType(
346 PowerflowBusType::
347 PQ); // for powerflow solver set as PQ component as default
348 return load;
349 } else {
350 if (mUseProtectionSwitches)
351 return std::make_shared<DP::Ph1::RXLoadSwitch>(
352 consumer->mRID, consumer->name, mComponentLogLevel);
353 else
354 return std::make_shared<DP::Ph1::RXLoad>(consumer->mRID, consumer->name,
355 mComponentLogLevel);
356 }
357}
358
359TopologicalPowerComp::Ptr Reader::mapACLineSegment(CIMPP::ACLineSegment *line) {
360 SPDLOG_LOGGER_INFO(mSLog,
361 " Found ACLineSegment {} r={} x={} bch={} gch={}",
362 line->name, (float)line->r.value, (float)line->x.value,
363 (float)line->bch.value, (float)line->gch.value);
364
365 Real resistance = line->r.value;
366 Real inductance = line->x.value / mOmega;
367
368 // By default there is always a small conductance to ground to
369 // avoid problems with floating nodes.
370 Real capacitance = mShuntCapacitorValue;
371 Real conductance = mShuntConductanceValue;
372
373 if (line->bch.value > 1e-9 && !mSetShuntCapacitor)
374 capacitance = Real(line->bch.value / mOmega);
375
376 if (line->gch.value > 1e-9 && !mSetShuntConductance)
377 conductance = Real(line->gch.value);
378
379 Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(line);
380
381 if (mDomain == Domain::EMT) {
382 if (mPhase == PhaseType::ABC) {
383 Matrix res_3ph = CPS::Math::singlePhaseParameterToThreePhase(resistance);
384 Matrix ind_3ph = CPS::Math::singlePhaseParameterToThreePhase(inductance);
385 Matrix cap_3ph = CPS::Math::singlePhaseParameterToThreePhase(capacitance);
386 Matrix cond_3ph =
388
389 auto cpsLine = std::make_shared<EMT::Ph3::PiLine>(line->mRID, line->name,
390 mComponentLogLevel);
391 cpsLine->setParameters(res_3ph, ind_3ph, cap_3ph, cond_3ph);
392 return cpsLine;
393 } else {
394 SPDLOG_LOGGER_INFO(mSLog, " PiLine for EMT not implemented yet");
395 auto cpsLine = std::make_shared<DP::Ph1::PiLine>(line->mRID, line->name,
396 mComponentLogLevel);
397 cpsLine->setParameters(resistance, inductance, capacitance, conductance);
398 return cpsLine;
399 }
400 } else if (mDomain == Domain::SP) {
401 auto cpsLine = std::make_shared<SP::Ph1::PiLine>(line->mRID, line->name,
402 mComponentLogLevel);
403 cpsLine->setParameters(resistance, inductance, capacitance, conductance);
404 cpsLine->setBaseVoltage(baseVoltage);
405 return cpsLine;
406 } else {
407 auto cpsLine = std::make_shared<DP::Ph1::PiLine>(line->mRID, line->name,
408 mComponentLogLevel);
409 cpsLine->setParameters(resistance, inductance, capacitance, conductance);
410 return cpsLine;
411 }
412}
413
414TopologicalPowerComp::Ptr
415Reader::mapPowerTransformer(CIMPP::PowerTransformer *trans) {
416 if (trans->PowerTransformerEnd.size() != 2) {
417 SPDLOG_LOGGER_WARN(
418 mSLog,
419 "PowerTransformer {} does not have exactly two windings, ignoring",
420 trans->name);
421 return nullptr;
422 }
423 SPDLOG_LOGGER_INFO(mSLog, "Found PowerTransformer {}", trans->name);
424
425 // assign transformer ends
426 CIMPP::PowerTransformerEnd *end1 = nullptr, *end2 = nullptr;
427 for (auto end : trans->PowerTransformerEnd) {
428 if (end->Terminal->sequenceNumber == 1)
429 end1 = end;
430 else if (end->Terminal->sequenceNumber == 2)
431 end2 = end;
432 else
433 return nullptr;
434 }
435
436 // setting default values for non-set resistances and reactances
437 SPDLOG_LOGGER_INFO(mSLog, " PowerTransformerEnd_1 {}", end1->name);
438 SPDLOG_LOGGER_INFO(mSLog, " Srated={} Vrated={}",
439 (float)end1->ratedS.value, (float)end1->ratedU.value);
440 try {
441 SPDLOG_LOGGER_INFO(mSLog, " R={}", (float)end1->r.value);
442 } catch (ReadingUninitializedField *e1) {
443 end1->r.value = 1e-12;
444 SPDLOG_LOGGER_WARN(mSLog,
445 " Uninitialized value for PowerTrafoEnd1 setting "
446 "default value of R={}",
447 (float)end1->r.value);
448 }
449 try {
450 SPDLOG_LOGGER_INFO(mSLog, " X={}", (float)end1->x.value);
451 } catch (ReadingUninitializedField *e1) {
452 end1->x.value = 1e-12;
453 SPDLOG_LOGGER_WARN(mSLog,
454 " Uninitialized value for PowerTrafoEnd1 setting "
455 "default value of X={}",
456 (float)end1->x.value);
457 }
458 SPDLOG_LOGGER_INFO(mSLog, " PowerTransformerEnd_2 {}", end2->name);
459 SPDLOG_LOGGER_INFO(mSLog, " Srated={} Vrated={}",
460 (float)end2->ratedS.value, (float)end2->ratedU.value);
461 try {
462 SPDLOG_LOGGER_INFO(mSLog, " R={}", (float)end2->r.value);
463 } catch (ReadingUninitializedField *e1) {
464 end2->r.value = 1e-12;
465 SPDLOG_LOGGER_WARN(mSLog,
466 " Uninitialized value for PowerTrafoEnd2 setting "
467 "default value of R={}",
468 (float)end2->r.value);
469 }
470 try {
471 SPDLOG_LOGGER_INFO(mSLog, " X={}", (float)end2->x.value);
472 } catch (ReadingUninitializedField *e1) {
473 end2->x.value = 1e-12;
474 SPDLOG_LOGGER_WARN(mSLog,
475 " Uninitialized value for PowerTrafoEnd2 setting "
476 "default value of X={}",
477 (float)end2->x.value);
478 }
479
480 if (end1->ratedS.value != end2->ratedS.value) {
481 SPDLOG_LOGGER_WARN(
482 mSLog,
483 " PowerTransformerEnds of {} come with distinct rated power values. "
484 "Using rated power of PowerTransformerEnd_1.",
485 trans->name);
486 }
487 Real ratedPower = unitValue(end1->ratedS.value, UnitMultiplier::M);
488 Real voltageNode1 = unitValue(end1->ratedU.value, UnitMultiplier::k);
489 Real voltageNode2 = unitValue(end2->ratedU.value, UnitMultiplier::k);
490
491 Real ratioAbsNominal = voltageNode1 / voltageNode2;
492 Real ratioAbs = ratioAbsNominal;
493
494 // use normalStep from RatioTapChanger
495 if (end1->RatioTapChanger) {
496 ratioAbs =
497 voltageNode1 / voltageNode2 *
498 (1 + (end1->RatioTapChanger->normalStep -
499 end1->RatioTapChanger->neutralStep) *
500 end1->RatioTapChanger->stepVoltageIncrement.value / 100);
501 }
502
503 // if corresponding SvTapStep available, use instead tap position from there
504 if (end1->RatioTapChanger) {
505 for (auto obj : mModel->Objects) {
506 auto tapStep = dynamic_cast<CIMPP::SvTapStep *>(obj);
507 if (tapStep && tapStep->TapChanger == end1->RatioTapChanger) {
508 ratioAbs =
509 voltageNode1 / voltageNode2 *
510 (1 + (tapStep->position - end1->RatioTapChanger->neutralStep) *
511 end1->RatioTapChanger->stepVoltageIncrement.value / 100);
512 }
513 }
514 }
515
516 // TODO: To be extracted from cim class
517 Real ratioPhase = 0;
518
519 // Calculate resistance and inductance referred to higher voltage side
520 Real resistance = 0;
521 Real inductance = 0;
522 if (voltageNode1 >= voltageNode2 && abs(end1->x.value) > 1e-12) {
523 inductance = end1->x.value / mOmega;
524 resistance = end1->r.value;
525 } else if (voltageNode1 >= voltageNode2 && abs(end2->x.value) > 1e-12) {
526 inductance = end2->x.value / mOmega * std::pow(ratioAbsNominal, 2);
527 resistance = end2->r.value * std::pow(ratioAbsNominal, 2);
528 } else if (voltageNode2 > voltageNode1 && abs(end2->x.value) > 1e-12) {
529 inductance = end2->x.value / mOmega;
530 resistance = end2->r.value;
531 } else if (voltageNode2 > voltageNode1 && abs(end1->x.value) > 1e-12) {
532 inductance = end1->x.value / mOmega / std::pow(ratioAbsNominal, 2);
533 resistance = end1->r.value / std::pow(ratioAbsNominal, 2);
534 }
535
536 if (mDomain == Domain::EMT) {
537 if (mPhase == PhaseType::ABC) {
538 Matrix resistance_3ph =
540 Matrix inductance_3ph =
542 Bool withResistiveLosses = resistance > 0;
543 auto transformer = std::make_shared<EMT::Ph3::Transformer>(
544 trans->mRID, trans->name, mComponentLogLevel, withResistiveLosses);
545 transformer->setParameters(voltageNode1, voltageNode2, ratedPower,
546 ratioAbs, ratioPhase, resistance_3ph,
547 inductance_3ph);
548 return transformer;
549 } else {
550 SPDLOG_LOGGER_INFO(mSLog, " Transformer for EMT not implemented yet");
551 return nullptr;
552 }
553 } else if (mDomain == Domain::SP) {
554 auto transformer = std::make_shared<SP::Ph1::Transformer>(
555 trans->mRID, trans->name, mComponentLogLevel);
556 transformer->setParameters(voltageNode1, voltageNode2, ratedPower, ratioAbs,
557 ratioPhase, resistance, inductance);
558 Real baseVolt = voltageNode1 >= voltageNode2 ? voltageNode1 : voltageNode2;
559 transformer->setBaseVoltage(baseVolt);
560 return transformer;
561 } else {
562 Bool withResistiveLosses = resistance > 0;
563 auto transformer = std::make_shared<DP::Ph1::Transformer>(
564 trans->mRID, trans->name, mComponentLogLevel, withResistiveLosses);
565 transformer->setParameters(voltageNode1, voltageNode2, ratedPower, ratioAbs,
566 ratioPhase, resistance, inductance);
567 return transformer;
568 }
569}
570
571TopologicalPowerComp::Ptr
572Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) {
573 SPDLOG_LOGGER_INFO(mSLog, " Found Synchronous machine {}", machine->name);
574
575 if (mDomain == Domain::DP) {
576 SPDLOG_LOGGER_INFO(mSLog, " Create generator in DP domain.");
577 if (mGeneratorType == GeneratorType::TransientStability ||
578 mGeneratorType == GeneratorType::SG6aOrderVBR ||
579 mGeneratorType == GeneratorType::SG6bOrderVBR ||
580 mGeneratorType == GeneratorType::SG4OrderVBR ||
581 mGeneratorType == GeneratorType::SG3OrderVBR ||
582 mGeneratorType == GeneratorType::SG4OrderPCM ||
583 mGeneratorType == GeneratorType::SG4OrderTPM ||
584 mGeneratorType == GeneratorType::SG6OrderPCM) {
585
586 Real ratedPower = unitValue(machine->ratedS.value, UnitMultiplier::M);
587 Real ratedVoltage = unitValue(machine->ratedU.value, UnitMultiplier::k);
588
589 for (auto obj : mModel->Objects) {
590 // Check if object is not TopologicalNode, SvVoltage or SvPowerFlow
591 if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn =
592 dynamic_cast<CIMPP::SynchronousMachineTimeConstantReactance *>(
593 obj)) {
594 if (genDyn->SynchronousMachine->mRID == machine->mRID) {
595 // stator
596 Real Rs = genDyn->statorResistance.value;
597 Real Ll = genDyn->statorLeakageReactance.value;
598
599 // reactances
600 Real Ld = genDyn->xDirectSync.value;
601 Real Lq = genDyn->xQuadSync.value;
602 Real Ld_t = genDyn->xDirectTrans.value;
603 Real Lq_t = genDyn->xQuadTrans.value;
604 Real Ld_s = genDyn->xDirectSubtrans.value;
605 Real Lq_s = genDyn->xQuadSubtrans.value;
606
607 // time constants
608 Real Td0_t = genDyn->tpdo.value;
609 Real Tq0_t = genDyn->tpqo.value;
610 Real Td0_s = genDyn->tppdo.value;
611 Real Tq0_s = genDyn->tppqo.value;
612
613 // inertia
614 Real H = genDyn->inertia.value;
615
616 // not available in CIM -> set to 0, as actually no impact on machine equations
617 Int poleNum = 0;
618 Real nomFieldCurr = 0;
619
620 if (mGeneratorType == GeneratorType::TransientStability) {
621 SPDLOG_LOGGER_DEBUG(mSLog,
622 " GeneratorType is TransientStability.");
623 auto gen = DP::Ph1::SynchronGeneratorTrStab::make(
624 machine->mRID, machine->name, mComponentLogLevel);
625 gen->setStandardParametersPU(ratedPower, ratedVoltage, mFrequency,
626 Ld_t, H);
627 return gen;
628 } else if (mGeneratorType == GeneratorType::SG6aOrderVBR) {
629 SPDLOG_LOGGER_DEBUG(
630 mSLog, " GeneratorType is SynchronGenerator6aOrderVBR.");
631 auto gen = std::make_shared<DP::Ph1::SynchronGenerator6aOrderVBR>(
632 machine->mRID, machine->name, mComponentLogLevel);
633 gen->setOperationalParametersPerUnit(
634 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
635 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
636 return gen;
637 } else if (mGeneratorType == GeneratorType::SG6bOrderVBR) {
638 SPDLOG_LOGGER_DEBUG(
639 mSLog, " GeneratorType is SynchronGenerator6bOrderVBR.");
640 auto gen = std::make_shared<DP::Ph1::SynchronGenerator6bOrderVBR>(
641 machine->mRID, machine->name, mComponentLogLevel);
642 gen->setOperationalParametersPerUnit(
643 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
644 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
645 return gen;
646 } else if (mGeneratorType == GeneratorType::SG5OrderVBR) {
647 SPDLOG_LOGGER_DEBUG(
648 mSLog, " GeneratorType is SynchronGenerator5OrderVBR.");
649 auto gen = std::make_shared<DP::Ph1::SynchronGenerator5OrderVBR>(
650 machine->mRID, machine->name, mComponentLogLevel);
651 gen->setOperationalParametersPerUnit(
652 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
653 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0);
654 return gen;
655 } else if (mGeneratorType == GeneratorType::SG4OrderVBR) {
656 SPDLOG_LOGGER_DEBUG(
657 mSLog, " GeneratorType is SynchronGenerator4OrderVBR.");
658 auto gen = std::make_shared<DP::Ph1::SynchronGenerator4OrderVBR>(
659 machine->mRID, machine->name, mComponentLogLevel);
660 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
661 mFrequency, H, Ld, Lq, Ll,
662 Ld_t, Lq_t, Td0_t, Tq0_t);
663 return gen;
664 } else if (mGeneratorType == GeneratorType::SG3OrderVBR) {
665 SPDLOG_LOGGER_DEBUG(
666 mSLog, " GeneratorType is SynchronGenerator3OrderVBR.");
667 auto gen = std::make_shared<DP::Ph1::SynchronGenerator3OrderVBR>(
668 machine->mRID, machine->name, mComponentLogLevel);
669 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
670 mFrequency, H, Ld, Lq, Ll,
671 Ld_t, Td0_t);
672 return gen;
673 } else if (mGeneratorType == GeneratorType::SG4OrderPCM) {
674 SPDLOG_LOGGER_DEBUG(
675 mSLog, " GeneratorType is SynchronGenerator4OrderPCM.");
676 auto gen = std::make_shared<DP::Ph1::SynchronGenerator4OrderPCM>(
677 machine->mRID, machine->name, mComponentLogLevel);
678 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
679 mFrequency, H, Ld, Lq, Ll,
680 Ld_t, Lq_t, Td0_t, Tq0_t);
681 return gen;
682 } else if (mGeneratorType == GeneratorType::SG4OrderTPM) {
683 SPDLOG_LOGGER_DEBUG(
684 mSLog, " GeneratorType is SynchronGenerator4OrderTPM.");
685 auto gen = std::make_shared<DP::Ph1::SynchronGenerator4OrderTPM>(
686 machine->mRID, machine->name, mComponentLogLevel);
687 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
688 mFrequency, H, Ld, Lq, Ll,
689 Ld_t, Lq_t, Td0_t, Tq0_t);
690 return gen;
691 } else if (mGeneratorType == GeneratorType::SG6OrderPCM) {
692 SPDLOG_LOGGER_DEBUG(
693 mSLog, " GeneratorType is SynchronGenerator6OrderPCM.");
694 auto gen = std::make_shared<DP::Ph1::SynchronGenerator6OrderPCM>(
695 machine->mRID, machine->name, mComponentLogLevel);
696 gen->setOperationalParametersPerUnit(
697 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
698 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
699 return gen;
700 }
701 }
702 }
703 }
704 } else if (mGeneratorType == GeneratorType::IdealVoltageSource) {
705 SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is IdealVoltageSource.");
706 return std::make_shared<DP::Ph1::SynchronGeneratorIdeal>(
707 machine->mRID, machine->name, mComponentLogLevel);
708 } else if (mGeneratorType == GeneratorType::None) {
709 throw SystemError("GeneratorType is None. Specify!");
710 } else {
711 throw SystemError("GeneratorType setting unfeasible.");
712 }
713 } else if (mDomain == Domain::SP) {
714 SPDLOG_LOGGER_INFO(mSLog, " Create generator in SP domain.");
715 if (mGeneratorType == GeneratorType::TransientStability ||
716 mGeneratorType == GeneratorType::SG6aOrderVBR ||
717 mGeneratorType == GeneratorType::SG6bOrderVBR ||
718 mGeneratorType == GeneratorType::SG5OrderVBR ||
719 mGeneratorType == GeneratorType::SG4OrderVBR ||
720 mGeneratorType == GeneratorType::SG3OrderVBR) {
721
722 Real ratedPower = unitValue(machine->ratedS.value, UnitMultiplier::M);
723 Real ratedVoltage = unitValue(machine->ratedU.value, UnitMultiplier::k);
724
725 for (auto obj : mModel->Objects) {
726 // Check if object is not TopologicalNode, SvVoltage or SvPowerFlow
727 if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn =
728 dynamic_cast<CIMPP::SynchronousMachineTimeConstantReactance *>(
729 obj)) {
730 if (genDyn->SynchronousMachine->mRID == machine->mRID) {
731 // stator
732 Real Rs = genDyn->statorResistance.value;
733 Real Ll = genDyn->statorLeakageReactance.value;
734
735 // reactances
736 Real Ld = genDyn->xDirectSync.value;
737 Real Lq = genDyn->xQuadSync.value;
738 Real Ld_t = genDyn->xDirectTrans.value;
739 Real Lq_t = genDyn->xQuadTrans.value;
740 Real Ld_s = genDyn->xDirectSubtrans.value;
741 Real Lq_s = genDyn->xQuadSubtrans.value;
742
743 // time constants
744 Real Td0_t = genDyn->tpdo.value;
745 Real Tq0_t = genDyn->tpqo.value;
746 Real Td0_s = genDyn->tppdo.value;
747 Real Tq0_s = genDyn->tppqo.value;
748
749 // inertia
750 Real H = genDyn->inertia.value;
751
752 // not available in CIM -> set to 0, as actually no impact on machine equations
753 Int poleNum = 0;
754 Real nomFieldCurr = 0;
755
756 if (mGeneratorType == GeneratorType::TransientStability) {
757 SPDLOG_LOGGER_DEBUG(mSLog,
758 " GeneratorType is TransientStability.");
759 auto gen = SP::Ph1::SynchronGeneratorTrStab::make(
760 machine->mRID, machine->name, mComponentLogLevel);
761 gen->setStandardParametersPU(ratedPower, ratedVoltage, mFrequency,
762 Ld_t, H);
763 return gen;
764 } else if (mGeneratorType == GeneratorType::SG6aOrderVBR) {
765 SPDLOG_LOGGER_DEBUG(
766 mSLog, " GeneratorType is SynchronGenerator6aOrderVBR.");
767 auto gen = std::make_shared<SP::Ph1::SynchronGenerator6aOrderVBR>(
768 machine->mRID, machine->name, mComponentLogLevel);
769 gen->setOperationalParametersPerUnit(
770 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
771 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
772 return gen;
773 } else if (mGeneratorType == GeneratorType::SG6bOrderVBR) {
774 SPDLOG_LOGGER_DEBUG(
775 mSLog, " GeneratorType is SynchronGenerator6bOrderVBR.");
776 auto gen = std::make_shared<SP::Ph1::SynchronGenerator6bOrderVBR>(
777 machine->mRID, machine->name, mComponentLogLevel);
778 gen->setOperationalParametersPerUnit(
779 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
780 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
781 return gen;
782 } else if (mGeneratorType == GeneratorType::SG5OrderVBR) {
783 SPDLOG_LOGGER_DEBUG(
784 mSLog, " GeneratorType is SynchronGenerator5OrderVBR.");
785 auto gen = std::make_shared<SP::Ph1::SynchronGenerator5OrderVBR>(
786 machine->mRID, machine->name, mComponentLogLevel);
787 gen->setOperationalParametersPerUnit(
788 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
789 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0);
790 return gen;
791 } else if (mGeneratorType == GeneratorType::SG4OrderVBR) {
792 SPDLOG_LOGGER_DEBUG(
793 mSLog, " GeneratorType is SynchronGenerator4OrderVBR.");
794 auto gen = std::make_shared<SP::Ph1::SynchronGenerator4OrderVBR>(
795 machine->mRID, machine->name, mComponentLogLevel);
796 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
797 mFrequency, H, Ld, Lq, Ll,
798 Ld_t, Lq_t, Td0_t, Tq0_t);
799 return gen;
800 } else if (mGeneratorType == GeneratorType::SG3OrderVBR) {
801 SPDLOG_LOGGER_DEBUG(
802 mSLog, " GeneratorType is SynchronGenerator3OrderVBR.");
803 auto gen = std::make_shared<SP::Ph1::SynchronGenerator3OrderVBR>(
804 machine->mRID, machine->name, mComponentLogLevel);
805 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
806 mFrequency, H, Ld, Lq, Ll,
807 Ld_t, Td0_t);
808 return gen;
809 }
810 }
811 }
812 }
813 } else if (mGeneratorType == GeneratorType::PVNode) {
814 SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is PVNode.");
815 for (auto obj : mModel->Objects) {
816 if (CIMPP::GeneratingUnit *genUnit =
817 dynamic_cast<CIMPP::GeneratingUnit *>(obj)) {
818 for (auto syncGen : genUnit->RotatingMachine) {
819 if (syncGen->mRID == machine->mRID) {
820 // Check whether relevant input data are set, otherwise set default values
821 Real setPointActivePower = 0;
822 Real setPointVoltage = 0;
823 Real maximumReactivePower = 1e12;
824 try {
825 setPointActivePower =
826 unitValue(genUnit->initialP.value, UnitMultiplier::M);
827 SPDLOG_LOGGER_INFO(mSLog, " setPointActivePower={}",
828 setPointActivePower);
829 } catch (ReadingUninitializedField *e) {
830 std::cerr
831 << "Uninitalized setPointActivePower for GeneratingUnit "
832 << machine->name << ". Using default value of "
833 << setPointActivePower << std::endl;
834 }
835 if (machine->RegulatingControl) {
836 setPointVoltage =
837 unitValue(machine->RegulatingControl->targetValue.value,
838 UnitMultiplier::k);
839 SPDLOG_LOGGER_INFO(mSLog, " setPointVoltage={}",
840 setPointVoltage);
841 } else {
842 std::cerr << "Uninitalized setPointVoltage for GeneratingUnit "
843 << machine->name << ". Using default value of "
844 << setPointVoltage << std::endl;
845 }
846 try {
847 maximumReactivePower =
848 unitValue(machine->maxQ.value, UnitMultiplier::M);
849 SPDLOG_LOGGER_INFO(mSLog, " maximumReactivePower={}",
850 maximumReactivePower);
851 } catch (ReadingUninitializedField *e) {
852 std::cerr
853 << "Uninitalized maximumReactivePower for GeneratingUnit "
854 << machine->name << ". Using default value of "
855 << maximumReactivePower << std::endl;
856 }
857
858 auto gen = std::make_shared<SP::Ph1::SynchronGenerator>(
859 machine->mRID, machine->name, mComponentLogLevel);
860 gen->setParameters(
861 unitValue(machine->ratedS.value, UnitMultiplier::M),
862 unitValue(machine->ratedU.value, UnitMultiplier::k),
863 setPointActivePower, setPointVoltage, PowerflowBusType::PV);
864 gen->setBaseVoltage(
865 unitValue(machine->ratedU.value, UnitMultiplier::k));
866 return gen;
867 }
868 }
869 }
870 }
871 SPDLOG_LOGGER_INFO(mSLog, "no corresponding initial power for {}",
872 machine->name);
873 return std::make_shared<SP::Ph1::SynchronGenerator>(
874 machine->mRID, machine->name, mComponentLogLevel);
875 } else if (mGeneratorType == GeneratorType::None) {
876 throw SystemError("GeneratorType is None. Specify!");
877 } else {
878 throw SystemError("GeneratorType setting unfeasible.");
879 }
880 } else {
881 SPDLOG_LOGGER_INFO(mSLog, " Create generator in EMT domain.");
882 if (mGeneratorType == GeneratorType::FullOrder ||
883 mGeneratorType == GeneratorType::FullOrderVBR ||
884 mGeneratorType == GeneratorType::SG3OrderVBR ||
885 mGeneratorType == GeneratorType::SG4OrderVBR ||
886 mGeneratorType == GeneratorType::SG6aOrderVBR ||
887 mGeneratorType == GeneratorType::SG6bOrderVBR) {
888
889 Real ratedPower = unitValue(machine->ratedS.value, UnitMultiplier::M);
890 Real ratedVoltage = unitValue(machine->ratedU.value, UnitMultiplier::k);
891
892 for (auto obj : mModel->Objects) {
893 // Check if object is not TopologicalNode, SvVoltage or SvPowerFlow
894 if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn =
895 dynamic_cast<CIMPP::SynchronousMachineTimeConstantReactance *>(
896 obj)) {
897 if (genDyn->SynchronousMachine->mRID == machine->mRID) {
898
899 // stator
900 Real Rs = genDyn->statorResistance.value;
901 Real Ll = genDyn->statorLeakageReactance.value;
902
903 // reactances
904 Real Ld = genDyn->xDirectSync.value;
905 Real Lq = genDyn->xQuadSync.value;
906 Real Ld_t = genDyn->xDirectTrans.value;
907 Real Lq_t = genDyn->xQuadTrans.value;
908 Real Ld_s = genDyn->xDirectSubtrans.value;
909 Real Lq_s = genDyn->xQuadSubtrans.value;
910
911 // time constants
912 Real Td0_t = genDyn->tpdo.value;
913 Real Tq0_t = genDyn->tpqo.value;
914 Real Td0_s = genDyn->tppdo.value;
915 Real Tq0_s = genDyn->tppqo.value;
916
917 // inertia
918 Real H = genDyn->inertia.value;
919
920 // not available in CIM -> set to 0, as actually no impact on machine equations
921 Int poleNum = 0;
922 Real nomFieldCurr = 0;
923
924 if (mGeneratorType == GeneratorType::FullOrder) {
925 SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is FullOrder.");
926 auto gen = std::make_shared<EMT::Ph3::SynchronGeneratorDQTrapez>(
927 machine->mRID, machine->name, mComponentLogLevel);
928 gen->setParametersOperationalPerUnit(
929 ratedPower, ratedVoltage, mFrequency, poleNum, nomFieldCurr,
930 Rs, Ld, Lq, Ld_t, Lq_t, Ld_s, Lq_s, Ll, Td0_t, Tq0_t, Td0_s,
931 Tq0_s, H);
932 return gen;
933 } else if (mGeneratorType == GeneratorType::FullOrderVBR) {
934 SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is FullOrderVBR.");
935 auto gen = std::make_shared<EMT::Ph3::SynchronGeneratorVBR>(
936 machine->mRID, machine->name, mComponentLogLevel);
937 gen->setBaseAndOperationalPerUnitParameters(
938 ratedPower, ratedVoltage, mFrequency, poleNum, nomFieldCurr,
939 Rs, Ld, Lq, Ld_t, Lq_t, Ld_s, Lq_s, Ll, Td0_t, Tq0_t, Td0_s,
940 Tq0_s, H);
941 return gen;
942 } else if (mGeneratorType == GeneratorType::SG6aOrderVBR) {
943 SPDLOG_LOGGER_DEBUG(
944 mSLog, " GeneratorType is SynchronGenerator6aOrderVBR.");
945 auto gen =
946 std::make_shared<EMT::Ph3::SynchronGenerator6aOrderVBR>(
947 machine->mRID, machine->name, mComponentLogLevel);
948 gen->setOperationalParametersPerUnit(
949 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
950 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
951 return gen;
952 } else if (mGeneratorType == GeneratorType::SG6bOrderVBR) {
953 SPDLOG_LOGGER_DEBUG(
954 mSLog, " GeneratorType is SynchronGenerator6bOrderVBR.");
955 auto gen =
956 std::make_shared<EMT::Ph3::SynchronGenerator6bOrderVBR>(
957 machine->mRID, machine->name, mComponentLogLevel);
958 gen->setOperationalParametersPerUnit(
959 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
960 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
961 return gen;
962 } else if (mGeneratorType == GeneratorType::SG5OrderVBR) {
963 SPDLOG_LOGGER_DEBUG(
964 mSLog, " GeneratorType is SynchronGenerator5OrderVBR.");
965 auto gen = std::make_shared<EMT::Ph3::SynchronGenerator5OrderVBR>(
966 machine->mRID, machine->name, mComponentLogLevel);
967 gen->setOperationalParametersPerUnit(
968 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
969 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0);
970 return gen;
971 } else if (mGeneratorType == GeneratorType::SG4OrderVBR) {
972 SPDLOG_LOGGER_DEBUG(
973 mSLog, " GeneratorType is SynchronGenerator4OrderVBR.");
974 auto gen = std::make_shared<EMT::Ph3::SynchronGenerator4OrderVBR>(
975 machine->mRID, machine->name, mComponentLogLevel);
976 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
977 mFrequency, H, Ld, Lq, Ll,
978 Ld_t, Lq_t, Td0_t, Tq0_t);
979 return gen;
980 } else if (mGeneratorType == GeneratorType::SG3OrderVBR) {
981 SPDLOG_LOGGER_DEBUG(
982 mSLog, " GeneratorType is SynchronGenerator3OrderVBR.");
983 auto gen = std::make_shared<EMT::Ph3::SynchronGenerator3OrderVBR>(
984 machine->mRID, machine->name, mComponentLogLevel);
985 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
986 mFrequency, H, Ld, Lq, Ll,
987 Ld_t, Td0_t);
988 return gen;
989 }
990 }
991 }
992 }
993 } else if (mGeneratorType == GeneratorType::IdealVoltageSource) {
994 SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is IdealVoltageSource.");
995 return std::make_shared<EMT::Ph3::SynchronGeneratorIdeal>(
996 machine->mRID, machine->name, mComponentLogLevel,
997 GeneratorType::IdealVoltageSource);
998 } else if (mGeneratorType == GeneratorType::IdealCurrentSource) {
999 SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is IdealCurrentSource.");
1000 return std::make_shared<EMT::Ph3::SynchronGeneratorIdeal>(
1001 machine->mRID, machine->name, mComponentLogLevel,
1002 GeneratorType::IdealCurrentSource);
1003 } else if (mGeneratorType == GeneratorType::None) {
1004 throw SystemError("GeneratorType is None. Specify!");
1005 } else {
1006 throw SystemError("GeneratorType setting unfeasible.");
1007 }
1008 }
1009 return nullptr;
1010}
1011
1012TopologicalPowerComp::Ptr
1013Reader::mapExternalNetworkInjection(CIMPP::ExternalNetworkInjection *extnet) {
1014 SPDLOG_LOGGER_INFO(mSLog, "Found External Network Injection {}",
1015 extnet->name);
1016
1017 Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(extnet);
1018
1019 if (mDomain == Domain::EMT) {
1020 if (mPhase == PhaseType::ABC) {
1021 return std::make_shared<EMT::Ph3::NetworkInjection>(
1022 extnet->mRID, extnet->name, mComponentLogLevel);
1023 } else {
1024 throw SystemError(
1025 "Mapping of ExternalNetworkInjection for EMT::Ph1 not existent!");
1026 return nullptr;
1027 }
1028 } else if (mDomain == Domain::SP) {
1029 if (mPhase == PhaseType::Single) {
1030 auto cpsextnet = std::make_shared<SP::Ph1::NetworkInjection>(
1031 extnet->mRID, extnet->name, mComponentLogLevel);
1032 cpsextnet->modifyPowerFlowBusType(
1033 PowerflowBusType::
1034 VD); // for powerflow solver set as VD component as default
1035 cpsextnet->setBaseVoltage(baseVoltage);
1036
1037 try {
1038 if (extnet->RegulatingControl) {
1039 SPDLOG_LOGGER_INFO(mSLog, " Voltage set-point={}",
1040 (float)extnet->RegulatingControl->targetValue);
1041 cpsextnet->setParameters(
1042 extnet->RegulatingControl->targetValue *
1043 baseVoltage); // assumes that value is specified in CIM data in per unit
1044 } else {
1045 SPDLOG_LOGGER_INFO(
1046 mSLog, " No voltage set-point defined. Using 1 per unit.");
1047 cpsextnet->setParameters(1. * baseVoltage);
1048 }
1049 } catch (ReadingUninitializedField *e) {
1050 std::cerr << "Ignore incomplete RegulatingControl" << std::endl;
1051 }
1052
1053 return cpsextnet;
1054 } else {
1055 throw SystemError(
1056 "Mapping of ExternalNetworkInjection for SP::Ph3 not existent!");
1057 return nullptr;
1058 }
1059 } else {
1060 if (mPhase == PhaseType::Single) {
1061 return std::make_shared<DP::Ph1::NetworkInjection>(
1062 extnet->mRID, extnet->name, mComponentLogLevel);
1063 } else {
1064 throw SystemError(
1065 "Mapping of ExternalNetworkInjection for DP::Ph3 not existent!");
1066 return nullptr;
1067 }
1068 }
1069}
1070
1071TopologicalPowerComp::Ptr
1072Reader::mapEquivalentShunt(CIMPP::EquivalentShunt *shunt) {
1073 SPDLOG_LOGGER_INFO(mSLog, "Found shunt {}", shunt->name);
1074
1075 Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(shunt);
1076
1077 auto cpsShunt = std::make_shared<SP::Ph1::Shunt>(shunt->mRID, shunt->name,
1078 mComponentLogLevel);
1079 cpsShunt->setParameters(shunt->g.value, shunt->b.value);
1080 cpsShunt->setBaseVoltage(baseVoltage);
1081 return cpsShunt;
1082}
1083
1084Real Reader::determineBaseVoltageAssociatedWithEquipment(
1085 CIMPP::ConductingEquipment *equipment) {
1086 Real baseVoltage = 0;
1087
1088 // first look for baseVolt object to determine baseVoltage
1089 for (auto obj : mModel->Objects) {
1090 if (CIMPP::BaseVoltage *baseVolt =
1091 dynamic_cast<CIMPP::BaseVoltage *>(obj)) {
1092 for (auto comp : baseVolt->ConductingEquipment) {
1093 if (comp->name == equipment->name) {
1094 baseVoltage =
1095 unitValue(baseVolt->nominalVoltage.value, UnitMultiplier::k);
1096 }
1097 }
1098 }
1099 }
1100 // as second option take baseVoltage of topologicalNode where equipment is connected to
1101 if (baseVoltage == 0) {
1102 for (auto obj : mModel->Objects) {
1103 if (CIMPP::TopologicalNode *topNode =
1104 dynamic_cast<CIMPP::TopologicalNode *>(obj)) {
1105 for (auto term : topNode->Terminal) {
1106 if (term->ConductingEquipment->name == equipment->name) {
1107 baseVoltage = unitValue(topNode->BaseVoltage->nominalVoltage.value,
1108 UnitMultiplier::k);
1109 }
1110 }
1111 }
1112 }
1113 }
1114
1115 return baseVoltage;
1116}
1117
1118template <typename VarType>
1119void Reader::processTopologicalNode(CIMPP::TopologicalNode *topNode) {
1120 // Add this node to global node list and assign simulation node incrementally.
1121 int matrixNodeIndex = Int(mPowerflowNodes.size());
1122 mPowerflowNodes[topNode->mRID] = SimNode<VarType>::make(
1123 topNode->mRID, topNode->name, matrixNodeIndex, mPhase);
1124
1125 if (mPhase == PhaseType::ABC) {
1126 SPDLOG_LOGGER_INFO(
1127 mSLog, "TopologicalNode {} phase A as simulation node {} ",
1128 topNode->mRID,
1129 mPowerflowNodes[topNode->mRID]->matrixNodeIndex(PhaseType::A));
1130 SPDLOG_LOGGER_INFO(
1131 mSLog, "TopologicalNode {} phase B as simulation node {}",
1132 topNode->mRID,
1133 mPowerflowNodes[topNode->mRID]->matrixNodeIndex(PhaseType::B));
1134 SPDLOG_LOGGER_INFO(
1135 mSLog, "TopologicalNode {} phase C as simulation node {}",
1136 topNode->mRID,
1137 mPowerflowNodes[topNode->mRID]->matrixNodeIndex(PhaseType::C));
1138 } else
1139 SPDLOG_LOGGER_INFO(mSLog,
1140 "TopologicalNode id: {}, name: {} as simulation node {}",
1141 topNode->mRID, topNode->name,
1142 mPowerflowNodes[topNode->mRID]->matrixNodeIndex());
1143
1144 for (auto term : topNode->Terminal) {
1145 // Insert Terminal if it does not exist in the map and add reference to node.
1146 // This could be optimized because the Terminal is searched twice.
1147 auto cpsTerm = SimTerminal<VarType>::make(term->mRID);
1148 mPowerflowTerminals.insert(std::make_pair(term->mRID, cpsTerm));
1149 cpsTerm->setNode(std::dynamic_pointer_cast<SimNode<VarType>>(
1150 mPowerflowNodes[topNode->mRID]));
1151
1152 if (!term->sequenceNumber.initialized)
1153 term->sequenceNumber = 1;
1154
1155 SPDLOG_LOGGER_INFO(mSLog, " Terminal {}, sequenceNumber {}", term->mRID,
1156 (int)term->sequenceNumber);
1157
1158 // Try to process Equipment connected to Terminal.
1159 CIMPP::ConductingEquipment *equipment = term->ConductingEquipment;
1160 if (!equipment) {
1161 SPDLOG_LOGGER_WARN(mSLog, "Terminal {} has no Equipment, ignoring!",
1162 term->mRID);
1163 } else {
1164 // Insert Equipment if it does not exist in the map and add reference to Terminal.
1165 // This could be optimized because the Equipment is searched twice.
1166 if (mPowerflowEquipment.find(equipment->mRID) ==
1167 mPowerflowEquipment.end()) {
1168 TopologicalPowerComp::Ptr comp = mapComponent(equipment);
1169 if (comp) {
1170 mPowerflowEquipment.insert(std::make_pair(equipment->mRID, comp));
1171 } else {
1172 SPDLOG_LOGGER_WARN(mSLog, "Could not map equipment {}",
1173 equipment->mRID);
1174 continue;
1175 }
1176 }
1177
1178 auto pfEquipment = mPowerflowEquipment.at(equipment->mRID);
1179 if (pfEquipment == nullptr) {
1180 SPDLOG_LOGGER_ERROR(mSLog, "Equipment {} is null in equipment list",
1181 equipment->mRID);
1182 throw SystemError("Equipment is null in equipment list.");
1183 }
1184 std::dynamic_pointer_cast<SimPowerComp<VarType>>(pfEquipment)
1185 ->setTerminalAt(std::dynamic_pointer_cast<SimTerminal<VarType>>(
1186 mPowerflowTerminals[term->mRID]),
1187 term->sequenceNumber - 1);
1188
1189 SPDLOG_LOGGER_INFO(mSLog, " Added Terminal {} to Equipment {}",
1190 term->mRID, equipment->mRID);
1191 }
1192 }
1193}
1194
1195template void
1196Reader::processTopologicalNode<Real>(CIMPP::TopologicalNode *topNode);
1197template void
1198Reader::processTopologicalNode<Complex>(CIMPP::TopologicalNode *topNode);
void setShuntConductance(Real v)
set shunt conductance value
Definition Reader.cpp:50
SystemTopology loadCIM(Real systemFrequency, const fs::path &filename, Domain domain=Domain::DP, PhaseType phase=PhaseType::Single, GeneratorType genType=GeneratorType::None)
Parses data from CIM files into the CPS data structure.
Definition Reader.cpp:209
void useProtectionSwitches(Bool value=true)
If set, some components like loads include protection switches.
Definition Reader.cpp:56
Reader(String name, Logger::Level logLevel=Logger::Level::info, Logger::Level componentLogLevel=Logger::Level::off)
Definition Reader.cpp:21
void setShuntCapacitor(Real v)
set shunt capacitor value
Definition Reader.cpp:45
static Matrix singlePhaseParameterToThreePhase(Real parameter)
To convert single phase parameters to symmetrical three phase ones.