9#include <CIMExceptions.hpp>
10#include <CIMModel.hpp>
11#include <IEC61970.hpp>
15#include <dpsim-models/CIM/Reader.h>
18using namespace CPS::CIM;
21using CIMPP::UnitMultiplier;
24 Logger::Level componentLogLevel) {
25 mSLog = Logger::get(name +
"_CIM", logLevel);
27 mModel =
new CIMModel();
28 mModel->setDependencyCheckOff();
29 mComponentLogLevel = componentLogLevel;
32Reader::~Reader() {
delete mModel; }
35 const std::list<CPS::String> &filenamesString,
36 Domain domain, PhaseType phase,
37 GeneratorType genType) {
38 std::list<fs::path> filenames;
39 for (
auto f : filenamesString)
40 filenames.emplace_back(f);
42 return loadCIM(systemFrequency, filenames, domain, phase, genType);
48 mShuntCapacitorValue = v;
49 mSetShuntCapacitor =
true;
53 mShuntConductanceValue = v;
54 mSetShuntConductance =
true;
59 mUseProtectionSwitches = value;
62void Reader::setExtnetVoltageTargetUnit(VoltageTargetUnit unit) {
63 mExtnetVoltageTargetUnit = unit;
66Real Reader::unitValue(Real value, CIMPP::UnitMultiplier mult) {
68 case UnitMultiplier::p:
71 case UnitMultiplier::n:
74 case UnitMultiplier::micro:
77 case UnitMultiplier::m:
80 case UnitMultiplier::c:
83 case UnitMultiplier::d:
86 case UnitMultiplier::k:
89 case UnitMultiplier::M:
92 case UnitMultiplier::G:
95 case UnitMultiplier::T:
104Bool Reader::isSupportedConductingEquipment(BaseClass *obj)
const {
108 if (
dynamic_cast<CIMPP::ACLineSegment *
>(obj))
111 if (
dynamic_cast<CIMPP::EnergyConsumer *
>(obj))
114 if (
dynamic_cast<CIMPP::PowerTransformer *
>(obj))
117 if (
dynamic_cast<CIMPP::SynchronousMachine *
>(obj))
120 if (
dynamic_cast<CIMPP::ExternalNetworkInjection *
>(obj))
123 if (
dynamic_cast<CIMPP::EquivalentShunt *
>(obj))
126 if (
dynamic_cast<CIMPP::Disconnector *
>(obj))
129 if (
dynamic_cast<CIMPP::Breaker *
>(obj))
135TopologicalPowerComp::Ptr Reader::mapComponent(BaseClass *obj) {
136 if (CIMPP::ACLineSegment *line =
dynamic_cast<CIMPP::ACLineSegment *
>(obj))
137 return mapACLineSegment(line);
138 if (CIMPP::EnergyConsumer *consumer =
139 dynamic_cast<CIMPP::EnergyConsumer *
>(obj))
140 return mapEnergyConsumer(consumer);
141 if (CIMPP::PowerTransformer *trans =
142 dynamic_cast<CIMPP::PowerTransformer *
>(obj))
143 return mapPowerTransformer(trans);
144 if (CIMPP::SynchronousMachine *syncMachine =
145 dynamic_cast<CIMPP::SynchronousMachine *
>(obj))
146 return mapSynchronousMachine(syncMachine);
147 if (CIMPP::ExternalNetworkInjection *extnet =
148 dynamic_cast<CIMPP::ExternalNetworkInjection *
>(obj))
149 return mapExternalNetworkInjection(extnet);
150 if (CIMPP::EquivalentShunt *shunt =
151 dynamic_cast<CIMPP::EquivalentShunt *
>(obj))
152 return mapEquivalentShunt(shunt);
153 if (CIMPP::Disconnector *disc =
dynamic_cast<CIMPP::Disconnector *
>(obj))
154 return mapDisconnector(disc);
155 if (CIMPP::Breaker *cb =
dynamic_cast<CIMPP::Breaker *
>(obj))
156 return mapBreaker(cb);
160void Reader::addFiles(
const fs::path &filename) {
161 if (!mModel->addCIMFile(filename.string()))
162 SPDLOG_LOGGER_ERROR(mSLog,
"Failed to read file {}", filename);
165void Reader::addFiles(
const std::list<fs::path> &filenames) {
166 for (
auto filename : filenames)
170void Reader::parseFiles() {
172 mModel->parseFiles();
174 SPDLOG_LOGGER_ERROR(mSLog,
"Failed to parse CIM files");
180 "#### List of TopologicalNodes, associated Terminals and Equipment");
181 for (
auto obj : mModel->Objects) {
182 if (CIMPP::TopologicalNode *topNode =
183 dynamic_cast<CIMPP::TopologicalNode *
>(obj)) {
184 if (mDomain == Domain::EMT)
185 processTopologicalNode<Real>(topNode);
187 processTopologicalNode<Complex>(topNode);
193 SPDLOG_LOGGER_INFO(mSLog,
194 "#### List of Node voltages and Terminal power flow data");
195 for (
auto obj : mModel->Objects) {
197 if (CIMPP::SvVoltage *volt =
dynamic_cast<CIMPP::SvVoltage *
>(obj)) {
198 processSvVoltage(volt);
201 else if (CIMPP::SvPowerFlow *flow =
202 dynamic_cast<CIMPP::SvPowerFlow *
>(obj)) {
203 processSvPowerFlow(flow);
207 SPDLOG_LOGGER_INFO(mSLog,
"#### Create other components");
208 for (
auto obj : mModel->Objects) {
211 if (!
dynamic_cast<CIMPP::TopologicalNode *
>(obj) &&
212 !
dynamic_cast<CIMPP::SvVoltage *
>(obj) &&
213 !
dynamic_cast<CIMPP::SvPowerFlow *
>(obj)) {
215 if (CIMPP::IdentifiedObject *idObj =
216 dynamic_cast<CIMPP::IdentifiedObject *
>(obj)) {
219 const auto &rid = cimString(idObj->mRID);
220 if (mPowerflowEquipment.find(rid) == mPowerflowEquipment.end()) {
221 TopologicalPowerComp::Ptr comp = mapComponent(obj);
223 mPowerflowEquipment.insert(std::make_pair(comp->uid(), comp));
229 SPDLOG_LOGGER_INFO(mSLog,
"#### Check topology for unconnected components");
230 for (
auto pfe : mPowerflowEquipment) {
233 if (mDomain == Domain::EMT) {
234 if (SimPowerComp<Real>::Ptr powercomp =
235 std::dynamic_pointer_cast<SimPowerComp<Real>>(c)) {
236 if (powercomp->terminalNumberConnected() < powercomp->terminalNumber())
237 throw InvalidTopology();
240 if (SimPowerComp<Complex>::Ptr powercomp =
241 std::dynamic_pointer_cast<SimPowerComp<Complex>>(c)) {
242 if (powercomp->terminalNumberConnected() < powercomp->terminalNumber())
243 throw InvalidTopology();
250 Domain domain, PhaseType phase,
251 GeneratorType genType) {
252 mFrequency = systemFrequency;
253 mOmega = 2 * PI * mFrequency;
256 mGeneratorType = genType;
259 return systemTopology();
263 const std::list<fs::path> &filenames,
264 Domain domain, PhaseType phase,
265 GeneratorType genType) {
266 mFrequency = systemFrequency;
267 mOmega = 2 * PI * mFrequency;
270 mGeneratorType = genType;
273 return systemTopology();
276void Reader::processSvVoltage(CIMPP::SvVoltage *volt) {
277 CIMPP::TopologicalNode *node = volt->TopologicalNode;
280 mSLog,
"SvVoltage references missing Topological Node, ignoring");
283 const auto &nodeRid = cimString(node->mRID);
284 auto search = mPowerflowNodes.find(nodeRid);
285 if (search == mPowerflowNodes.end()) {
286 SPDLOG_LOGGER_WARN(mSLog,
287 "SvVoltage references Topological Node {}"
288 " missing from mTopNodes, ignoring",
293 Real voltageAbs = Reader::unitValue(volt->v.value, UnitMultiplier::k);
296 SPDLOG_LOGGER_INFO(mSLog,
" Angle={}", (
float)volt->angle.value);
297 }
catch (ReadingUninitializedField *e) {
298 volt->angle.value = 0;
299 std::cerr <<
"Uninitialized Angle for SVVoltage at "
300 << volt->TopologicalNode->name <<
".Setting default value of "
301 << volt->angle.value << std::endl;
303 Real voltagePhase = volt->angle.value * PI / 180;
304 mPowerflowNodes[nodeRid]->setInitialVoltage(
305 std::polar<Real>(voltageAbs, voltagePhase));
308 mSLog,
"Node {} MatrixNodeIndex {}: {} V, {} deg",
309 mPowerflowNodes[nodeRid]->uid(),
310 mPowerflowNodes[nodeRid]->matrixNodeIndex(),
311 std::abs(mPowerflowNodes[nodeRid]->initialSingleVoltage()),
312 std::arg(mPowerflowNodes[nodeRid]->initialSingleVoltage()) * 180 / PI);
315void Reader::processSvPowerFlow(CIMPP::SvPowerFlow *flow) {
317 SPDLOG_LOGGER_WARN(mSLog,
"Cannot process null SvPowerFlow, ignoring");
321 CIMPP::Terminal *term = flow->Terminal;
324 SPDLOG_LOGGER_WARN(mSLog,
325 "SvPowerFlow references missing Terminal, ignoring");
329 const auto &terminalRid = cimString(term->mRID);
330 auto terminalIt = mPowerflowTerminals.find(terminalRid);
332 if (terminalIt == mPowerflowTerminals.end() || !terminalIt->second) {
333 SPDLOG_LOGGER_WARN(mSLog,
334 "SvPowerFlow references Terminal {} missing from "
335 "mPowerflowTerminals, ignoring",
340 terminalIt->second->setPower(
341 Complex(Reader::unitValue(flow->p.value, UnitMultiplier::M),
342 Reader::unitValue(flow->q.value, UnitMultiplier::M)));
344 SPDLOG_LOGGER_INFO(mSLog,
"Terminal {}: {} W + j {} Var", terminalRid,
345 terminalIt->second->singleActivePower(),
346 terminalIt->second->singleReactivePower());
349SystemTopology Reader::systemTopology() {
350 SystemTopology system(mFrequency);
352 for (
auto comp : mPowerflowEquipment) {
353 system.addComponent(comp.second);
355 if (SimPowerComp<Complex>::Ptr powercomp =
356 std::dynamic_pointer_cast<SimPowerComp<Complex>>(comp.second)) {
357 for (
auto term : powercomp->topologicalTerminals()) {
358 TopologicalNode::Ptr node = term->topologicalNodes();
360 if (system.mComponentsAtNode.find(node) ==
361 system.mComponentsAtNode.end()) {
362 TopologicalPowerComp::List complist;
363 complist.push_back(powercomp);
364 system.mComponentsAtNode.insert(std::make_pair(node, complist));
366 system.mComponentsAtNode[node].push_back(powercomp);
372 system.mNodes.resize(mPowerflowNodes.size());
374 for (
auto node : mPowerflowNodes) {
377 system.addNodeAt(node.second, node.second->matrixNodeIndex());
383Matrix::Index Reader::mapTopologicalNode(String mrid) {
384 auto search = mPowerflowNodes.find(mrid);
385 if (search == mPowerflowNodes.end()) {
388 return search->second->matrixNodeIndex();
391TopologicalPowerComp::Ptr
392Reader::mapEnergyConsumer(CIMPP::EnergyConsumer *consumer) {
393 const auto &consumerName = cimString(consumer->name);
394 const auto &consumerRid = cimString(consumer->mRID);
396 SPDLOG_LOGGER_INFO(mSLog,
" Found EnergyConsumer {}", consumerName);
397 if (mDomain == Domain::EMT) {
398 if (mPhase == PhaseType::ABC) {
399 return std::make_shared<EMT::Ph3::RXLoad>(consumerRid, consumerName,
402 SPDLOG_LOGGER_INFO(mSLog,
" RXLoad for EMT not implemented yet");
403 return std::make_shared<DP::Ph1::RXLoad>(consumerRid, consumerName,
406 }
else if (mDomain == Domain::SP) {
407 auto load = std::make_shared<SP::Ph1::Load>(consumerRid, consumerName,
413 if (consumer->p.initialized || consumer->q.initialized) {
416 if (consumer->p.initialized)
417 p = unitValue(consumer->p.value, UnitMultiplier::M);
418 if (consumer->q.initialized)
419 q = unitValue(consumer->q.value, UnitMultiplier::M);
420 Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(consumer);
421 load->setParameters(p, q, baseVoltage);
424 load->modifyPowerFlowBusType(
429 if (mUseProtectionSwitches)
430 return std::make_shared<DP::Ph1::RXLoadSwitch>(consumerRid, consumerName,
433 return std::make_shared<DP::Ph1::RXLoad>(consumerRid, consumerName,
438TopologicalPowerComp::Ptr Reader::mapACLineSegment(CIMPP::ACLineSegment *line) {
439 const auto &lineName = cimString(line->name);
440 const auto &lineRid = cimString(line->mRID);
442 SPDLOG_LOGGER_INFO(mSLog,
443 " Found ACLineSegment {} r={} x={} bch={} gch={}",
444 lineName, (
float)line->r.value, (
float)line->x.value,
445 (
float)line->bch.value, (
float)line->gch.value);
447 Real resistance = line->r.value;
448 Real inductance = line->x.value / mOmega;
452 Real capacitance = mShuntCapacitorValue;
453 Real conductance = mShuntConductanceValue;
455 if (line->bch.value > 1e-9 && !mSetShuntCapacitor)
456 capacitance = Real(line->bch.value / mOmega);
458 if (line->gch.value > 1e-9 && !mSetShuntConductance)
459 conductance = Real(line->gch.value);
461 Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(line);
463 if (mDomain == Domain::EMT) {
464 if (mPhase == PhaseType::ABC) {
471 auto cpsLine = std::make_shared<EMT::Ph3::PiLine>(lineRid, lineName,
473 cpsLine->setParameters(res_3ph, ind_3ph, cap_3ph, cond_3ph);
476 SPDLOG_LOGGER_INFO(mSLog,
" PiLine for EMT not implemented yet");
477 auto cpsLine = std::make_shared<DP::Ph1::PiLine>(lineRid, lineName,
479 cpsLine->setParameters(resistance, inductance, capacitance, conductance);
482 }
else if (mDomain == Domain::SP) {
483 auto cpsLine = std::make_shared<SP::Ph1::PiLine>(lineRid, lineName,
485 cpsLine->setParameters(resistance, inductance, capacitance, conductance);
486 cpsLine->setBaseVoltage(baseVoltage);
489 auto cpsLine = std::make_shared<DP::Ph1::PiLine>(lineRid, lineName,
491 cpsLine->setParameters(resistance, inductance, capacitance, conductance);
496TopologicalPowerComp::Ptr
497Reader::mapPowerTransformer(CIMPP::PowerTransformer *trans) {
498 const auto &transRid = cimString(trans->mRID);
499 if (trans->PowerTransformerEnd.size() != 2) {
502 "PowerTransformer {} does not have exactly two windings, ignoring",
503 cimString(trans->name));
506 SPDLOG_LOGGER_INFO(mSLog,
"Found PowerTransformer {}",
507 cimString(trans->name));
510 CIMPP::PowerTransformerEnd *end1 =
nullptr, *end2 =
nullptr;
511 for (
auto end : trans->PowerTransformerEnd) {
512 if (end->Terminal->sequenceNumber == 1)
514 else if (end->Terminal->sequenceNumber == 2)
521 SPDLOG_LOGGER_INFO(mSLog,
" PowerTransformerEnd_1 {}",
522 cimString(end1->name));
523 SPDLOG_LOGGER_INFO(mSLog,
" Srated={} Vrated={}",
524 (
float)end1->ratedS.value, (
float)end1->ratedU.value);
526 SPDLOG_LOGGER_INFO(mSLog,
" R={}", (
float)end1->r.value);
527 }
catch (ReadingUninitializedField *e1) {
528 end1->r.value = 1e-12;
529 SPDLOG_LOGGER_WARN(mSLog,
530 " Uninitialized value for PowerTrafoEnd1 setting "
531 "default value of R={}",
532 (
float)end1->r.value);
535 SPDLOG_LOGGER_INFO(mSLog,
" X={}", (
float)end1->x.value);
536 }
catch (ReadingUninitializedField *e1) {
537 end1->x.value = 1e-12;
538 SPDLOG_LOGGER_WARN(mSLog,
539 " Uninitialized value for PowerTrafoEnd1 setting "
540 "default value of X={}",
541 (
float)end1->x.value);
543 SPDLOG_LOGGER_INFO(mSLog,
" PowerTransformerEnd_2 {}",
544 cimString(end2->name));
545 SPDLOG_LOGGER_INFO(mSLog,
" Srated={} Vrated={}",
546 (
float)end2->ratedS.value, (
float)end2->ratedU.value);
548 SPDLOG_LOGGER_INFO(mSLog,
" R={}", (
float)end2->r.value);
549 }
catch (ReadingUninitializedField *e1) {
550 end2->r.value = 1e-12;
551 SPDLOG_LOGGER_WARN(mSLog,
552 " Uninitialized value for PowerTrafoEnd2 setting "
553 "default value of R={}",
554 (
float)end2->r.value);
557 SPDLOG_LOGGER_INFO(mSLog,
" X={}", (
float)end2->x.value);
558 }
catch (ReadingUninitializedField *e1) {
559 end2->x.value = 1e-12;
560 SPDLOG_LOGGER_WARN(mSLog,
561 " Uninitialized value for PowerTrafoEnd2 setting "
562 "default value of X={}",
563 (
float)end2->x.value);
566 if (end1->ratedS.value != end2->ratedS.value) {
569 " PowerTransformerEnds of {} come with distinct rated power values. "
570 "Using rated power of PowerTransformerEnd_1.",
571 cimString(trans->name));
573 Real ratedPower = unitValue(end1->ratedS.value, UnitMultiplier::M);
574 Real voltageNode1 = unitValue(end1->ratedU.value, UnitMultiplier::k);
575 Real voltageNode2 = unitValue(end2->ratedU.value, UnitMultiplier::k);
577 Real ratioAbsNominal = voltageNode1 / voltageNode2;
578 Real ratioAbs = ratioAbsNominal;
581 if (end1->RatioTapChanger) {
583 voltageNode1 / voltageNode2 *
584 (1 + (end1->RatioTapChanger->normalStep -
585 end1->RatioTapChanger->neutralStep) *
586 end1->RatioTapChanger->stepVoltageIncrement.value / 100);
590 if (end1->RatioTapChanger) {
591 for (
auto obj : mModel->Objects) {
592 auto tapStep =
dynamic_cast<CIMPP::SvTapStep *
>(obj);
593 if (tapStep && tapStep->TapChanger == end1->RatioTapChanger) {
595 voltageNode1 / voltageNode2 *
596 (1 + (tapStep->position - end1->RatioTapChanger->neutralStep) *
597 end1->RatioTapChanger->stepVoltageIncrement.value / 100);
608 if (voltageNode1 >= voltageNode2 && abs(end1->x.value) > 1e-12) {
609 inductance = end1->x.value / mOmega;
610 resistance = end1->r.value;
611 }
else if (voltageNode1 >= voltageNode2 && abs(end2->x.value) > 1e-12) {
612 inductance = end2->x.value / mOmega * std::pow(ratioAbsNominal, 2);
613 resistance = end2->r.value * std::pow(ratioAbsNominal, 2);
614 }
else if (voltageNode2 > voltageNode1 && abs(end2->x.value) > 1e-12) {
615 inductance = end2->x.value / mOmega;
616 resistance = end2->r.value;
617 }
else if (voltageNode2 > voltageNode1 && abs(end1->x.value) > 1e-12) {
618 inductance = end1->x.value / mOmega / std::pow(ratioAbsNominal, 2);
619 resistance = end1->r.value / std::pow(ratioAbsNominal, 2);
622 if (mDomain == Domain::EMT) {
623 if (mPhase == PhaseType::ABC) {
624 Matrix resistance_3ph =
626 Matrix inductance_3ph =
628 Bool withResistiveLosses = resistance > 0;
629 auto transformer = std::make_shared<EMT::Ph3::Transformer>(
630 transRid, cimString(trans->name), mComponentLogLevel,
631 withResistiveLosses);
632 transformer->setParameters(voltageNode1, voltageNode2, ratedPower,
633 ratioAbs, ratioPhase, resistance_3ph,
637 SPDLOG_LOGGER_INFO(mSLog,
" Transformer for EMT not implemented yet");
640 }
else if (mDomain == Domain::SP) {
641 auto transformer = std::make_shared<SP::Ph1::Transformer>(
642 transRid, cimString(trans->name), mComponentLogLevel);
643 transformer->setParameters(voltageNode1, voltageNode2, ratedPower, ratioAbs,
644 ratioPhase, resistance, inductance);
645 Real baseVolt = voltageNode1 >= voltageNode2 ? voltageNode1 : voltageNode2;
646 transformer->setBaseVoltage(baseVolt);
649 Bool withResistiveLosses = resistance > 0;
650 auto transformer = std::make_shared<DP::Ph1::Transformer>(
651 transRid, cimString(trans->name), mComponentLogLevel,
652 withResistiveLosses);
653 transformer->setParameters(voltageNode1, voltageNode2, ratedPower, ratioAbs,
654 ratioPhase, resistance, inductance);
659TopologicalPowerComp::Ptr
660Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) {
661 const auto &machineName = cimString(machine->name);
662 const auto &machineRid = cimString(machine->mRID);
664 SPDLOG_LOGGER_INFO(mSLog,
" Found Synchronous machine {}", machineName);
666 if (mDomain == Domain::DP) {
667 SPDLOG_LOGGER_INFO(mSLog,
" Create generator in DP domain.");
668 if (mGeneratorType == GeneratorType::TransientStability ||
669 mGeneratorType == GeneratorType::SG6aOrderVBR ||
670 mGeneratorType == GeneratorType::SG6bOrderVBR ||
671 mGeneratorType == GeneratorType::SG4OrderVBR ||
672 mGeneratorType == GeneratorType::SG3OrderVBR ||
673 mGeneratorType == GeneratorType::SG4OrderPCM ||
674 mGeneratorType == GeneratorType::SG4OrderTPM ||
675 mGeneratorType == GeneratorType::SG6OrderPCM) {
677 Real ratedPower = unitValue(machine->ratedS.value, UnitMultiplier::M);
678 Real ratedVoltage = unitValue(machine->ratedU.value, UnitMultiplier::k);
680 for (
auto obj : mModel->Objects) {
682 if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn =
683 dynamic_cast<CIMPP::SynchronousMachineTimeConstantReactance *
>(
685 if (cimString(genDyn->SynchronousMachine->mRID) == machineRid) {
687 Real Rs = genDyn->statorResistance.value;
688 Real Ll = genDyn->statorLeakageReactance.value;
691 Real Ld = genDyn->xDirectSync.value;
692 Real Lq = genDyn->xQuadSync.value;
693 Real Ld_t = genDyn->xDirectTrans.value;
694 Real Lq_t = genDyn->xQuadTrans.value;
695 Real Ld_s = genDyn->xDirectSubtrans.value;
696 Real Lq_s = genDyn->xQuadSubtrans.value;
699 Real Td0_t = genDyn->tpdo.value;
700 Real Tq0_t = genDyn->tpqo.value;
701 Real Td0_s = genDyn->tppdo.value;
702 Real Tq0_s = genDyn->tppqo.value;
705 Real H = genDyn->inertia.value;
709 Real nomFieldCurr = 0;
711 if (mGeneratorType == GeneratorType::TransientStability) {
712 SPDLOG_LOGGER_DEBUG(mSLog,
713 " GeneratorType is TransientStability.");
714 auto gen = DP::Ph1::SynchronGeneratorTrStab::make(
715 machineRid, machineName, mComponentLogLevel);
716 gen->setStandardParametersPU(ratedPower, ratedVoltage, mFrequency,
719 }
else if (mGeneratorType == GeneratorType::SG6aOrderVBR) {
721 mSLog,
" GeneratorType is SynchronGenerator6aOrderVBR.");
722 auto gen = std::make_shared<DP::Ph1::SynchronGenerator6aOrderVBR>(
723 machineRid, machineName, mComponentLogLevel);
724 gen->setOperationalParametersPerUnit(
725 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
726 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
728 }
else if (mGeneratorType == GeneratorType::SG6bOrderVBR) {
730 mSLog,
" GeneratorType is SynchronGenerator6bOrderVBR.");
731 auto gen = std::make_shared<DP::Ph1::SynchronGenerator6bOrderVBR>(
732 machineRid, machineName, mComponentLogLevel);
733 gen->setOperationalParametersPerUnit(
734 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
735 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
737 }
else if (mGeneratorType == GeneratorType::SG5OrderVBR) {
739 mSLog,
" GeneratorType is SynchronGenerator5OrderVBR.");
740 auto gen = std::make_shared<DP::Ph1::SynchronGenerator5OrderVBR>(
741 machineRid, machineName, mComponentLogLevel);
742 gen->setOperationalParametersPerUnit(
743 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
744 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0);
746 }
else if (mGeneratorType == GeneratorType::SG4OrderVBR) {
748 mSLog,
" GeneratorType is SynchronGenerator4OrderVBR.");
749 auto gen = std::make_shared<DP::Ph1::SynchronGenerator4OrderVBR>(
750 machineRid, machineName, mComponentLogLevel);
751 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
752 mFrequency, H, Ld, Lq, Ll,
753 Ld_t, Lq_t, Td0_t, Tq0_t);
755 }
else if (mGeneratorType == GeneratorType::SG3OrderVBR) {
757 mSLog,
" GeneratorType is SynchronGenerator3OrderVBR.");
758 auto gen = std::make_shared<DP::Ph1::SynchronGenerator3OrderVBR>(
759 machineRid, machineName, mComponentLogLevel);
760 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
761 mFrequency, H, Ld, Lq, Ll,
764 }
else if (mGeneratorType == GeneratorType::SG4OrderPCM) {
766 mSLog,
" GeneratorType is SynchronGenerator4OrderPCM.");
767 auto gen = std::make_shared<DP::Ph1::SynchronGenerator4OrderPCM>(
768 machineRid, machineName, mComponentLogLevel);
769 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
770 mFrequency, H, Ld, Lq, Ll,
771 Ld_t, Lq_t, Td0_t, Tq0_t);
773 }
else if (mGeneratorType == GeneratorType::SG4OrderTPM) {
775 mSLog,
" GeneratorType is SynchronGenerator4OrderTPM.");
776 auto gen = std::make_shared<DP::Ph1::SynchronGenerator4OrderTPM>(
777 machineRid, machineName, mComponentLogLevel);
778 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
779 mFrequency, H, Ld, Lq, Ll,
780 Ld_t, Lq_t, Td0_t, Tq0_t);
782 }
else if (mGeneratorType == GeneratorType::SG6OrderPCM) {
784 mSLog,
" GeneratorType is SynchronGenerator6OrderPCM.");
785 auto gen = std::make_shared<DP::Ph1::SynchronGenerator6OrderPCM>(
786 machineRid, machineName, 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);
795 }
else if (mGeneratorType == GeneratorType::IdealVoltageSource) {
796 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is IdealVoltageSource.");
797 return std::make_shared<DP::Ph1::SynchronGeneratorIdeal>(
798 machineRid, machineName, mComponentLogLevel);
799 }
else if (mGeneratorType == GeneratorType::None) {
800 throw SystemError(
"GeneratorType is None. Specify!");
802 throw SystemError(
"GeneratorType setting unfeasible.");
804 }
else if (mDomain == Domain::SP) {
805 SPDLOG_LOGGER_INFO(mSLog,
" Create generator in SP domain.");
806 if (mGeneratorType == GeneratorType::TransientStability ||
807 mGeneratorType == GeneratorType::SG6aOrderVBR ||
808 mGeneratorType == GeneratorType::SG6bOrderVBR ||
809 mGeneratorType == GeneratorType::SG5OrderVBR ||
810 mGeneratorType == GeneratorType::SG4OrderVBR ||
811 mGeneratorType == GeneratorType::SG3OrderVBR) {
813 Real ratedPower = unitValue(machine->ratedS.value, UnitMultiplier::M);
814 Real ratedVoltage = unitValue(machine->ratedU.value, UnitMultiplier::k);
816 for (
auto obj : mModel->Objects) {
818 if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn =
819 dynamic_cast<CIMPP::SynchronousMachineTimeConstantReactance *
>(
821 if (cimString(genDyn->SynchronousMachine->mRID) == machineRid) {
823 Real Rs = genDyn->statorResistance.value;
824 Real Ll = genDyn->statorLeakageReactance.value;
827 Real Ld = genDyn->xDirectSync.value;
828 Real Lq = genDyn->xQuadSync.value;
829 Real Ld_t = genDyn->xDirectTrans.value;
830 Real Lq_t = genDyn->xQuadTrans.value;
831 Real Ld_s = genDyn->xDirectSubtrans.value;
832 Real Lq_s = genDyn->xQuadSubtrans.value;
835 Real Td0_t = genDyn->tpdo.value;
836 Real Tq0_t = genDyn->tpqo.value;
837 Real Td0_s = genDyn->tppdo.value;
838 Real Tq0_s = genDyn->tppqo.value;
841 Real H = genDyn->inertia.value;
845 Real nomFieldCurr = 0;
847 if (mGeneratorType == GeneratorType::TransientStability) {
848 SPDLOG_LOGGER_DEBUG(mSLog,
849 " GeneratorType is TransientStability.");
850 auto gen = SP::Ph1::SynchronGeneratorTrStab::make(
851 machineRid, machineName, mComponentLogLevel);
852 gen->setStandardParametersPU(ratedPower, ratedVoltage, mFrequency,
855 }
else if (mGeneratorType == GeneratorType::SG6aOrderVBR) {
857 mSLog,
" GeneratorType is SynchronGenerator6aOrderVBR.");
858 auto gen = std::make_shared<SP::Ph1::SynchronGenerator6aOrderVBR>(
859 machineRid, machineName, mComponentLogLevel);
860 gen->setOperationalParametersPerUnit(
861 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
862 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
864 }
else if (mGeneratorType == GeneratorType::SG6bOrderVBR) {
866 mSLog,
" GeneratorType is SynchronGenerator6bOrderVBR.");
867 auto gen = std::make_shared<SP::Ph1::SynchronGenerator6bOrderVBR>(
868 machineRid, machineName, mComponentLogLevel);
869 gen->setOperationalParametersPerUnit(
870 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
871 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
873 }
else if (mGeneratorType == GeneratorType::SG5OrderVBR) {
875 mSLog,
" GeneratorType is SynchronGenerator5OrderVBR.");
876 auto gen = std::make_shared<SP::Ph1::SynchronGenerator5OrderVBR>(
877 machineRid, machineName, mComponentLogLevel);
878 gen->setOperationalParametersPerUnit(
879 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
880 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0);
882 }
else if (mGeneratorType == GeneratorType::SG4OrderVBR) {
884 mSLog,
" GeneratorType is SynchronGenerator4OrderVBR.");
885 auto gen = std::make_shared<SP::Ph1::SynchronGenerator4OrderVBR>(
886 machineRid, machineName, mComponentLogLevel);
887 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
888 mFrequency, H, Ld, Lq, Ll,
889 Ld_t, Lq_t, Td0_t, Tq0_t);
891 }
else if (mGeneratorType == GeneratorType::SG3OrderVBR) {
893 mSLog,
" GeneratorType is SynchronGenerator3OrderVBR.");
894 auto gen = std::make_shared<SP::Ph1::SynchronGenerator3OrderVBR>(
895 machineRid, machineName, mComponentLogLevel);
896 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
897 mFrequency, H, Ld, Lq, Ll,
904 }
else if (mGeneratorType == GeneratorType::PVNode) {
905 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is PVNode.");
906 for (
auto obj : mModel->Objects) {
907 if (CIMPP::GeneratingUnit *genUnit =
908 dynamic_cast<CIMPP::GeneratingUnit *
>(obj)) {
909 for (
auto syncGen : genUnit->RotatingMachine) {
910 if (cimString(syncGen->mRID) == machineRid) {
912 Real setPointActivePower = 0;
913 Real setPointVoltage = 0;
914 Real maximumReactivePower = 1e12;
915 PowerflowBusType busType = PowerflowBusType::PV;
917 setPointActivePower =
918 unitValue(genUnit->initialP.value, UnitMultiplier::M);
919 SPDLOG_LOGGER_INFO(mSLog,
" setPointActivePower={}",
920 setPointActivePower);
921 }
catch (ReadingUninitializedField *e) {
923 <<
"Uninitalized setPointActivePower for GeneratingUnit "
924 << machineName <<
". Using default value of "
925 << setPointActivePower << std::endl;
927 if (machine->RegulatingControl) {
929 unitValue(machine->RegulatingControl->targetValue.value,
931 SPDLOG_LOGGER_INFO(mSLog,
" setPointVoltage={}",
935 busType = PowerflowBusType::PQ;
938 " No RegulatingControl for {}, mapping as PQ generator",
942 maximumReactivePower =
943 unitValue(machine->maxQ.value, UnitMultiplier::M);
944 SPDLOG_LOGGER_INFO(mSLog,
" maximumReactivePower={}",
945 maximumReactivePower);
946 }
catch (ReadingUninitializedField *e) {
948 <<
"Uninitalized maximumReactivePower for GeneratingUnit "
949 << machineName <<
". Using default value of "
950 << maximumReactivePower << std::endl;
953 auto gen = std::make_shared<SP::Ph1::SynchronGenerator>(
954 machineRid, machineName, mComponentLogLevel);
956 unitValue(machine->ratedS.value, UnitMultiplier::M),
957 unitValue(machine->ratedU.value, UnitMultiplier::k),
958 setPointActivePower, setPointVoltage, busType);
960 unitValue(machine->ratedU.value, UnitMultiplier::k));
966 SPDLOG_LOGGER_INFO(mSLog,
"no corresponding initial power for {}",
968 return std::make_shared<SP::Ph1::SynchronGenerator>(
969 machineRid, machineName, mComponentLogLevel);
970 }
else if (mGeneratorType == GeneratorType::None) {
971 throw SystemError(
"GeneratorType is None. Specify!");
973 throw SystemError(
"GeneratorType setting unfeasible.");
976 SPDLOG_LOGGER_INFO(mSLog,
" Create generator in EMT domain.");
977 if (mGeneratorType == GeneratorType::FullOrder ||
978 mGeneratorType == GeneratorType::FullOrderVBR ||
979 mGeneratorType == GeneratorType::SG3OrderVBR ||
980 mGeneratorType == GeneratorType::SG4OrderVBR ||
981 mGeneratorType == GeneratorType::SG6aOrderVBR ||
982 mGeneratorType == GeneratorType::SG6bOrderVBR) {
984 Real ratedPower = unitValue(machine->ratedS.value, UnitMultiplier::M);
985 Real ratedVoltage = unitValue(machine->ratedU.value, UnitMultiplier::k);
987 for (
auto obj : mModel->Objects) {
989 if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn =
990 dynamic_cast<CIMPP::SynchronousMachineTimeConstantReactance *
>(
992 if (cimString(genDyn->SynchronousMachine->mRID) == machineRid) {
995 Real Rs = genDyn->statorResistance.value;
996 Real Ll = genDyn->statorLeakageReactance.value;
999 Real Ld = genDyn->xDirectSync.value;
1000 Real Lq = genDyn->xQuadSync.value;
1001 Real Ld_t = genDyn->xDirectTrans.value;
1002 Real Lq_t = genDyn->xQuadTrans.value;
1003 Real Ld_s = genDyn->xDirectSubtrans.value;
1004 Real Lq_s = genDyn->xQuadSubtrans.value;
1007 Real Td0_t = genDyn->tpdo.value;
1008 Real Tq0_t = genDyn->tpqo.value;
1009 Real Td0_s = genDyn->tppdo.value;
1010 Real Tq0_s = genDyn->tppqo.value;
1013 Real H = genDyn->inertia.value;
1017 Real nomFieldCurr = 0;
1019 if (mGeneratorType == GeneratorType::FullOrder) {
1020 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is FullOrder.");
1021 auto gen = std::make_shared<EMT::Ph3::SynchronGeneratorDQTrapez>(
1022 machineRid, machineName, mComponentLogLevel);
1023 gen->setParametersOperationalPerUnit(
1024 ratedPower, ratedVoltage, mFrequency, poleNum, nomFieldCurr,
1025 Rs, Ld, Lq, Ld_t, Lq_t, Ld_s, Lq_s, Ll, Td0_t, Tq0_t, Td0_s,
1028 }
else if (mGeneratorType == GeneratorType::FullOrderVBR) {
1029 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is FullOrderVBR.");
1030 auto gen = std::make_shared<EMT::Ph3::SynchronGeneratorVBR>(
1031 machineRid, machineName, mComponentLogLevel);
1032 gen->setBaseAndOperationalPerUnitParameters(
1033 ratedPower, ratedVoltage, mFrequency, poleNum, nomFieldCurr,
1034 Rs, Ld, Lq, Ld_t, Lq_t, Ld_s, Lq_s, Ll, Td0_t, Tq0_t, Td0_s,
1037 }
else if (mGeneratorType == GeneratorType::SG6aOrderVBR) {
1038 SPDLOG_LOGGER_DEBUG(
1039 mSLog,
" GeneratorType is SynchronGenerator6aOrderVBR.");
1041 std::make_shared<EMT::Ph3::SynchronGenerator6aOrderVBR>(
1042 machineRid, machineName, mComponentLogLevel);
1043 gen->setOperationalParametersPerUnit(
1044 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
1045 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
1047 }
else if (mGeneratorType == GeneratorType::SG6bOrderVBR) {
1048 SPDLOG_LOGGER_DEBUG(
1049 mSLog,
" GeneratorType is SynchronGenerator6bOrderVBR.");
1051 std::make_shared<EMT::Ph3::SynchronGenerator6bOrderVBR>(
1052 machineRid, machineName, mComponentLogLevel);
1053 gen->setOperationalParametersPerUnit(
1054 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
1055 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
1057 }
else if (mGeneratorType == GeneratorType::SG5OrderVBR) {
1058 SPDLOG_LOGGER_DEBUG(
1059 mSLog,
" GeneratorType is SynchronGenerator5OrderVBR.");
1060 auto gen = std::make_shared<EMT::Ph3::SynchronGenerator5OrderVBR>(
1061 machineRid, machineName, mComponentLogLevel);
1062 gen->setOperationalParametersPerUnit(
1063 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
1064 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0);
1066 }
else if (mGeneratorType == GeneratorType::SG4OrderVBR) {
1067 SPDLOG_LOGGER_DEBUG(
1068 mSLog,
" GeneratorType is SynchronGenerator4OrderVBR.");
1069 auto gen = std::make_shared<EMT::Ph3::SynchronGenerator4OrderVBR>(
1070 machineRid, machineName, mComponentLogLevel);
1071 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
1072 mFrequency, H, Ld, Lq, Ll,
1073 Ld_t, Lq_t, Td0_t, Tq0_t);
1075 }
else if (mGeneratorType == GeneratorType::SG3OrderVBR) {
1076 SPDLOG_LOGGER_DEBUG(
1077 mSLog,
" GeneratorType is SynchronGenerator3OrderVBR.");
1078 auto gen = std::make_shared<EMT::Ph3::SynchronGenerator3OrderVBR>(
1079 machineRid, machineName, mComponentLogLevel);
1080 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
1081 mFrequency, H, Ld, Lq, Ll,
1088 }
else if (mGeneratorType == GeneratorType::IdealVoltageSource) {
1089 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is IdealVoltageSource.");
1090 return std::make_shared<EMT::Ph3::SynchronGeneratorIdeal>(
1091 machineRid, machineName, mComponentLogLevel,
1092 GeneratorType::IdealVoltageSource);
1093 }
else if (mGeneratorType == GeneratorType::IdealCurrentSource) {
1094 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is IdealCurrentSource.");
1095 return std::make_shared<EMT::Ph3::SynchronGeneratorIdeal>(
1096 machineRid, machineName, mComponentLogLevel,
1097 GeneratorType::IdealCurrentSource);
1098 }
else if (mGeneratorType == GeneratorType::None) {
1099 throw SystemError(
"GeneratorType is None. Specify!");
1101 throw SystemError(
"GeneratorType setting unfeasible.");
1107TopologicalPowerComp::Ptr
1108Reader::mapExternalNetworkInjection(CIMPP::ExternalNetworkInjection *extnet) {
1109 SPDLOG_LOGGER_INFO(mSLog,
"Found External Network Injection {}",
1110 cimString(extnet->name));
1112 Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(extnet);
1114 if (mDomain == Domain::EMT) {
1115 if (mPhase == PhaseType::ABC) {
1116 return std::make_shared<EMT::Ph3::NetworkInjection>(
1117 extnet->mRID, extnet->name, mComponentLogLevel);
1120 "Mapping of ExternalNetworkInjection for EMT::Ph1 not existent!");
1123 }
else if (mDomain == Domain::SP) {
1124 if (mPhase == PhaseType::Single) {
1125 auto cpsextnet = std::make_shared<SP::Ph1::NetworkInjection>(
1126 extnet->mRID, extnet->name, mComponentLogLevel);
1127 cpsextnet->modifyPowerFlowBusType(
1130 cpsextnet->setBaseVoltage(baseVoltage);
1133 if (extnet->RegulatingControl) {
1135 Real rawTarget = extnet->RegulatingControl->targetValue.value;
1137 switch (mExtnetVoltageTargetUnit) {
1138 case VoltageTargetUnit::PerUnit:
1141 case VoltageTargetUnit::Absolute:
1144 case VoltageTargetUnit::Auto:
1146 perUnit = std::abs(rawTarget) >= 0.5 && std::abs(rawTarget) <= 1.5;
1149 Real voltageSetPoint = perUnit
1150 ? rawTarget * baseVoltage
1151 : unitValue(rawTarget, UnitMultiplier::k);
1152 SPDLOG_LOGGER_INFO(mSLog,
" Voltage set-point={}",
1154 cpsextnet->setParameters(voltageSetPoint);
1157 mSLog,
" No voltage set-point defined. Using 1 per unit.");
1158 cpsextnet->setParameters(1. * baseVoltage);
1160 }
catch (ReadingUninitializedField *e) {
1161 std::cerr <<
"Ignore incomplete RegulatingControl" << std::endl;
1167 "Mapping of ExternalNetworkInjection for SP::Ph3 not existent!");
1171 if (mPhase == PhaseType::Single) {
1172 return std::make_shared<DP::Ph1::NetworkInjection>(
1173 extnet->mRID, extnet->name, mComponentLogLevel);
1176 "Mapping of ExternalNetworkInjection for DP::Ph3 not existent!");
1182TopologicalPowerComp::Ptr
1183Reader::mapEquivalentShunt(CIMPP::EquivalentShunt *shunt) {
1184 SPDLOG_LOGGER_INFO(mSLog,
"Found shunt {}", cimString(shunt->name));
1186 Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(shunt);
1188 auto cpsShunt = std::make_shared<SP::Ph1::Shunt>(shunt->mRID, shunt->name,
1189 mComponentLogLevel);
1190 cpsShunt->setParameters(shunt->g.value, shunt->b.value);
1191 cpsShunt->setBaseVoltage(baseVoltage);
1195TopologicalPowerComp::Ptr Reader::mapDisconnector(CIMPP::Disconnector *disc) {
1197 SPDLOG_LOGGER_INFO(mSLog,
"Found Disconnector {} with status {}",
1198 cimString(disc->name), (
bool)disc->open.value);
1200 Real openResistance = 1e12;
1201 Real closedResistance = 1e-6;
1203 Bool status = disc->open.value;
1205 if (mPhase == PhaseType::ABC) {
1206 Matrix openResistance3Ph =
1208 Matrix closedResistance3Ph =
1211 if (mDomain == Domain::EMT) {
1212 auto cpsSwitch = std::make_shared<EMT::Ph3::Switch>(
1213 disc->mRID, disc->name, mComponentLogLevel);
1215 cpsSwitch->setParameters(openResistance3Ph, closedResistance3Ph);
1217 if (status ==
true) {
1218 cpsSwitch->openSwitch();
1220 cpsSwitch->closeSwitch();
1224 }
else if (mDomain == Domain::DP) {
1225 SPDLOG_LOGGER_INFO(mSLog,
1226 "Mapping of Disconnector for DP::Ph3 not existent!");
1230 SPDLOG_LOGGER_INFO(mSLog,
1231 "Mapping of Disconnector for SP::Ph3 not existent!");
1235 std::shared_ptr<CPS::TopologicalPowerComp> topoSwitch;
1236 std::shared_ptr<CPS::Base::Ph1::Switch> cpsSwitch;
1238 if (mDomain == Domain::EMT) {
1239 auto sw = std::make_shared<EMT::Ph1::Switch>(disc->mRID, disc->name,
1240 mComponentLogLevel);
1243 }
else if (mDomain == Domain::DP) {
1244 auto sw = std::make_shared<DP::Ph1::Switch>(disc->mRID, disc->name,
1245 mComponentLogLevel);
1249 auto sw = std::make_shared<SP::Ph1::Switch>(disc->mRID, disc->name,
1250 mComponentLogLevel);
1255 cpsSwitch->setParameters(openResistance, closedResistance);
1266TopologicalPowerComp::Ptr Reader::mapBreaker(CIMPP::Breaker *cb) {
1267 SPDLOG_LOGGER_INFO(mSLog,
"Found Breaker {} with status {}",
1268 cimString(cb->name), (
bool)cb->open.value);
1270 Real openResistance = 1e12;
1271 Real closedResistance = 1e-6;
1273 Bool status = cb->open.value;
1275 if (mPhase == PhaseType::ABC) {
1276 Matrix openResistance3Ph =
1278 Matrix closedResistance3Ph =
1281 if (mDomain == Domain::EMT) {
1282 auto cpsSwitch = std::make_shared<EMT::Ph3::Switch>(cb->mRID, cb->name,
1283 mComponentLogLevel);
1285 cpsSwitch->setParameters(openResistance3Ph, closedResistance3Ph);
1287 if (status ==
true) {
1288 cpsSwitch->openSwitch();
1290 cpsSwitch->closeSwitch();
1294 }
else if (mDomain == Domain::DP) {
1295 SPDLOG_LOGGER_INFO(mSLog,
"Mapping of Breaker for DP::Ph3 not existent!");
1299 SPDLOG_LOGGER_INFO(mSLog,
"Mapping of Breaker for SP::Ph3 not existent!");
1303 std::shared_ptr<CPS::TopologicalPowerComp> topoSwitch;
1304 std::shared_ptr<CPS::Base::Ph1::Switch> cpsSwitch;
1306 if (mDomain == Domain::EMT) {
1307 auto sw = std::make_shared<EMT::Ph1::Switch>(cb->mRID, cb->name,
1308 mComponentLogLevel);
1311 }
else if (mDomain == Domain::DP) {
1312 auto sw = std::make_shared<DP::Ph1::Switch>(cb->mRID, cb->name,
1313 mComponentLogLevel);
1317 auto sw = std::make_shared<SP::Ph1::Switch>(cb->mRID, cb->name,
1318 mComponentLogLevel);
1323 cpsSwitch->setParameters(openResistance, closedResistance);
1334Real Reader::determineBaseVoltageAssociatedWithEquipment(
1335 CIMPP::ConductingEquipment *equipment) {
1336 Real baseVoltage = 0;
1339 for (
auto obj : mModel->Objects) {
1340 if (CIMPP::BaseVoltage *baseVolt =
1341 dynamic_cast<CIMPP::BaseVoltage *
>(obj)) {
1342 for (
auto comp : baseVolt->ConductingEquipment) {
1343 if (cimString(comp->name) == cimString(equipment->name)) {
1345 unitValue(baseVolt->nominalVoltage.value, UnitMultiplier::k);
1351 if (baseVoltage == 0) {
1352 for (
auto obj : mModel->Objects) {
1353 if (CIMPP::TopologicalNode *topNode =
1354 dynamic_cast<CIMPP::TopologicalNode *
>(obj)) {
1355 for (
auto term : topNode->Terminal) {
1356 if (cimString(term->ConductingEquipment->name) ==
1357 cimString(equipment->name)) {
1358 baseVoltage = unitValue(topNode->BaseVoltage->nominalVoltage.value,
1369template <
typename VarType>
1370void Reader::processTopologicalNode(CIMPP::TopologicalNode *topNode) {
1374 SPDLOG_LOGGER_WARN(mSLog,
"Cannot process null TopologicalNode, ignoring");
1378 Bool hasSupportedEquipment =
false;
1380 for (
auto term : topNode->Terminal) {
1381 if (!term || !term->ConductingEquipment)
1384 if (isSupportedConductingEquipment(term->ConductingEquipment)) {
1385 hasSupportedEquipment =
true;
1390 if (!hasSupportedEquipment) {
1393 "Skipping TopologicalNode {} ({}) because it has no terminals "
1394 "connected to supported equipment",
1395 cimString(topNode->name), cimString(topNode->mRID));
1399 int matrixNodeIndex = Int(mPowerflowNodes.size());
1400 const auto &nodeRid = cimString(topNode->mRID);
1401 mPowerflowNodes[nodeRid] = SimNode<VarType>::make(
1402 nodeRid, cimString(topNode->name), matrixNodeIndex, mPhase);
1404 if (mPhase == PhaseType::ABC) {
1406 mSLog,
"TopologicalNode {} phase A as simulation node {} ", nodeRid,
1407 mPowerflowNodes[nodeRid]->matrixNodeIndex(PhaseType::A));
1409 mSLog,
"TopologicalNode {} phase B as simulation node {}", nodeRid,
1410 mPowerflowNodes[nodeRid]->matrixNodeIndex(PhaseType::B));
1412 mSLog,
"TopologicalNode {} phase C as simulation node {}", nodeRid,
1413 mPowerflowNodes[nodeRid]->matrixNodeIndex(PhaseType::C));
1415 SPDLOG_LOGGER_INFO(mSLog,
1416 "TopologicalNode id: {}, name: {} as simulation node {}",
1417 nodeRid, cimString(topNode->name),
1418 mPowerflowNodes[nodeRid]->matrixNodeIndex());
1420 for (
auto term : topNode->Terminal) {
1423 mSLog,
"TopologicalNode {} contains a null Terminal, ignoring",
1428 const auto &termRid = cimString(term->mRID);
1429 auto cpsTerm = SimTerminal<VarType>::make(termRid);
1430 mPowerflowTerminals.insert(std::make_pair(termRid, cpsTerm));
1432 std::dynamic_pointer_cast<SimNode<VarType>>(mPowerflowNodes[nodeRid]));
1434 if (!term->sequenceNumber.initialized)
1435 term->sequenceNumber = 1;
1437 SPDLOG_LOGGER_INFO(mSLog,
" Terminal {}, sequenceNumber {}", termRid,
1438 (
int)term->sequenceNumber);
1441 CIMPP::ConductingEquipment *equipment = term->ConductingEquipment;
1443 SPDLOG_LOGGER_WARN(mSLog,
"Terminal {} has no Equipment, ignoring!",
1449 if (!isSupportedConductingEquipment(equipment)) {
1452 "Terminal {} references unsupported ConductingEquipment {}, ignoring",
1453 termRid, cimString(equipment->mRID));
1459 const auto &equipmentRid = cimString(equipment->mRID);
1460 if (mPowerflowEquipment.find(equipmentRid) == mPowerflowEquipment.end()) {
1461 TopologicalPowerComp::Ptr comp = mapComponent(equipment);
1463 mPowerflowEquipment.insert(std::make_pair(equipmentRid, comp));
1465 SPDLOG_LOGGER_WARN(mSLog,
"Could not map equipment {}", equipmentRid);
1470 auto pfEquipment = mPowerflowEquipment.at(equipmentRid);
1471 if (pfEquipment ==
nullptr) {
1472 SPDLOG_LOGGER_ERROR(mSLog,
"Equipment {} is null in equipment list",
1474 throw SystemError(
"Equipment is null in equipment list.");
1476 std::dynamic_pointer_cast<SimPowerComp<VarType>>(pfEquipment)
1477 ->setTerminalAt(std::dynamic_pointer_cast<SimTerminal<VarType>>(
1478 mPowerflowTerminals[termRid]),
1479 term->sequenceNumber - 1);
1481 SPDLOG_LOGGER_INFO(mSLog,
" Added Terminal {} to Equipment {}",
1482 termRid, equipmentRid);
1487Reader::processTopologicalNode<Real>(CIMPP::TopologicalNode *topNode);
1489Reader::processTopologicalNode<Complex>(CIMPP::TopologicalNode *topNode);
void setShuntConductance(Real v)
set shunt conductance value
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.
void useProtectionSwitches(Bool value=true)
If set, some components like loads include protection switches.
Reader(String name, Logger::Level logLevel=Logger::Level::info, Logger::Level componentLogLevel=Logger::Level::off)
void setShuntCapacitor(Real v)
set shunt capacitor value
static Matrix singlePhaseParameterToThreePhase(Real parameter)
To convert single phase parameters to symmetrical three phase ones.