DPsim
Loading...
Searching...
No Matches
MNAStateSpaceContributor.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University
2// SPDX-License-Identifier: MPL-2.0
5
36#include <stdexcept>
37#include <string>
38#include <utility>
39
40using namespace CPS;
41
42namespace DPsim {
43namespace {
44
45using SimPowerCompReal = CPS::SimPowerComp<CPS::Real>;
46using SimPowerCompComplex = CPS::SimPowerComp<CPS::Complex>;
47
48std::shared_ptr<CompositePowerComp<Real>>
49getSupportedRealComposite(const MNAInterface::Ptr &component) {
50 if (const auto composite =
51 std::dynamic_pointer_cast<EMT::Ph3::NetworkInjection>(component))
52 return composite;
53
54 if (const auto composite =
55 std::dynamic_pointer_cast<EMT::Ph3::PiLine>(component))
56 return composite;
57
58 if (const auto composite =
59 std::dynamic_pointer_cast<EMT::Ph3::RXLoad>(component))
60 return composite;
61
62 if (const auto composite =
63 std::dynamic_pointer_cast<EMT::Ph3::RxLine>(component))
64 return composite;
65
66 if (const auto composite =
67 std::dynamic_pointer_cast<EMT::Ph3::Shunt>(component))
68 return composite;
69
70 if (const auto composite =
71 std::dynamic_pointer_cast<EMT::Ph3::Transformer>(component))
72 return composite;
73
74 return nullptr;
75}
76
77std::shared_ptr<CompositePowerComp<Complex>>
78getSupportedComplexComposite(const MNAInterface::Ptr &component) {
79 if (const auto composite =
80 std::dynamic_pointer_cast<DP::Ph1::NetworkInjection>(component))
81 return composite;
82
83 if (const auto composite =
84 std::dynamic_pointer_cast<DP::Ph1::PiLine>(component))
85 return composite;
86
87 if (const auto composite =
88 std::dynamic_pointer_cast<DP::Ph1::RXLoad>(component))
89 return composite;
90
91 if (const auto composite =
92 std::dynamic_pointer_cast<DP::Ph1::RxLine>(component))
93 return composite;
94
95 if (const auto composite =
96 std::dynamic_pointer_cast<DP::Ph1::Shunt>(component))
97 return composite;
98
99 if (const auto composite =
100 std::dynamic_pointer_cast<DP::Ph1::Transformer>(component))
101 return composite;
102
103 return nullptr;
104}
105
108Matrix buildTwoTerminalInterfaceVoltageMapping(SimPowerCompReal &component,
109 UInt mnaVectorSize) {
110 Matrix K = Matrix::Zero(3, mnaVectorSize);
111
112 if (component.terminalNotGrounded(1)) {
113 for (UInt phase = 0; phase < 3; ++phase)
114 K(phase, component.matrixNodeIndex(1, phase)) = 1.0;
115 }
116
117 if (component.terminalNotGrounded(0)) {
118 for (UInt phase = 0; phase < 3; ++phase)
119 K(phase, component.matrixNodeIndex(0, phase)) = -1.0;
120 }
121
122 return K;
123}
124
127Matrix
128buildSinglePhaseComplexInterfaceVoltageMapping(SimPowerCompComplex &component,
129 UInt mnaVectorSize) {
130 if (mnaVectorSize % 2 != 0) {
131 throw std::logic_error(
132 "DP MNA state-space extraction requires a real-imaginary stacked "
133 "MNA vector with even size.");
134 }
135
136 const UInt complexOffset = mnaVectorSize / 2;
137 Matrix K = Matrix::Zero(2, mnaVectorSize);
138
139 if (component.terminalNotGrounded(1)) {
140 const UInt nodeIdx = component.matrixNodeIndex(1);
141 K(0, nodeIdx) = 1.0;
142 K(1, nodeIdx + complexOffset) = 1.0;
143 }
144
145 if (component.terminalNotGrounded(0)) {
146 const UInt nodeIdx = component.matrixNodeIndex(0);
147 K(0, nodeIdx) = -1.0;
148 K(1, nodeIdx + complexOffset) = -1.0;
149 }
150
151 return K;
152}
153
158void stampTwoTerminalCurrentInjectionMapping(const Matrix &K, Matrix &CdMna,
159 UInt stateOffset,
160 const Matrix &outputMatrix) {
161 CdMna.block(0, stateOffset, CdMna.rows(), outputMatrix.cols()) +=
162 -K.transpose() * outputMatrix;
163}
164
165Matrix realAugment(const MatrixComp &matrix) {
166 const Matrix::Index rows = matrix.rows();
167 const Matrix::Index cols = matrix.cols();
168
169 Matrix result = Matrix::Zero(2 * rows, 2 * cols);
170 result.topLeftCorner(rows, cols) = matrix.real();
171 result.topRightCorner(rows, cols) = -matrix.imag();
172 result.bottomLeftCorner(rows, cols) = matrix.imag();
173 result.bottomRightCorner(rows, cols) = matrix.real();
174
175 return result;
176}
177
178Matrix realAugment(const Complex &value) {
179 Matrix result = Matrix::Zero(2, 2);
180 result << value.real(), -value.imag(), value.imag(), value.real();
181 return result;
182}
183
184Complex calculateDPInductorPreviousCurrentFactor(const Complex &conductance) {
185 const Real omegaDtHalf = -conductance.imag() / conductance.real();
186 return Complex(1.0, -omegaDtHalf) / Complex(1.0, omegaDtHalf);
187}
188
189void setStateName(StateSpaceMetadata &metadata, UInt stateIndex,
190 const String &name) {
191 if (stateIndex >= metadata.stateNames.size())
192 throw std::runtime_error(
193 "MNA state-space contributor tried to set a state name outside the "
194 "extracted state vector.");
195
196 metadata.stateNames[stateIndex] = name;
197}
198
199void addThreePhaseAbcStateMetadata(StateSpaceMetadata &metadata,
200 UInt stateOffset, const String &baseName) {
201 setStateName(metadata, stateOffset + 0, baseName + "_a");
202 setStateName(metadata, stateOffset + 1, baseName + "_b");
203 setStateName(metadata, stateOffset + 2, baseName + "_c");
204
205 metadata.abcStateBlocks.push_back(
206 {{stateOffset + 0, stateOffset + 1, stateOffset + 2}, baseName});
207}
208
209void addSinglePhaseComplexStateMetadata(StateSpaceMetadata &metadata,
210 UInt stateOffset,
211 const String &baseName) {
212 setStateName(metadata, stateOffset + 0, baseName + "_re");
213 setStateName(metadata, stateOffset + 1, baseName + "_im");
214}
215
216void addComplexStateMetadata(StateSpaceMetadata &metadata, UInt stateOffset,
217 UInt complexStateCount,
218 const String &componentName) {
219 for (UInt idx = 0; idx < complexStateCount; ++idx) {
220 const String stateName = componentName + ".x" + std::to_string(idx);
221 setStateName(metadata, stateOffset + idx, stateName + "_re");
222 setStateName(metadata, stateOffset + complexStateCount + idx,
223 stateName + "_im");
224 }
225}
226
227void addRealStateMetadata(StateSpaceMetadata &metadata, UInt stateOffset,
228 UInt stateCount, const String &componentName) {
229 for (UInt idx = 0; idx < stateCount; ++idx)
230 setStateName(metadata, stateOffset + idx,
231 componentName + ".x" + std::to_string(idx));
232}
233
234class EMTPh3InductorStateSpaceContributor final
235 : public MNAStateSpaceContributor {
236public:
237 explicit EMTPh3InductorStateSpaceContributor(
238 std::shared_ptr<EMT::Ph3::Inductor> component)
239 : mComponent(std::move(component)) {}
240
241 UInt getStateCount() const override { return 3; }
242
243 void stamp(Matrix &AdLocal, Matrix &BdMna, Matrix &CdMna, UInt stateOffset,
244 UInt mnaVectorSize) const override {
245 const Matrix &conductance = mComponent->getMNAConductance();
246
247 const Matrix K =
248 buildTwoTerminalInterfaceVoltageMapping(*mComponent, mnaVectorSize);
249
250 // History state h:
251 // i[k+1] = G vIntf[k+1] + h[k]
252 // h[k+1] = h[k] + 2 G vIntf[k+1]
253 // Therefore: AdLocal = I, BdMna = 2 G K, CdMna = -K^T.
254 AdLocal.block(stateOffset, stateOffset, 3, 3) += Matrix::Identity(3, 3);
255
256 BdMna.block(stateOffset, 0, 3, mnaVectorSize) += 2.0 * conductance * K;
257
258 stampTwoTerminalCurrentInjectionMapping(K, CdMna, stateOffset,
259 Matrix::Identity(3, 3));
260 }
261
262 void contributeMetadata(StateSpaceMetadata &metadata,
263 UInt stateOffset) const override {
264 addThreePhaseAbcStateMetadata(metadata, stateOffset, mComponent->name());
265 }
266
267private:
268 std::shared_ptr<EMT::Ph3::Inductor> mComponent;
269};
270
271class EMTPh3CapacitorStateSpaceContributor final
272 : public MNAStateSpaceContributor {
273public:
274 explicit EMTPh3CapacitorStateSpaceContributor(
275 std::shared_ptr<EMT::Ph3::Capacitor> component)
276 : mComponent(std::move(component)) {}
277
278 UInt getStateCount() const override { return 3; }
279
280 void stamp(Matrix &AdLocal, Matrix &BdMna, Matrix &CdMna, UInt stateOffset,
281 UInt mnaVectorSize) const override {
282 const Matrix &conductance = mComponent->getMNAConductance();
283
284 const Matrix K =
285 buildTwoTerminalInterfaceVoltageMapping(*mComponent, mnaVectorSize);
286
287 // History state h:
288 // i[k+1] = G vIntf[k+1] + h[k]
289 // h[k+1] = -h[k] - 2 G vIntf[k+1]
290 // Therefore: AdLocal = -I, BdMna = -2 G K, CdMna = -K^T.
291 AdLocal.block(stateOffset, stateOffset, 3, 3) -= Matrix::Identity(3, 3);
292
293 BdMna.block(stateOffset, 0, 3, mnaVectorSize) -= 2.0 * conductance * K;
294
295 stampTwoTerminalCurrentInjectionMapping(K, CdMna, stateOffset,
296 Matrix::Identity(3, 3));
297 }
298
299 void contributeMetadata(StateSpaceMetadata &metadata,
300 UInt stateOffset) const override {
301 addThreePhaseAbcStateMetadata(metadata, stateOffset, mComponent->name());
302 }
303
304private:
305 std::shared_ptr<EMT::Ph3::Capacitor> mComponent;
306};
307
308class EMTPh3TwoTerminalVTypeSSNStateSpaceContributor final
309 : public MNAStateSpaceContributor {
310public:
311 EMTPh3TwoTerminalVTypeSSNStateSpaceContributor(
312 std::shared_ptr<EMT::VTypeSSNComp> component, Bool isVariable)
313 : mComponent(std::move(component)), mIsVariable(isVariable) {}
314
315 UInt getStateCount() const override { return mComponent->getStateCount(); }
316
317 Bool contributesToUpdatedMatrices() const override { return mIsVariable; }
318
319 void stamp(Matrix &AdLocal, Matrix &BdMna, Matrix &CdMna, UInt stateOffset,
320 UInt mnaVectorSize) const override {
321 const UInt localStateCount = getStateCount();
322
323 const Matrix &discreteA = mComponent->getDiscreteA();
324 const Matrix &discreteB = mComponent->getDiscreteB();
325 const Matrix &outputC = mComponent->getC();
326
327 const Matrix K =
328 buildTwoTerminalInterfaceVoltageMapping(*mComponent, mnaVectorSize);
329
330 // History-coordinate state s = discreteA x + discreteB vIntf:
331 // s[k+1] = discreteA s[k] + (discreteA + I) discreteB vIntf[k+1]
332 // yHist[k] = C s[k]
333 // Therefore: AdLocal = discreteA, BdMna = (discreteA + I) discreteB K,
334 // CdMna = -K^T C.
335 AdLocal.block(stateOffset, stateOffset, localStateCount, localStateCount) +=
336 discreteA;
337
338 const Matrix inputUpdate =
339 (discreteA + Matrix::Identity(localStateCount, localStateCount)) *
340 discreteB;
341
342 BdMna.block(stateOffset, 0, localStateCount, mnaVectorSize) +=
343 inputUpdate * K;
344
345 stampTwoTerminalCurrentInjectionMapping(K, CdMna, stateOffset, outputC);
346 }
347
348 void contributeMetadata(StateSpaceMetadata &metadata,
349 UInt stateOffset) const override {
350 const UInt localStateCount = getStateCount();
351 const String componentName = mComponent->name();
352
353 const auto localStateNames = mComponent->getLocalStateNames();
354
355 if (!localStateNames.empty() && localStateNames.size() != localStateCount) {
356 throw std::runtime_error(
357 "SSN component returned an invalid number of local state names.");
358 }
359
360 for (UInt idx = 0; idx < localStateCount; ++idx) {
361 if (!localStateNames.empty()) {
362 setStateName(metadata, stateOffset + idx,
363 componentName + "." + localStateNames[idx]);
364 }
365 }
366
367 for (auto abcBlock : mComponent->getLocalAbcStateBlocks()) {
368 if (abcBlock.name.empty()) {
369 throw std::runtime_error(
370 "SSN component returned an abc state block with an empty name.");
371 }
372
373 for (auto &idx : abcBlock.indices) {
374 if (idx >= localStateCount) {
375 throw std::runtime_error(
376 "SSN component returned an invalid abc state index.");
377 }
378
379 idx += stateOffset;
380 }
381
382 metadata.abcStateBlocks.push_back(
383 {abcBlock.indices, componentName + "." + abcBlock.name});
384 }
385 }
386
387private:
388 std::shared_ptr<EMT::VTypeSSNComp> mComponent;
389 Bool mIsVariable = false;
390};
391
392class EMTPh3TwoTerminalVTypeSplitSSNStateSpaceContributor final
393 : public MNAStateSpaceContributor {
394public:
395 explicit EMTPh3TwoTerminalVTypeSplitSSNStateSpaceContributor(
396 std::shared_ptr<EMT::Ph3::TwoTerminalVTypeSplitSSNComp> component)
397 : mComponent(std::move(component)) {}
398
399 UInt getStateCount() const override {
400 return mComponent->getSplitStateCount();
401 }
402
403 Bool contributesToUpdatedMatrices() const override {
404 return mComponent->requiresStateSpaceMatrixUpdate();
405 }
406
407 Bool requiresUpdate() const override {
408 return mComponent->requiresStateSpaceMatrixUpdate();
409 }
410
411 CPS::AttributeBase::List getAttributeDependencies() const override {
412 if (requiresUpdate())
413 return {mComponent->getSplitStateAttribute()};
414
415 return {};
416 }
417
418 void stamp(Matrix &AdLocal, Matrix &BdMna, Matrix &CdMna, UInt stateOffset,
419 UInt mnaVectorSize) const override {
420 const UInt localStateCount = getStateCount();
421 const Matrix &discreteA = mComponent->getSplitDiscreteA();
422 const Matrix &discreteB = mComponent->getSplitDiscreteB();
423 const Matrix &historyC = mComponent->getSplitHistoryC();
424 const Matrix K =
425 buildTwoTerminalInterfaceVoltageMapping(*mComponent, mnaVectorSize);
426
427 AdLocal.block(stateOffset, stateOffset, localStateCount, localStateCount) +=
428 discreteA;
429 BdMna.block(stateOffset, 0, localStateCount, mnaVectorSize) +=
430 discreteB * K;
431 stampTwoTerminalCurrentInjectionMapping(K, CdMna, stateOffset, historyC);
432 }
433
434 void contributeMetadata(StateSpaceMetadata &metadata,
435 UInt stateOffset) const override {
436 const UInt localStateCount = getStateCount();
437 const String componentName = mComponent->name();
438 const auto localStateNames = mComponent->getSplitLocalStateNames();
439
440 if (!localStateNames.empty() && localStateNames.size() != localStateCount) {
441 throw std::runtime_error(
442 "Split SSN component returned an invalid number of local state "
443 "names.");
444 }
445
446 for (UInt idx = 0; idx < localStateCount; ++idx) {
447 if (!localStateNames.empty())
448 setStateName(metadata, stateOffset + idx,
449 componentName + "." + localStateNames[idx]);
450 }
451
452 for (auto abcBlock : mComponent->getSplitLocalAbcStateBlocks()) {
453 if (abcBlock.name.empty()) {
454 throw std::runtime_error(
455 "Split SSN component returned an abc state block with an empty "
456 "name.");
457 }
458
459 for (auto &idx : abcBlock.indices) {
460 if (idx >= localStateCount) {
461 throw std::runtime_error(
462 "Split SSN component returned an invalid abc state index.");
463 }
464 idx += stateOffset;
465 }
466
467 metadata.abcStateBlocks.push_back(
468 {abcBlock.indices, componentName + "." + abcBlock.name});
469 }
470 }
471
472private:
473 std::shared_ptr<EMT::Ph3::TwoTerminalVTypeSplitSSNComp> mComponent;
474};
475
476class DPPh1InductorStateSpaceContributor final
477 : public MNAStateSpaceContributor {
478public:
479 explicit DPPh1InductorStateSpaceContributor(
480 std::shared_ptr<DP::Ph1::Inductor> component)
481 : mComponent(std::move(component)) {}
482
483 UInt getStateCount() const override { return 2; }
484
485 void stamp(Matrix &AdLocal, Matrix &BdMna, Matrix &CdMna, UInt stateOffset,
486 UInt mnaVectorSize) const override {
487 const Complex conductance = mComponent->getMNAConductance();
488 const Complex prevCurrentFactor =
489 calculateDPInductorPreviousCurrentFactor(conductance);
490
491 const Matrix K = buildSinglePhaseComplexInterfaceVoltageMapping(
492 *mComponent, mnaVectorSize);
493
494 // Complex history state h:
495 // i[k+1] = Y_L vIntf[k+1] + h[k]
496 // h[k+1] = alpha h[k] + (1 + alpha) Y_L vIntf[k+1]
497 // Therefore: AdLocal = alpha, BdMna = (1 + alpha) Y_L K,
498 // CdMna = -K^T in real-imaginary augmented form.
499 AdLocal.block(stateOffset, stateOffset, 2, 2) +=
500 realAugment(prevCurrentFactor);
501
502 BdMna.block(stateOffset, 0, 2, mnaVectorSize) +=
503 realAugment((Complex(1.0, 0.0) + prevCurrentFactor) * conductance) * K;
504
505 stampTwoTerminalCurrentInjectionMapping(K, CdMna, stateOffset,
506 Matrix::Identity(2, 2));
507 }
508
509 void contributeMetadata(StateSpaceMetadata &metadata,
510 UInt stateOffset) const override {
511 addSinglePhaseComplexStateMetadata(metadata, stateOffset,
512 mComponent->name());
513 }
514
515private:
516 std::shared_ptr<DP::Ph1::Inductor> mComponent;
517};
518
519class DPPh1CapacitorStateSpaceContributor final
520 : public MNAStateSpaceContributor {
521public:
522 explicit DPPh1CapacitorStateSpaceContributor(
523 std::shared_ptr<DP::Ph1::Capacitor> component)
524 : mComponent(std::move(component)) {}
525
526 UInt getStateCount() const override { return 2; }
527
528 void stamp(Matrix &AdLocal, Matrix &BdMna, Matrix &CdMna, UInt stateOffset,
529 UInt mnaVectorSize) const override {
530 const Complex conductance = mComponent->getMNAConductance();
531
532 const Matrix K = buildSinglePhaseComplexInterfaceVoltageMapping(
533 *mComponent, mnaVectorSize);
534
535 // Complex history state h:
536 // i[k+1] = Y_C vIntf[k+1] + h[k]
537 // h[k+1] = -h[k] - (Y_C + conj(Y_C)) vIntf[k+1]
538 // Therefore: AdLocal = -1, BdMna = -2 Re(Y_C) K,
539 // CdMna = -K^T in real-imaginary augmented form.
540 AdLocal.block(stateOffset, stateOffset, 2, 2) -= Matrix::Identity(2, 2);
541
542 BdMna.block(stateOffset, 0, 2, mnaVectorSize) -=
543 2.0 * conductance.real() * K;
544
545 stampTwoTerminalCurrentInjectionMapping(K, CdMna, stateOffset,
546 Matrix::Identity(2, 2));
547 }
548
549 void contributeMetadata(StateSpaceMetadata &metadata,
550 UInt stateOffset) const override {
551 addSinglePhaseComplexStateMetadata(metadata, stateOffset,
552 mComponent->name());
553 }
554
555private:
556 std::shared_ptr<DP::Ph1::Capacitor> mComponent;
557};
558
559class DPPh1TwoTerminalVTypeSSNStateSpaceContributor final
560 : public MNAStateSpaceContributor {
561public:
562 explicit DPPh1TwoTerminalVTypeSSNStateSpaceContributor(
563 std::shared_ptr<DP::VTypeSSNComp> component)
564 : mComponent(std::move(component)) {}
565
566 UInt getStateCount() const override {
567 return 2 * mComponent->getStateCount();
568 }
569
570 void stamp(Matrix &AdLocal, Matrix &BdMna, Matrix &CdMna, UInt stateOffset,
571 UInt mnaVectorSize) const override {
572 const UInt complexStateCount = mComponent->getStateCount();
573 const UInt realStateCount = getStateCount();
574
575 const MatrixComp &discreteA = mComponent->getDiscreteA();
576 const MatrixComp &discreteB = mComponent->getDiscreteB();
577 const MatrixComp outputC = mComponent->getC().cast<Complex>();
578
579 const Matrix K = buildSinglePhaseComplexInterfaceVoltageMapping(
580 *mComponent, mnaVectorSize);
581
582 // Complex history-coordinate state s = discreteA x + discreteB vIntf:
583 // s[k+1] = discreteA s[k] + (discreteA + I) discreteB vIntf[k+1]
584 // yHist[k] = C s[k]
585 // Therefore: AdLocal = discreteA, BdMna = (discreteA + I) discreteB K,
586 // CdMna = -K^T C in real-imaginary augmented form.
587 AdLocal.block(stateOffset, stateOffset, realStateCount, realStateCount) +=
588 realAugment(discreteA);
589
590 const MatrixComp inputUpdate =
591 (discreteA +
592 MatrixComp::Identity(complexStateCount, complexStateCount)) *
593 discreteB;
594
595 BdMna.block(stateOffset, 0, realStateCount, mnaVectorSize) +=
596 realAugment(inputUpdate) * K;
597
598 stampTwoTerminalCurrentInjectionMapping(K, CdMna, stateOffset,
599 realAugment(outputC));
600 }
601
602 void contributeMetadata(StateSpaceMetadata &metadata,
603 UInt stateOffset) const override {
604 addComplexStateMetadata(metadata, stateOffset, mComponent->getStateCount(),
605 mComponent->name());
606 }
607
608private:
609 std::shared_ptr<DP::VTypeSSNComp> mComponent;
610};
611
612class DPPh1MixedVTypeVariableSSNStateSpaceContributor final
613 : public MNAStateSpaceContributor {
614public:
615 explicit DPPh1MixedVTypeVariableSSNStateSpaceContributor(
616 std::shared_ptr<DP::Ph1::MixedVTypeVariableSSNComp> component)
617 : mComponent(std::move(component)) {}
618
619 UInt getStateCount() const override { return mComponent->getStateCount(); }
620
621 Bool contributesToUpdatedMatrices() const override { return true; }
622
623 void stamp(Matrix &AdLocal, Matrix &BdMna, Matrix &CdMna, UInt stateOffset,
624 UInt mnaVectorSize) const override {
625 const UInt localStateCount = getStateCount();
626
627 const Matrix &discreteA = mComponent->getDiscreteA();
628 const Matrix &discreteB = mComponent->getDiscreteB();
629 const Matrix &outputC = mComponent->getC();
630
631 const Matrix K = buildSinglePhaseComplexInterfaceVoltageMapping(
632 *mComponent, mnaVectorSize);
633
634 // Real packed history-coordinate state s = discreteA x + discreteB vIntf:
635 // s[k+1] = discreteA s[k] + (discreteA + I) discreteB vIntf[k+1]
636 // yHist[k] = C s[k]
637 // Therefore: AdLocal = discreteA, BdMna = (discreteA + I) discreteB K,
638 // CdMna = -K^T C.
639 AdLocal.block(stateOffset, stateOffset, localStateCount, localStateCount) +=
640 discreteA;
641
642 const Matrix inputUpdate =
643 (discreteA + Matrix::Identity(localStateCount, localStateCount)) *
644 discreteB;
645
646 BdMna.block(stateOffset, 0, localStateCount, mnaVectorSize) +=
647 inputUpdate * K;
648
649 stampTwoTerminalCurrentInjectionMapping(K, CdMna, stateOffset, outputC);
650 }
651
652 void contributeMetadata(StateSpaceMetadata &metadata,
653 UInt stateOffset) const override {
654 addRealStateMetadata(metadata, stateOffset, getStateCount(),
655 mComponent->name());
656 }
657
658private:
659 std::shared_ptr<DP::Ph1::MixedVTypeVariableSSNComp> mComponent;
660};
661
662} // namespace
663
665MNAStateSpaceContributorFactory::create(const MNAInterface::Ptr &component) {
666 if (!component)
667 return nullptr;
668
669 if (auto inductor =
670 std::dynamic_pointer_cast<EMT::Ph3::Inductor>(component)) {
671 return std::make_shared<EMTPh3InductorStateSpaceContributor>(inductor);
672 }
673
674 if (auto capacitor =
675 std::dynamic_pointer_cast<EMT::Ph3::Capacitor>(component)) {
676 return std::make_shared<EMTPh3CapacitorStateSpaceContributor>(capacitor);
677 }
678
679 if (auto variableSsn =
680 std::dynamic_pointer_cast<EMT::Ph3::TwoTerminalVTypeVariableSSNComp>(
681 component)) {
682 return std::make_shared<EMTPh3TwoTerminalVTypeSSNStateSpaceContributor>(
683 variableSsn, true);
684 }
685
686 if (auto splitSsn =
687 std::dynamic_pointer_cast<EMT::Ph3::TwoTerminalVTypeSplitSSNComp>(
688 component)) {
689 return std::make_shared<
690 EMTPh3TwoTerminalVTypeSplitSSNStateSpaceContributor>(splitSsn);
691 }
692
693 if (auto ssn = std::dynamic_pointer_cast<EMT::Ph3::TwoTerminalVTypeSSNComp>(
694 component)) {
695 return std::make_shared<EMTPh3TwoTerminalVTypeSSNStateSpaceContributor>(
696 ssn, false);
697 }
698
699 if (std::dynamic_pointer_cast<EMT::Ph3::Resistor>(component))
700 return nullptr;
701
702 if (std::dynamic_pointer_cast<EMT::Ph3::Switch>(component))
703 return nullptr;
704
705 if (std::dynamic_pointer_cast<EMT::Ph3::VoltageSource>(component))
706 return nullptr;
707
708 if (auto inductor = std::dynamic_pointer_cast<DP::Ph1::Inductor>(component)) {
709 return std::make_shared<DPPh1InductorStateSpaceContributor>(inductor);
710 }
711
712 if (auto capacitor =
713 std::dynamic_pointer_cast<DP::Ph1::Capacitor>(component)) {
714 return std::make_shared<DPPh1CapacitorStateSpaceContributor>(capacitor);
715 }
716
717 if (auto mixedVariableSsn =
718 std::dynamic_pointer_cast<DP::Ph1::MixedVTypeVariableSSNComp>(
719 component)) {
720 return std::make_shared<DPPh1MixedVTypeVariableSSNStateSpaceContributor>(
721 mixedVariableSsn);
722 }
723
724 if (auto ssn = std::dynamic_pointer_cast<DP::Ph1::TwoTerminalVTypeSSNComp>(
725 component)) {
726 return std::make_shared<DPPh1TwoTerminalVTypeSSNStateSpaceContributor>(ssn);
727 }
728
729 if (std::dynamic_pointer_cast<DP::Ph1::Resistor>(component))
730 return nullptr;
731
732 if (std::dynamic_pointer_cast<DP::Ph1::Switch>(component))
733 return nullptr;
734
735 if (std::dynamic_pointer_cast<DP::Ph1::VoltageSource>(component))
736 return nullptr;
737
738 throw std::invalid_argument(
739 "Unsupported component in MNA state-space extraction.");
740}
741
743 const MNAInterface::List &components) {
745
746 const auto appendContributor =
747 [&contributors](const MNAInterface::Ptr &component) {
748 auto contributor = MNAStateSpaceContributorFactory::create(component);
749
750 if (contributor)
751 contributors.push_back(std::move(contributor));
752 };
753
754 const auto appendCompositeContributors =
755 [&appendContributor](const auto &composite) {
756 for (const auto &subcomponent : composite->mnaSubComponents())
757 appendContributor(subcomponent);
758 };
759
760 for (const auto &component : components) {
761 if (const auto composite = getSupportedRealComposite(component)) {
762 appendCompositeContributors(composite);
763 continue;
764 }
765
766 if (const auto composite = getSupportedComplexComposite(component)) {
767 appendCompositeContributors(composite);
768 continue;
769 }
770
771 appendContributor(component);
772 }
773
774 return contributors;
775}
776
777} // namespace DPsim
std::vector< Ptr > List
Definition Attribute.h:123
std::vector< Ptr > List
std::shared_ptr< MNAInterface > Ptr
static MNAStateSpaceContributor::List createList(const CPS::MNAInterface::List &components)
std::shared_ptr< MNAStateSpaceContributor > Ptr
CPS::Complex Complex
Definition Definitions.h:19
CPS::Real Real
Definition Definitions.h:18
CPS::String String
Definition Definitions.h:20
CPS::Matrix Matrix
Definition Definitions.h:24
CPS::Bool Bool
Definition Definitions.h:21
CPS::UInt UInt
Definition Definitions.h:23
CPS::MatrixComp MatrixComp
Definition Definitions.h:25