9 #include <CIMExceptions.hpp>
10 #include <CIMModel.hpp>
11 #include <IEC61970.hpp>
15 #include <dpsim-models/CIM/Reader.h>
18 using namespace CPS::CIM;
19 using CIMPP::UnitMultiplier;
22 Logger::Level componentLogLevel) {
23 mSLog = Logger::get(name +
"_CIM", logLevel);
25 mModel =
new CIMModel();
26 mModel->setDependencyCheckOff();
27 mComponentLogLevel = componentLogLevel;
30 Reader::~Reader() {
delete mModel; }
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);
40 return loadCIM(systemFrequency, filenames, domain, phase, genType);
46 mShuntCapacitorValue = v;
47 mSetShuntCapacitor =
true;
51 mShuntConductanceValue = v;
52 mSetShuntConductance =
true;
57 mUseProtectionSwitches = value;
60 Real Reader::unitValue(Real value, CIMPP::UnitMultiplier mult) {
62 case UnitMultiplier::p:
65 case UnitMultiplier::n:
68 case UnitMultiplier::micro:
71 case UnitMultiplier::m:
74 case UnitMultiplier::c:
77 case UnitMultiplier::d:
80 case UnitMultiplier::k:
83 case UnitMultiplier::M:
86 case UnitMultiplier::G:
89 case UnitMultiplier::T:
98 TopologicalPowerComp::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);
120 void Reader::addFiles(
const fs::path &filename) {
121 if (!mModel->addCIMFile(filename.string()))
122 SPDLOG_LOGGER_ERROR(mSLog,
"Failed to read file {}", filename);
125 void Reader::addFiles(
const std::list<fs::path> &filenames) {
126 for (
auto filename : filenames)
130 void Reader::parseFiles() {
132 mModel->parseFiles();
134 SPDLOG_LOGGER_ERROR(mSLog,
"Failed to parse CIM files");
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);
147 processTopologicalNode<Complex>(topNode);
153 SPDLOG_LOGGER_INFO(mSLog,
154 "#### List of Node voltages and Terminal power flow data");
155 for (
auto obj : mModel->Objects) {
157 if (CIMPP::SvVoltage *volt =
dynamic_cast<CIMPP::SvVoltage *
>(obj)) {
158 processSvVoltage(volt);
161 else if (CIMPP::SvPowerFlow *flow =
162 dynamic_cast<CIMPP::SvPowerFlow *
>(obj)) {
163 processSvPowerFlow(flow);
167 SPDLOG_LOGGER_INFO(mSLog,
"#### Create other components");
168 for (
auto obj : mModel->Objects) {
171 if (!
dynamic_cast<CIMPP::TopologicalNode *
>(obj) &&
172 !
dynamic_cast<CIMPP::SvVoltage *
>(obj) &&
173 !
dynamic_cast<CIMPP::SvPowerFlow *
>(obj)) {
175 if (CIMPP::IdentifiedObject *idObj =
176 dynamic_cast<CIMPP::IdentifiedObject *
>(obj)) {
179 if (mPowerflowEquipment.find(idObj->mRID) ==
180 mPowerflowEquipment.end()) {
181 TopologicalPowerComp::Ptr comp = mapComponent(obj);
183 mPowerflowEquipment.insert(std::make_pair(comp->uid(), comp));
189 SPDLOG_LOGGER_INFO(mSLog,
"#### Check topology for unconnected components");
190 for (
auto pfe : mPowerflowEquipment) {
193 if (mDomain == Domain::EMT) {
196 if (powercomp->terminalNumberConnected() < powercomp->terminalNumber())
202 if (powercomp->terminalNumberConnected() < powercomp->terminalNumber())
210 Domain domain, PhaseType phase,
211 GeneratorType genType) {
212 mFrequency = systemFrequency;
213 mOmega = 2 * PI * mFrequency;
216 mGeneratorType = genType;
219 return systemTopology();
223 const std::list<fs::path> &filenames,
224 Domain domain, PhaseType phase,
225 GeneratorType genType) {
226 mFrequency = systemFrequency;
227 mOmega = 2 * PI * mFrequency;
230 mGeneratorType = genType;
233 return systemTopology();
236 void Reader::processSvVoltage(CIMPP::SvVoltage *volt) {
237 CIMPP::TopologicalNode *node = volt->TopologicalNode;
240 mSLog,
"SvVoltage references missing Topological Node, ignoring");
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",
252 Real voltageAbs = Reader::unitValue(volt->v.value, UnitMultiplier::k);
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;
262 Real voltagePhase = volt->angle.value * PI / 180;
263 mPowerflowNodes[node->mRID]->setInitialVoltage(
264 std::polar<Real>(voltageAbs, voltagePhase));
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);
274 void Reader::processSvPowerFlow(CIMPP::SvPowerFlow *flow) {
275 CIMPP::Terminal *term = flow->Terminal;
277 mPowerflowTerminals[term->mRID]->setPower(
278 Complex(Reader::unitValue(flow->p.value, UnitMultiplier::M),
279 Reader::unitValue(flow->q.value, UnitMultiplier::M)));
281 SPDLOG_LOGGER_WARN(mSLog,
"Terminal {}: {} W + j {} Var", term->mRID,
282 mPowerflowTerminals[term->mRID]->singleActivePower(),
283 mPowerflowTerminals[term->mRID]->singleReactivePower());
289 for (
auto comp : mPowerflowEquipment) {
290 system.addComponent(comp.second);
294 for (
auto term : powercomp->topologicalTerminals()) {
295 TopologicalNode::Ptr node = term->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));
303 system.mComponentsAtNode[node].push_back(powercomp);
309 system.mNodes.resize(mPowerflowNodes.size());
311 for (
auto node : mPowerflowNodes) {
314 system.addNodeAt(node.second, node.second->matrixNodeIndex());
320 Matrix::Index Reader::mapTopologicalNode(String mrid) {
321 auto search = mPowerflowNodes.find(mrid);
322 if (search == mPowerflowNodes.end()) {
325 return search->second->matrixNodeIndex();
328 TopologicalPowerComp::Ptr
329 Reader::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,
336 SPDLOG_LOGGER_INFO(mSLog,
" RXLoad for EMT not implemented yet");
337 return std::make_shared<DP::Ph1::RXLoad>(consumer->mRID, consumer->name,
340 }
else if (mDomain == Domain::SP) {
341 auto load = std::make_shared<SP::Ph1::Load>(consumer->mRID, consumer->name,
358 load->modifyPowerFlowBusType(
363 if (mUseProtectionSwitches)
364 return std::make_shared<DP::Ph1::RXLoadSwitch>(
365 consumer->mRID, consumer->name, mComponentLogLevel);
367 return std::make_shared<DP::Ph1::RXLoad>(consumer->mRID, consumer->name,
372 TopologicalPowerComp::Ptr Reader::mapACLineSegment(CIMPP::ACLineSegment *line) {
373 SPDLOG_LOGGER_INFO(mSLog,
374 " Found ACLineSegment {} r={} x={} bch={} gch={}",
375 line->name, (
float)line->r.value, (
float)line->x.value,
376 (
float)line->bch.value, (
float)line->gch.value);
378 Real resistance = line->r.value;
379 Real inductance = line->x.value / mOmega;
383 Real capacitance = mShuntCapacitorValue;
384 Real conductance = mShuntConductanceValue;
386 if (line->bch.value > 1e-9 && !mSetShuntCapacitor)
387 capacitance = Real(line->bch.value / mOmega);
389 if (line->gch.value > 1e-9 && !mSetShuntConductance)
390 conductance = Real(line->gch.value);
392 Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(line);
394 if (mDomain == Domain::EMT) {
395 if (mPhase == PhaseType::ABC) {
402 auto cpsLine = std::make_shared<EMT::Ph3::PiLine>(line->mRID, line->name,
404 cpsLine->setParameters(res_3ph, ind_3ph, cap_3ph, cond_3ph);
407 SPDLOG_LOGGER_INFO(mSLog,
" PiLine for EMT not implemented yet");
408 auto cpsLine = std::make_shared<DP::Ph1::PiLine>(line->mRID, line->name,
410 cpsLine->setParameters(resistance, inductance, capacitance, conductance);
413 }
else if (mDomain == Domain::SP) {
414 auto cpsLine = std::make_shared<SP::Ph1::PiLine>(line->mRID, line->name,
416 cpsLine->setParameters(resistance, inductance, capacitance, conductance);
417 cpsLine->setBaseVoltage(baseVoltage);
420 auto cpsLine = std::make_shared<DP::Ph1::PiLine>(line->mRID, line->name,
422 cpsLine->setParameters(resistance, inductance, capacitance, conductance);
427 TopologicalPowerComp::Ptr
428 Reader::mapPowerTransformer(CIMPP::PowerTransformer *trans) {
429 if (trans->PowerTransformerEnd.size() != 2) {
432 "PowerTransformer {} does not have exactly two windings, ignoring",
436 SPDLOG_LOGGER_INFO(mSLog,
"Found PowerTransformer {}", trans->name);
439 CIMPP::PowerTransformerEnd *end1 =
nullptr, *end2 =
nullptr;
440 for (
auto end : trans->PowerTransformerEnd) {
441 if (end->Terminal->sequenceNumber == 1)
443 else if (end->Terminal->sequenceNumber == 2)
450 SPDLOG_LOGGER_INFO(mSLog,
" PowerTransformerEnd_1 {}", end1->name);
451 SPDLOG_LOGGER_INFO(mSLog,
" Srated={} Vrated={}",
452 (
float)end1->ratedS.value, (
float)end1->ratedU.value);
454 SPDLOG_LOGGER_INFO(mSLog,
" R={}", (
float)end1->r.value);
455 }
catch (ReadingUninitializedField *e1) {
456 end1->r.value = 1e-12;
457 SPDLOG_LOGGER_WARN(mSLog,
458 " Uninitialized value for PowerTrafoEnd1 setting "
459 "default value of R={}",
460 (
float)end1->r.value);
463 SPDLOG_LOGGER_INFO(mSLog,
" X={}", (
float)end1->x.value);
464 }
catch (ReadingUninitializedField *e1) {
465 end1->x.value = 1e-12;
466 SPDLOG_LOGGER_WARN(mSLog,
467 " Uninitialized value for PowerTrafoEnd1 setting "
468 "default value of X={}",
469 (
float)end1->x.value);
471 SPDLOG_LOGGER_INFO(mSLog,
" PowerTransformerEnd_2 {}", end2->name);
472 SPDLOG_LOGGER_INFO(mSLog,
" Srated={} Vrated={}",
473 (
float)end2->ratedS.value, (
float)end2->ratedU.value);
475 SPDLOG_LOGGER_INFO(mSLog,
" R={}", (
float)end2->r.value);
476 }
catch (ReadingUninitializedField *e1) {
477 end2->r.value = 1e-12;
478 SPDLOG_LOGGER_WARN(mSLog,
479 " Uninitialized value for PowerTrafoEnd2 setting "
480 "default value of R={}",
481 (
float)end2->r.value);
484 SPDLOG_LOGGER_INFO(mSLog,
" X={}", (
float)end2->x.value);
485 }
catch (ReadingUninitializedField *e1) {
486 end2->x.value = 1e-12;
487 SPDLOG_LOGGER_WARN(mSLog,
488 " Uninitialized value for PowerTrafoEnd2 setting "
489 "default value of X={}",
490 (
float)end2->x.value);
493 if (end1->ratedS.value != end2->ratedS.value) {
496 " PowerTransformerEnds of {} come with distinct rated power values. "
497 "Using rated power of PowerTransformerEnd_1.",
500 Real ratedPower = unitValue(end1->ratedS.value, UnitMultiplier::M);
501 Real voltageNode1 = unitValue(end1->ratedU.value, UnitMultiplier::k);
502 Real voltageNode2 = unitValue(end2->ratedU.value, UnitMultiplier::k);
504 Real ratioAbsNominal = voltageNode1 / voltageNode2;
505 Real ratioAbs = ratioAbsNominal;
508 if (end1->RatioTapChanger) {
510 voltageNode1 / voltageNode2 *
511 (1 + (end1->RatioTapChanger->normalStep -
512 end1->RatioTapChanger->neutralStep) *
513 end1->RatioTapChanger->stepVoltageIncrement.value / 100);
517 if (end1->RatioTapChanger) {
518 for (
auto obj : mModel->Objects) {
519 auto tapStep =
dynamic_cast<CIMPP::SvTapStep *
>(obj);
520 if (tapStep && tapStep->TapChanger == end1->RatioTapChanger) {
522 voltageNode1 / voltageNode2 *
523 (1 + (tapStep->position - end1->RatioTapChanger->neutralStep) *
524 end1->RatioTapChanger->stepVoltageIncrement.value / 100);
535 if (voltageNode1 >= voltageNode2 && abs(end1->x.value) > 1e-12) {
536 inductance = end1->x.value / mOmega;
537 resistance = end1->r.value;
538 }
else if (voltageNode1 >= voltageNode2 && abs(end2->x.value) > 1e-12) {
539 inductance = end2->x.value / mOmega * std::pow(ratioAbsNominal, 2);
540 resistance = end2->r.value * std::pow(ratioAbsNominal, 2);
541 }
else if (voltageNode2 > voltageNode1 && abs(end2->x.value) > 1e-12) {
542 inductance = end2->x.value / mOmega;
543 resistance = end2->r.value;
544 }
else if (voltageNode2 > voltageNode1 && abs(end1->x.value) > 1e-12) {
545 inductance = end1->x.value / mOmega / std::pow(ratioAbsNominal, 2);
546 resistance = end1->r.value / std::pow(ratioAbsNominal, 2);
549 if (mDomain == Domain::EMT) {
550 if (mPhase == PhaseType::ABC) {
551 Matrix resistance_3ph =
553 Matrix inductance_3ph =
555 Bool withResistiveLosses = resistance > 0;
556 auto transformer = std::make_shared<EMT::Ph3::Transformer>(
557 trans->mRID, trans->name, mComponentLogLevel, withResistiveLosses);
558 transformer->setParameters(voltageNode1, voltageNode2, ratedPower,
559 ratioAbs, ratioPhase, resistance_3ph,
563 SPDLOG_LOGGER_INFO(mSLog,
" Transformer for EMT not implemented yet");
566 }
else if (mDomain == Domain::SP) {
567 auto transformer = std::make_shared<SP::Ph1::Transformer>(
568 trans->mRID, trans->name, mComponentLogLevel);
569 transformer->setParameters(voltageNode1, voltageNode2, ratedPower, ratioAbs,
570 ratioPhase, resistance, inductance);
571 Real baseVolt = voltageNode1 >= voltageNode2 ? voltageNode1 : voltageNode2;
572 transformer->setBaseVoltage(baseVolt);
575 Bool withResistiveLosses = resistance > 0;
576 auto transformer = std::make_shared<DP::Ph1::Transformer>(
577 trans->mRID, trans->name, mComponentLogLevel, withResistiveLosses);
578 transformer->setParameters(voltageNode1, voltageNode2, ratedPower, ratioAbs,
579 ratioPhase, resistance, inductance);
584 TopologicalPowerComp::Ptr
585 Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) {
586 SPDLOG_LOGGER_INFO(mSLog,
" Found Synchronous machine {}", machine->name);
588 if (mDomain == Domain::DP) {
589 SPDLOG_LOGGER_INFO(mSLog,
" Create generator in DP domain.");
590 if (mGeneratorType == GeneratorType::TransientStability ||
591 mGeneratorType == GeneratorType::SG6aOrderVBR ||
592 mGeneratorType == GeneratorType::SG6bOrderVBR ||
593 mGeneratorType == GeneratorType::SG4OrderVBR ||
594 mGeneratorType == GeneratorType::SG3OrderVBR ||
595 mGeneratorType == GeneratorType::SG4OrderPCM ||
596 mGeneratorType == GeneratorType::SG4OrderTPM ||
597 mGeneratorType == GeneratorType::SG6OrderPCM) {
599 Real ratedPower = unitValue(machine->ratedS.value, UnitMultiplier::M);
600 Real ratedVoltage = unitValue(machine->ratedU.value, UnitMultiplier::k);
602 for (
auto obj : mModel->Objects) {
604 if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn =
605 dynamic_cast<CIMPP::SynchronousMachineTimeConstantReactance *
>(
607 if (genDyn->SynchronousMachine->mRID == machine->mRID) {
609 Real Rs = genDyn->statorResistance.value;
610 Real Ll = genDyn->statorLeakageReactance.value;
613 Real Ld = genDyn->xDirectSync.value;
614 Real Lq = genDyn->xQuadSync.value;
615 Real Ld_t = genDyn->xDirectTrans.value;
616 Real Lq_t = genDyn->xQuadTrans.value;
617 Real Ld_s = genDyn->xDirectSubtrans.value;
618 Real Lq_s = genDyn->xQuadSubtrans.value;
621 Real Td0_t = genDyn->tpdo.value;
622 Real Tq0_t = genDyn->tpqo.value;
623 Real Td0_s = genDyn->tppdo.value;
624 Real Tq0_s = genDyn->tppqo.value;
627 Real H = genDyn->inertia.value;
631 Real nomFieldCurr = 0;
633 if (mGeneratorType == GeneratorType::TransientStability) {
634 SPDLOG_LOGGER_DEBUG(mSLog,
635 " GeneratorType is TransientStability.");
636 auto gen = DP::Ph1::SynchronGeneratorTrStab::make(
637 machine->mRID, machine->name, mComponentLogLevel);
638 gen->setStandardParametersPU(ratedPower, ratedVoltage, mFrequency,
641 }
else if (mGeneratorType == GeneratorType::SG6aOrderVBR) {
643 mSLog,
" GeneratorType is SynchronGenerator6aOrderVBR.");
644 auto gen = std::make_shared<DP::Ph1::SynchronGenerator6aOrderVBR>(
645 machine->mRID, machine->name, mComponentLogLevel);
646 gen->setOperationalParametersPerUnit(
647 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
648 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
650 }
else if (mGeneratorType == GeneratorType::SG6bOrderVBR) {
652 mSLog,
" GeneratorType is SynchronGenerator6bOrderVBR.");
653 auto gen = std::make_shared<DP::Ph1::SynchronGenerator6bOrderVBR>(
654 machine->mRID, machine->name, mComponentLogLevel);
655 gen->setOperationalParametersPerUnit(
656 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
657 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
659 }
else if (mGeneratorType == GeneratorType::SG5OrderVBR) {
661 mSLog,
" GeneratorType is SynchronGenerator5OrderVBR.");
662 auto gen = std::make_shared<DP::Ph1::SynchronGenerator5OrderVBR>(
663 machine->mRID, machine->name, mComponentLogLevel);
664 gen->setOperationalParametersPerUnit(
665 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
666 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0);
668 }
else if (mGeneratorType == GeneratorType::SG4OrderVBR) {
670 mSLog,
" GeneratorType is SynchronGenerator4OrderVBR.");
671 auto gen = std::make_shared<DP::Ph1::SynchronGenerator4OrderVBR>(
672 machine->mRID, machine->name, mComponentLogLevel);
673 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
674 mFrequency, H, Ld, Lq, Ll,
675 Ld_t, Lq_t, Td0_t, Tq0_t);
677 }
else if (mGeneratorType == GeneratorType::SG3OrderVBR) {
679 mSLog,
" GeneratorType is SynchronGenerator3OrderVBR.");
680 auto gen = std::make_shared<DP::Ph1::SynchronGenerator3OrderVBR>(
681 machine->mRID, machine->name, mComponentLogLevel);
682 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
683 mFrequency, H, Ld, Lq, Ll,
686 }
else if (mGeneratorType == GeneratorType::SG4OrderPCM) {
688 mSLog,
" GeneratorType is SynchronGenerator4OrderPCM.");
689 auto gen = std::make_shared<DP::Ph1::SynchronGenerator4OrderPCM>(
690 machine->mRID, machine->name, mComponentLogLevel);
691 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
692 mFrequency, H, Ld, Lq, Ll,
693 Ld_t, Lq_t, Td0_t, Tq0_t);
695 }
else if (mGeneratorType == GeneratorType::SG4OrderTPM) {
697 mSLog,
" GeneratorType is SynchronGenerator4OrderTPM.");
698 auto gen = std::make_shared<DP::Ph1::SynchronGenerator4OrderTPM>(
699 machine->mRID, machine->name, mComponentLogLevel);
700 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
701 mFrequency, H, Ld, Lq, Ll,
702 Ld_t, Lq_t, Td0_t, Tq0_t);
704 }
else if (mGeneratorType == GeneratorType::SG6OrderPCM) {
706 mSLog,
" GeneratorType is SynchronGenerator6OrderPCM.");
707 auto gen = std::make_shared<DP::Ph1::SynchronGenerator6OrderPCM>(
708 machine->mRID, machine->name, mComponentLogLevel);
709 gen->setOperationalParametersPerUnit(
710 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
711 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
717 }
else if (mGeneratorType == GeneratorType::IdealVoltageSource) {
718 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is IdealVoltageSource.");
719 return std::make_shared<DP::Ph1::SynchronGeneratorIdeal>(
720 machine->mRID, machine->name, mComponentLogLevel);
721 }
else if (mGeneratorType == GeneratorType::None) {
722 throw SystemError(
"GeneratorType is None. Specify!");
724 throw SystemError(
"GeneratorType setting unfeasible.");
726 }
else if (mDomain == Domain::SP) {
727 SPDLOG_LOGGER_INFO(mSLog,
" Create generator in SP domain.");
728 if (mGeneratorType == GeneratorType::TransientStability ||
729 mGeneratorType == GeneratorType::SG6aOrderVBR ||
730 mGeneratorType == GeneratorType::SG6bOrderVBR ||
731 mGeneratorType == GeneratorType::SG5OrderVBR ||
732 mGeneratorType == GeneratorType::SG4OrderVBR ||
733 mGeneratorType == GeneratorType::SG3OrderVBR) {
735 Real ratedPower = unitValue(machine->ratedS.value, UnitMultiplier::M);
736 Real ratedVoltage = unitValue(machine->ratedU.value, UnitMultiplier::k);
738 for (
auto obj : mModel->Objects) {
740 if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn =
741 dynamic_cast<CIMPP::SynchronousMachineTimeConstantReactance *
>(
743 if (genDyn->SynchronousMachine->mRID == machine->mRID) {
745 Real Rs = genDyn->statorResistance.value;
746 Real Ll = genDyn->statorLeakageReactance.value;
749 Real Ld = genDyn->xDirectSync.value;
750 Real Lq = genDyn->xQuadSync.value;
751 Real Ld_t = genDyn->xDirectTrans.value;
752 Real Lq_t = genDyn->xQuadTrans.value;
753 Real Ld_s = genDyn->xDirectSubtrans.value;
754 Real Lq_s = genDyn->xQuadSubtrans.value;
757 Real Td0_t = genDyn->tpdo.value;
758 Real Tq0_t = genDyn->tpqo.value;
759 Real Td0_s = genDyn->tppdo.value;
760 Real Tq0_s = genDyn->tppqo.value;
763 Real H = genDyn->inertia.value;
767 Real nomFieldCurr = 0;
769 if (mGeneratorType == GeneratorType::TransientStability) {
770 SPDLOG_LOGGER_DEBUG(mSLog,
771 " GeneratorType is TransientStability.");
772 auto gen = SP::Ph1::SynchronGeneratorTrStab::make(
773 machine->mRID, machine->name, mComponentLogLevel);
774 gen->setStandardParametersPU(ratedPower, ratedVoltage, mFrequency,
777 }
else if (mGeneratorType == GeneratorType::SG6aOrderVBR) {
779 mSLog,
" GeneratorType is SynchronGenerator6aOrderVBR.");
780 auto gen = std::make_shared<SP::Ph1::SynchronGenerator6aOrderVBR>(
781 machine->mRID, machine->name, mComponentLogLevel);
782 gen->setOperationalParametersPerUnit(
783 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
784 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
786 }
else if (mGeneratorType == GeneratorType::SG6bOrderVBR) {
788 mSLog,
" GeneratorType is SynchronGenerator6bOrderVBR.");
789 auto gen = std::make_shared<SP::Ph1::SynchronGenerator6bOrderVBR>(
790 machine->mRID, machine->name, mComponentLogLevel);
791 gen->setOperationalParametersPerUnit(
792 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
793 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
795 }
else if (mGeneratorType == GeneratorType::SG5OrderVBR) {
797 mSLog,
" GeneratorType is SynchronGenerator5OrderVBR.");
798 auto gen = std::make_shared<SP::Ph1::SynchronGenerator5OrderVBR>(
799 machine->mRID, machine->name, mComponentLogLevel);
800 gen->setOperationalParametersPerUnit(
801 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
802 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0);
804 }
else if (mGeneratorType == GeneratorType::SG4OrderVBR) {
806 mSLog,
" GeneratorType is SynchronGenerator4OrderVBR.");
807 auto gen = std::make_shared<SP::Ph1::SynchronGenerator4OrderVBR>(
808 machine->mRID, machine->name, mComponentLogLevel);
809 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
810 mFrequency, H, Ld, Lq, Ll,
811 Ld_t, Lq_t, Td0_t, Tq0_t);
813 }
else if (mGeneratorType == GeneratorType::SG3OrderVBR) {
815 mSLog,
" GeneratorType is SynchronGenerator3OrderVBR.");
816 auto gen = std::make_shared<SP::Ph1::SynchronGenerator3OrderVBR>(
817 machine->mRID, machine->name, mComponentLogLevel);
818 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
819 mFrequency, H, Ld, Lq, Ll,
826 }
else if (mGeneratorType == GeneratorType::PVNode) {
827 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is PVNode.");
828 for (
auto obj : mModel->Objects) {
829 if (CIMPP::GeneratingUnit *genUnit =
830 dynamic_cast<CIMPP::GeneratingUnit *
>(obj)) {
831 for (
auto syncGen : genUnit->RotatingMachine) {
832 if (syncGen->mRID == machine->mRID) {
834 Real setPointActivePower = 0;
835 Real setPointVoltage = 0;
836 Real maximumReactivePower = 1e12;
838 setPointActivePower =
839 unitValue(genUnit->initialP.value, UnitMultiplier::M);
840 SPDLOG_LOGGER_INFO(mSLog,
" setPointActivePower={}",
841 setPointActivePower);
842 }
catch (ReadingUninitializedField *e) {
844 <<
"Uninitalized setPointActivePower for GeneratingUnit "
845 << machine->name <<
". Using default value of "
846 << setPointActivePower << std::endl;
848 if (machine->RegulatingControl) {
850 unitValue(machine->RegulatingControl->targetValue.value,
852 SPDLOG_LOGGER_INFO(mSLog,
" setPointVoltage={}",
855 std::cerr <<
"Uninitalized setPointVoltage for GeneratingUnit "
856 << machine->name <<
". Using default value of "
857 << setPointVoltage << std::endl;
860 maximumReactivePower =
861 unitValue(machine->maxQ.value, UnitMultiplier::M);
862 SPDLOG_LOGGER_INFO(mSLog,
" maximumReactivePower={}",
863 maximumReactivePower);
864 }
catch (ReadingUninitializedField *e) {
866 <<
"Uninitalized maximumReactivePower for GeneratingUnit "
867 << machine->name <<
". Using default value of "
868 << maximumReactivePower << std::endl;
871 auto gen = std::make_shared<SP::Ph1::SynchronGenerator>(
872 machine->mRID, machine->name, mComponentLogLevel);
874 unitValue(machine->ratedS.value, UnitMultiplier::M),
875 unitValue(machine->ratedU.value, UnitMultiplier::k),
876 setPointActivePower, setPointVoltage, PowerflowBusType::PV);
878 unitValue(machine->ratedU.value, UnitMultiplier::k));
884 SPDLOG_LOGGER_INFO(mSLog,
"no corresponding initial power for {}",
886 return std::make_shared<SP::Ph1::SynchronGenerator>(
887 machine->mRID, machine->name, mComponentLogLevel);
888 }
else if (mGeneratorType == GeneratorType::None) {
889 throw SystemError(
"GeneratorType is None. Specify!");
891 throw SystemError(
"GeneratorType setting unfeasible.");
894 SPDLOG_LOGGER_INFO(mSLog,
" Create generator in EMT domain.");
895 if (mGeneratorType == GeneratorType::FullOrder ||
896 mGeneratorType == GeneratorType::FullOrderVBR ||
897 mGeneratorType == GeneratorType::SG3OrderVBR ||
898 mGeneratorType == GeneratorType::SG4OrderVBR ||
899 mGeneratorType == GeneratorType::SG6aOrderVBR ||
900 mGeneratorType == GeneratorType::SG6bOrderVBR) {
902 Real ratedPower = unitValue(machine->ratedS.value, UnitMultiplier::M);
903 Real ratedVoltage = unitValue(machine->ratedU.value, UnitMultiplier::k);
905 for (
auto obj : mModel->Objects) {
907 if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn =
908 dynamic_cast<CIMPP::SynchronousMachineTimeConstantReactance *
>(
910 if (genDyn->SynchronousMachine->mRID == machine->mRID) {
913 Real Rs = genDyn->statorResistance.value;
914 Real Ll = genDyn->statorLeakageReactance.value;
917 Real Ld = genDyn->xDirectSync.value;
918 Real Lq = genDyn->xQuadSync.value;
919 Real Ld_t = genDyn->xDirectTrans.value;
920 Real Lq_t = genDyn->xQuadTrans.value;
921 Real Ld_s = genDyn->xDirectSubtrans.value;
922 Real Lq_s = genDyn->xQuadSubtrans.value;
925 Real Td0_t = genDyn->tpdo.value;
926 Real Tq0_t = genDyn->tpqo.value;
927 Real Td0_s = genDyn->tppdo.value;
928 Real Tq0_s = genDyn->tppqo.value;
931 Real H = genDyn->inertia.value;
935 Real nomFieldCurr = 0;
937 if (mGeneratorType == GeneratorType::FullOrder) {
938 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is FullOrder.");
939 auto gen = std::make_shared<EMT::Ph3::SynchronGeneratorDQTrapez>(
940 machine->mRID, machine->name, mComponentLogLevel);
941 gen->setParametersOperationalPerUnit(
942 ratedPower, ratedVoltage, mFrequency, poleNum, nomFieldCurr,
943 Rs, Ld, Lq, Ld_t, Lq_t, Ld_s, Lq_s, Ll, Td0_t, Tq0_t, Td0_s,
946 }
else if (mGeneratorType == GeneratorType::FullOrderVBR) {
947 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is FullOrderVBR.");
948 auto gen = std::make_shared<EMT::Ph3::SynchronGeneratorVBR>(
949 machine->mRID, machine->name, mComponentLogLevel);
950 gen->setBaseAndOperationalPerUnitParameters(
951 ratedPower, ratedVoltage, mFrequency, poleNum, nomFieldCurr,
952 Rs, Ld, Lq, Ld_t, Lq_t, Ld_s, Lq_s, Ll, Td0_t, Tq0_t, Td0_s,
955 }
else if (mGeneratorType == GeneratorType::SG6aOrderVBR) {
957 mSLog,
" GeneratorType is SynchronGenerator6aOrderVBR.");
959 std::make_shared<EMT::Ph3::SynchronGenerator6aOrderVBR>(
960 machine->mRID, machine->name, mComponentLogLevel);
961 gen->setOperationalParametersPerUnit(
962 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
963 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
965 }
else if (mGeneratorType == GeneratorType::SG6bOrderVBR) {
967 mSLog,
" GeneratorType is SynchronGenerator6bOrderVBR.");
969 std::make_shared<EMT::Ph3::SynchronGenerator6bOrderVBR>(
970 machine->mRID, machine->name, mComponentLogLevel);
971 gen->setOperationalParametersPerUnit(
972 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
973 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s);
975 }
else if (mGeneratorType == GeneratorType::SG5OrderVBR) {
977 mSLog,
" GeneratorType is SynchronGenerator5OrderVBR.");
978 auto gen = std::make_shared<EMT::Ph3::SynchronGenerator5OrderVBR>(
979 machine->mRID, machine->name, mComponentLogLevel);
980 gen->setOperationalParametersPerUnit(
981 ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t,
982 Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0);
984 }
else if (mGeneratorType == GeneratorType::SG4OrderVBR) {
986 mSLog,
" GeneratorType is SynchronGenerator4OrderVBR.");
987 auto gen = std::make_shared<EMT::Ph3::SynchronGenerator4OrderVBR>(
988 machine->mRID, machine->name, mComponentLogLevel);
989 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
990 mFrequency, H, Ld, Lq, Ll,
991 Ld_t, Lq_t, Td0_t, Tq0_t);
993 }
else if (mGeneratorType == GeneratorType::SG3OrderVBR) {
995 mSLog,
" GeneratorType is SynchronGenerator3OrderVBR.");
996 auto gen = std::make_shared<EMT::Ph3::SynchronGenerator3OrderVBR>(
997 machine->mRID, machine->name, mComponentLogLevel);
998 gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage,
999 mFrequency, H, Ld, Lq, Ll,
1006 }
else if (mGeneratorType == GeneratorType::IdealVoltageSource) {
1007 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is IdealVoltageSource.");
1008 return std::make_shared<EMT::Ph3::SynchronGeneratorIdeal>(
1009 machine->mRID, machine->name, mComponentLogLevel,
1010 GeneratorType::IdealVoltageSource);
1011 }
else if (mGeneratorType == GeneratorType::IdealCurrentSource) {
1012 SPDLOG_LOGGER_DEBUG(mSLog,
" GeneratorType is IdealCurrentSource.");
1013 return std::make_shared<EMT::Ph3::SynchronGeneratorIdeal>(
1014 machine->mRID, machine->name, mComponentLogLevel,
1015 GeneratorType::IdealCurrentSource);
1016 }
else if (mGeneratorType == GeneratorType::None) {
1017 throw SystemError(
"GeneratorType is None. Specify!");
1019 throw SystemError(
"GeneratorType setting unfeasible.");
1025 TopologicalPowerComp::Ptr
1026 Reader::mapExternalNetworkInjection(CIMPP::ExternalNetworkInjection *extnet) {
1027 SPDLOG_LOGGER_INFO(mSLog,
"Found External Network Injection {}",
1030 Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(extnet);
1032 if (mDomain == Domain::EMT) {
1033 if (mPhase == PhaseType::ABC) {
1034 return std::make_shared<EMT::Ph3::NetworkInjection>(
1035 extnet->mRID, extnet->name, mComponentLogLevel);
1038 "Mapping of ExternalNetworkInjection for EMT::Ph1 not existent!");
1041 }
else if (mDomain == Domain::SP) {
1042 if (mPhase == PhaseType::Single) {
1043 auto cpsextnet = std::make_shared<SP::Ph1::NetworkInjection>(
1044 extnet->mRID, extnet->name, mComponentLogLevel);
1045 cpsextnet->modifyPowerFlowBusType(
1048 cpsextnet->setBaseVoltage(baseVoltage);
1051 if (extnet->RegulatingControl) {
1052 SPDLOG_LOGGER_INFO(mSLog,
" Voltage set-point={}",
1053 (
float)extnet->RegulatingControl->targetValue);
1054 cpsextnet->setParameters(
1055 extnet->RegulatingControl->targetValue *
1059 mSLog,
" No voltage set-point defined. Using 1 per unit.");
1060 cpsextnet->setParameters(1. * baseVoltage);
1062 }
catch (ReadingUninitializedField *e) {
1063 std::cerr <<
"Ignore incomplete RegulatingControl" << std::endl;
1069 "Mapping of ExternalNetworkInjection for SP::Ph3 not existent!");
1073 if (mPhase == PhaseType::Single) {
1074 return std::make_shared<DP::Ph1::NetworkInjection>(
1075 extnet->mRID, extnet->name, mComponentLogLevel);
1078 "Mapping of ExternalNetworkInjection for DP::Ph3 not existent!");
1084 TopologicalPowerComp::Ptr
1085 Reader::mapEquivalentShunt(CIMPP::EquivalentShunt *shunt) {
1086 SPDLOG_LOGGER_INFO(mSLog,
"Found shunt {}", shunt->name);
1088 Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(shunt);
1090 auto cpsShunt = std::make_shared<SP::Ph1::Shunt>(shunt->mRID, shunt->name,
1091 mComponentLogLevel);
1092 cpsShunt->setParameters(shunt->g.value, shunt->b.value);
1093 cpsShunt->setBaseVoltage(baseVoltage);
1097 Real Reader::determineBaseVoltageAssociatedWithEquipment(
1098 CIMPP::ConductingEquipment *equipment) {
1099 Real baseVoltage = 0;
1102 for (
auto obj : mModel->Objects) {
1103 if (CIMPP::BaseVoltage *baseVolt =
1104 dynamic_cast<CIMPP::BaseVoltage *
>(obj)) {
1105 for (
auto comp : baseVolt->ConductingEquipment) {
1106 if (comp->name == equipment->name) {
1108 unitValue(baseVolt->nominalVoltage.value, UnitMultiplier::k);
1114 if (baseVoltage == 0) {
1115 for (
auto obj : mModel->Objects) {
1116 if (CIMPP::TopologicalNode *topNode =
1117 dynamic_cast<CIMPP::TopologicalNode *
>(obj)) {
1118 for (
auto term : topNode->Terminal) {
1119 if (term->ConductingEquipment->name == equipment->name) {
1120 baseVoltage = unitValue(topNode->BaseVoltage->nominalVoltage.value,
1131 template <
typename VarType>
1132 void Reader::processTopologicalNode(CIMPP::TopologicalNode *topNode) {
1134 int matrixNodeIndex = Int(mPowerflowNodes.size());
1136 topNode->mRID, topNode->name, matrixNodeIndex, mPhase);
1138 if (mPhase == PhaseType::ABC) {
1140 mSLog,
"TopologicalNode {} phase A as simulation node {} ",
1142 mPowerflowNodes[topNode->mRID]->matrixNodeIndex(PhaseType::A));
1144 mSLog,
"TopologicalNode {} phase B as simulation node {}",
1146 mPowerflowNodes[topNode->mRID]->matrixNodeIndex(PhaseType::B));
1148 mSLog,
"TopologicalNode {} phase C as simulation node {}",
1150 mPowerflowNodes[topNode->mRID]->matrixNodeIndex(PhaseType::C));
1152 SPDLOG_LOGGER_INFO(mSLog,
1153 "TopologicalNode id: {}, name: {} as simulation node {}",
1154 topNode->mRID, topNode->name,
1155 mPowerflowNodes[topNode->mRID]->matrixNodeIndex());
1157 for (
auto term : topNode->Terminal) {
1161 mPowerflowTerminals.insert(std::make_pair(term->mRID, cpsTerm));
1163 mPowerflowNodes[topNode->mRID]));
1165 if (!term->sequenceNumber.initialized)
1166 term->sequenceNumber = 1;
1168 SPDLOG_LOGGER_INFO(mSLog,
" Terminal {}, sequenceNumber {}", term->mRID,
1169 (
int)term->sequenceNumber);
1172 CIMPP::ConductingEquipment *equipment = term->ConductingEquipment;
1174 SPDLOG_LOGGER_WARN(mSLog,
"Terminal {} has no Equipment, ignoring!",
1179 if (mPowerflowEquipment.find(equipment->mRID) ==
1180 mPowerflowEquipment.end()) {
1181 TopologicalPowerComp::Ptr comp = mapComponent(equipment);
1183 mPowerflowEquipment.insert(std::make_pair(equipment->mRID, comp));
1185 SPDLOG_LOGGER_WARN(mSLog,
"Could not map equipment {}",
1191 auto pfEquipment = mPowerflowEquipment.at(equipment->mRID);
1192 std::dynamic_pointer_cast<SimPowerComp<VarType>>(pfEquipment)
1194 mPowerflowTerminals[term->mRID]),
1195 term->sequenceNumber - 1);
1197 SPDLOG_LOGGER_INFO(mSLog,
" Added Terminal {} to Equipment {}",
1198 term->mRID, equipment->mRID);
1204 Reader::processTopologicalNode<Real>(CIMPP::TopologicalNode *topNode);
1206 Reader::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.
Base class for all components that are transmitting power.