DPsim
Loading...
Searching...
No Matches
MNAStateSpaceExtractor.cpp
1// SPDX-FileCopyrightText: 2026 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University
2// SPDX-License-Identifier: MPL-2.0
3
4#include <dpsim/DirectLinearSolver.h>
5#include <dpsim/MNAStateSpaceExtractor.h>
6
7#include <stdexcept>
8
9namespace DPsim {
10
11void MNAStateSpaceExtractor::initialize(
12 const CPS::MNAInterface::List &components, UInt mnaVectorSize,
13 Real timeStep) {
14 reset();
15
16 if (timeStep <= 0.0)
17 throw std::invalid_argument(
18 "MNAStateSpaceExtractor requires a positive time step.");
19
20 mMnaVectorSize = mnaVectorSize;
21 mTimeStep = timeStep;
22
23 const auto contributors =
24 MNAStateSpaceContributorFactory::createList(components);
25
26 UInt nextStateOffset = 0;
27
28 for (const auto &contributor : contributors) {
29 const UInt localStateCount = contributor->getStateCount();
30
31 ContributorEntry entry;
32 entry.contributor = contributor;
33 entry.stateOffset = nextStateOffset;
34 mContributorEntries.push_back(entry);
35
36 nextStateOffset += localStateCount;
37
38 if (contributor->isVariable())
39 mHasVariableContributors = true;
40 }
41
42 mStateCount = nextStateOffset;
43
44 allocateMatrices();
45 collectMetadata();
46
47 stampStaticMatrices();
48 restampVariableMatrices();
49 rebuildCombinedMatrices();
50
51 mStateMatrixValid = false;
52 mInitialized = true;
53}
54
55void MNAStateSpaceExtractor::reset() {
56 mInitialized = false;
57
58 mMnaVectorSize = 0;
59 mStateCount = 0;
60 mTimeStep = 0.0;
61
62 mHasVariableContributors = false;
63 mStateMatrixValid = false;
64 mMetadata = StateSpaceMetadata{};
65 mLastExtractionTime = 0.0;
66 mHasExtractionTime = false;
67
68 mContributorEntries.clear();
69
70 mAdLocalStatic.resize(0, 0);
71 mBdMnaStatic.resize(0, 0);
72 mCdMnaStatic.resize(0, 0);
73
74 mAdLocalVariable.resize(0, 0);
75 mBdMnaVariable.resize(0, 0);
76 mCdMnaVariable.resize(0, 0);
77
78 mAdLocal.resize(0, 0);
79 mBdMna.resize(0, 0);
80 mCdMna.resize(0, 0);
81
82 mAd.resize(0, 0);
83}
84
85void MNAStateSpaceExtractor::extract(DirectLinearSolver &linearSolver,
86 Bool variableModelChanged,
87 Bool systemMatrixChanged, Real time) {
88 if (!mInitialized)
89 throw std::logic_error(
90 "MNAStateSpaceExtractor::extract() called before initialize().");
91
92 mLastExtractionTime = time;
93 mHasExtractionTime = true;
94
95 if (mStateCount == 0) {
96 mStateMatrixValid = true;
97 return;
98 }
99
100 if (variableModelChanged && mHasVariableContributors) {
101 restampVariableMatrices();
102 rebuildCombinedMatrices();
103 mStateMatrixValid = false;
104 }
105
106 if (systemMatrixChanged)
107 mStateMatrixValid = false;
108
109 if (!mStateMatrixValid)
110 computeStateMatrix(linearSolver);
111}
112
113void MNAStateSpaceExtractor::allocateMatrices() {
114 mAdLocalStatic = Matrix::Zero(mStateCount, mStateCount);
115 mBdMnaStatic = Matrix::Zero(mStateCount, mMnaVectorSize);
116 mCdMnaStatic = Matrix::Zero(mMnaVectorSize, mStateCount);
117
118 mAdLocalVariable = Matrix::Zero(mStateCount, mStateCount);
119 mBdMnaVariable = Matrix::Zero(mStateCount, mMnaVectorSize);
120 mCdMnaVariable = Matrix::Zero(mMnaVectorSize, mStateCount);
121
122 mAdLocal = Matrix::Zero(mStateCount, mStateCount);
123 mBdMna = Matrix::Zero(mStateCount, mMnaVectorSize);
124 mCdMna = Matrix::Zero(mMnaVectorSize, mStateCount);
125
126 mAd = Matrix::Zero(mStateCount, mStateCount);
127}
128
129void MNAStateSpaceExtractor::collectMetadata() {
130 mMetadata = StateSpaceMetadata{};
131
132 for (const auto &entry : mContributorEntries) {
133 entry.contributor->contributeMetadata(mMetadata, entry.stateOffset);
134 }
135
136 for (const auto &abcBlock : mMetadata.abcStateIndexTriples) {
137 for (const auto idx : abcBlock) {
138 if (idx >= mStateCount) {
139 throw std::runtime_error(
140 "MNAStateSpaceExtractor: abc metadata index is outside the "
141 "extracted state vector.");
142 }
143 }
144 }
145}
146
147void MNAStateSpaceExtractor::stampStaticMatrices() {
148 mAdLocalStatic.setZero();
149 mBdMnaStatic.setZero();
150 mCdMnaStatic.setZero();
151
152 for (const auto &entry : mContributorEntries) {
153 if (!entry.contributor->isVariable()) {
154 entry.contributor->stamp(mAdLocalStatic, mBdMnaStatic, mCdMnaStatic,
155 entry.stateOffset, mMnaVectorSize);
156 }
157 }
158}
159
160void MNAStateSpaceExtractor::restampVariableMatrices() {
161 mAdLocalVariable.setZero();
162 mBdMnaVariable.setZero();
163 mCdMnaVariable.setZero();
164
165 for (const auto &entry : mContributorEntries) {
166 if (entry.contributor->isVariable()) {
167 entry.contributor->stamp(mAdLocalVariable, mBdMnaVariable, mCdMnaVariable,
168 entry.stateOffset, mMnaVectorSize);
169 }
170 }
171}
172
173void MNAStateSpaceExtractor::rebuildCombinedMatrices() {
174 mAdLocal = mAdLocalStatic + mAdLocalVariable;
175 mBdMna = mBdMnaStatic + mBdMnaVariable;
176 mCdMna = mCdMnaStatic + mCdMnaVariable;
177}
178
179void MNAStateSpaceExtractor::computeStateMatrix(
180 DirectLinearSolver &linearSolver) {
181 // DirectLinearSolver::solve takes a non-const Matrix&, so use a local copy.
182 Matrix rhs = mCdMna;
183 const Matrix mnaToStateSolution = linearSolver.solve(rhs);
184
185 if (mnaToStateSolution.rows() != mMnaVectorSize ||
186 mnaToStateSolution.cols() != mStateCount) {
187 throw std::runtime_error(
188 "MNAStateSpaceExtractor: linear solver returned unexpected "
189 "dimensions.");
190 }
191
192 mAd = mAdLocal + mBdMna * mnaToStateSolution;
193
194 mStateMatrixValid = true;
195}
196
197} // namespace DPsim