DPsim
Loading...
Searching...
No Matches
MNASolverDirect.cpp
1/* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
2 * EONERC, RWTH Aachen University
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7 *********************************************************************************/
8
9#include <dpsim/MNASolverDirect.h>
10#include <dpsim/SequentialScheduler.h>
11
12using namespace DPsim;
13using namespace CPS;
14
15namespace DPsim {
16
17template <typename VarType>
18MnaSolverDirect<VarType>::MnaSolverDirect(String name, CPS::Domain domain,
19 CPS::Logger::Level logLevel)
20 : MnaSolver<VarType>(name, domain, logLevel) {
21 mImplementationInUse = DirectLinearSolverImpl::KLU;
22}
23
24template <typename VarType>
26 mSwitchedMatrices[std::bitset<SWITCH_NUM>(index)][0].setZero();
27}
28
29template <typename VarType>
31 Int freqIdx) {
32 mSwitchedMatrices[std::bitset<SWITCH_NUM>(swIdx)][freqIdx].setZero();
33}
34
35template <typename VarType>
37 std::size_t index, std::vector<std::shared_ptr<CPS::MNAInterface>> &comp) {
38 auto bit = std::bitset<SWITCH_NUM>(index);
39 auto &sys = mSwitchedMatrices[bit][0];
40 for (auto component : comp) {
41 component->mnaApplySystemMatrixStamp(sys);
42 }
43 for (UInt i = 0; i < mSwitches.size(); ++i)
44 mSwitches[i]->mnaApplySwitchSystemMatrixStamp(bit[i], sys, 0);
45
46 // Compute LU-factorization for system matrix
47 mDirectLinearSolvers[bit][0]->preprocessing(sys,
49 auto start = std::chrono::steady_clock::now();
50 mDirectLinearSolvers[bit][0]->factorize(sys);
51 auto end = std::chrono::steady_clock::now();
52 std::chrono::duration<Real> diff = end - start;
53 mFactorizeTimes.push_back(diff.count());
54}
55
56template <typename VarType>
58
61 // TODO: a direct linear solver configuration is only applied if system matrix recomputation is used
62 this->mDirectLinearSolverVariableSystemMatrix->setConfiguration(
64
65 SPDLOG_LOGGER_INFO(mSLog,
66 "Number of variable Elements: {}"
67 "\nNumber of MNA components: {}",
68 mVariableComps.size(), mMNAComponents.size());
69
70 // Build base matrix with only static elements
71 mBaseSystemMatrix.setZero();
72 for (auto statElem : mMNAComponents)
73 statElem->mnaApplySystemMatrixStamp(mBaseSystemMatrix);
74 SPDLOG_LOGGER_INFO(mSLog, "Base matrix with only static elements: {}",
75 Logger::matrixToString(mBaseSystemMatrix));
76 mSLog->flush();
77
78 // Continue from base matrix
80
81 // Now stamp initial state of variable elements and switches into matrix
82 SPDLOG_LOGGER_INFO(mSLog, "Stamping variable elements");
83 for (auto varElem : mMNAIntfVariableComps)
84 varElem->mnaApplySystemMatrixStamp(mVariableSystemMatrix);
85
86 SPDLOG_LOGGER_INFO(mSLog, "Initial system matrix with variable elements {}",
87 Logger::matrixToString(mVariableSystemMatrix));
88 /* TODO: find replacement for flush() */
89 mSLog->flush();
90
91 // Calculate factorization of current matrix
94
95 auto start = std::chrono::steady_clock::now();
97 auto end = std::chrono::steady_clock::now();
98 std::chrono::duration<Real> diff = end - start;
99 mFactorizeTimes.push_back(diff.count());
100}
101
102template <typename VarType>
104 Real time, Int timeStepCount) {
105 // Reset source vector
106 mRightSideVector.setZero();
107
108 // Add together the right side vector (computed by the components'
109 // pre-step tasks)
110 for (auto stamp : mRightVectorStamps)
111 mRightSideVector += *stamp;
112
113 // Get switch and variable comp status and update system matrix and lu factorization accordingly
116
117 // Calculate new solution vector
118 auto start = std::chrono::steady_clock::now();
121 auto end = std::chrono::steady_clock::now();
122 std::chrono::duration<Real> diff = end - start;
123 mSolveTimes.push_back(diff.count());
124
125 // TODO split into separate task? (dependent on x, updating all v attributes)
126 for (UInt nodeIdx = 0; nodeIdx < mNumNetNodes; ++nodeIdx)
127 mNodes[nodeIdx]->mnaUpdateVoltage(**mLeftSideVector);
128
129 // Components' states will be updated by the post-step tasks
130}
131
132template <typename VarType>
134 // Start from base matrix
136
137 // Now stamp variable elements and switches into matrix
138 for (auto comp : mMNAIntfVariableComps)
139 comp->mnaApplySystemMatrixStamp(mVariableSystemMatrix);
140
141 // Refactorization of matrix assuming that structure remained
142 // constant by omitting analyzePattern
143 auto start = std::chrono::steady_clock::now();
144 mDirectLinearSolverVariableSystemMatrix->partialRefactorize(
146 auto end = std::chrono::steady_clock::now();
147 std::chrono::duration<Real> diff = end - start;
148 mRecomputationTimes.push_back(diff.count());
150}
151
153 if (mSwitches.size() > SWITCH_NUM)
154 throw SystemError("Too many Switches.");
155
161 } else {
162 for (std::size_t i = 0; i < (1ULL << mSwitches.size()); i++) {
163 auto bit = std::bitset<SWITCH_NUM>(i);
164 mSwitchedMatrices[bit].push_back(
166 mDirectLinearSolvers[bit].push_back(
168 }
169 }
170}
171
173 if (mSwitches.size() > SWITCH_NUM)
174 throw SystemError("Too many Switches.");
175
176 if (mFrequencyParallel) {
177 for (UInt i = 0; i < std::pow(2, mSwitches.size()); ++i) {
178 for (Int freq = 0; freq < mSystem.mFrequencies.size(); ++freq) {
179 auto bit = std::bitset<SWITCH_NUM>(i);
180 mSwitchedMatrices[bit].push_back(SparseMatrix(
182 mDirectLinearSolvers[bit].push_back(
184 }
185 }
186 } else if (mSystemMatrixRecomputation) {
188 SparseMatrix(2 * (mNumMatrixNodeIndices), 2 * (mNumMatrixNodeIndices));
190 SparseMatrix(2 * (mNumMatrixNodeIndices), 2 * (mNumMatrixNodeIndices));
191 } else {
192 for (std::size_t i = 0; i < (1ULL << mSwitches.size()); i++) {
193 auto bit = std::bitset<SWITCH_NUM>(i);
194 mSwitchedMatrices[bit].push_back(SparseMatrix(
196 mDirectLinearSolvers[bit].push_back(
198 }
199 }
200}
201
202template <typename VarType>
203std::shared_ptr<CPS::Task> MnaSolverDirect<VarType>::createSolveTask() {
204 return std::make_shared<MnaSolverDirect<VarType>::SolveTask>(*this);
205}
206
207template <typename VarType>
209 return std::make_shared<MnaSolverDirect<VarType>::SolveTaskRecomp>(*this);
210}
211
212template <typename VarType>
213std::shared_ptr<CPS::Task>
215 return std::make_shared<MnaSolverDirect<VarType>::SolveTaskHarm>(*this,
216 freqIdx);
217}
218
219template <typename VarType>
220std::shared_ptr<CPS::Task> MnaSolverDirect<VarType>::createLogTask() {
221 return std::make_shared<MnaSolverDirect<VarType>::LogTask>(*this);
222}
223
224template <typename VarType>
225void MnaSolverDirect<VarType>::solve(Real time, Int timeStepCount) {
226 // Reset source vector
227 mRightSideVector.setZero();
228
229 // Add together the right side vector (computed by the components' pre-step tasks)
230 for (auto stamp : mRightVectorStamps)
231 mRightSideVector += *stamp;
232
235
236 if (mSwitchedMatrices.size() > 0) {
237 std::chrono::steady_clock::time_point start;
239 start = std::chrono::steady_clock::now();
240
243
245 auto end = std::chrono::steady_clock::now();
246 std::chrono::duration<Real> diff = end - start;
247 mSolveTimes.push_back(diff.count());
248 }
249 }
250
251 // CHECK: Is this really required? Or can operations actually become part of
252 // correctorStep and mnaPostStep?
253 for (auto syncGen : mSyncGen)
254 syncGen->updateVoltage(**mLeftSideVector);
255
256 // Reset number of iterations
257 mIter = 0;
258
259 // Additional solve steps for iterative models
260 if (mSyncGen.size() > 0) {
261 UInt numCompsRequireIter;
262 do {
263 // count synchronous generators that require iteration
264 numCompsRequireIter = 0;
265 for (auto syncGen : mSyncGen)
266 if (syncGen->requiresIteration())
267 numCompsRequireIter++;
268
269 // recompute solve step if at least one component demands iteration
270 if (numCompsRequireIter > 0) {
271 mIter++;
272
273 // Reset source vector
274 mRightSideVector.setZero();
275
278
279 for (auto syncGen : mSyncGen)
280 syncGen->correctorStep();
281
282 // Add together the right side vector (computed by the components' pre-step tasks)
283 for (auto stamp : mRightVectorStamps)
284 mRightSideVector += *stamp;
285
286 if (mSwitchedMatrices.size() > 0) {
287 auto start = std::chrono::steady_clock::now();
291 auto end = std::chrono::steady_clock::now();
292 std::chrono::duration<Real> diff = end - start;
293 mSolveTimes.push_back(diff.count());
294 }
295
296 // CHECK: Is this really required? Or can operations actually become part of
297 // correctorStep and mnaPostStep?
298 for (auto syncGen : mSyncGen)
299 syncGen->updateVoltage(**mLeftSideVector);
300 }
301 } while (numCompsRequireIter > 0);
302 }
303
304 // TODO split into separate task? (dependent on x, updating all v attributes)
305 for (UInt nodeIdx = 0; nodeIdx < mNumNetNodes; ++nodeIdx)
306 mNodes[nodeIdx]->mnaUpdateVoltage(**mLeftSideVector);
307
308 // Components' states will be updated by the post-step tasks
309}
310
311template <typename VarType>
312void MnaSolverDirect<VarType>::solveWithHarmonics(Real time, Int timeStepCount,
313 Int freqIdx) {
314 mRightSideVectorHarm[freqIdx].setZero();
315
316 // Sum of right side vectors (computed by the components' pre-step tasks)
317 for (auto stamp : mRightVectorStamps)
318 mRightSideVectorHarm[freqIdx] += stamp->col(freqIdx);
319
320 **mLeftSideVectorHarm[freqIdx] =
322 mRightSideVectorHarm[freqIdx]);
323}
324
325template <typename VarType> void MnaSolverDirect<VarType>::logSystemMatrices() {
326 if (mFrequencyParallel) {
327 for (UInt i = 0; i < mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)].size();
328 ++i) {
329 SPDLOG_LOGGER_INFO(mSLog, "System matrix for frequency: {:d} \n{:s}", i,
330 Logger::matrixToString(
331 mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)][i]));
332 }
333
334 for (UInt i = 0; i < mRightSideVectorHarm.size(); ++i) {
335 SPDLOG_LOGGER_INFO(mSLog, "Right side vector for frequency: {:d} \n{:s}",
336 i, Logger::matrixToString(mRightSideVectorHarm[i]));
337 }
338
339 } else if (mSystemMatrixRecomputation) {
340 SPDLOG_LOGGER_INFO(mSLog, "Summarizing matrices: ");
341 SPDLOG_LOGGER_INFO(mSLog, "Base matrix with only static elements: {}",
342 Logger::matrixToString(mBaseSystemMatrix));
343 SPDLOG_LOGGER_INFO(mSLog, "Initial system matrix with variable elements {}",
344 Logger::matrixToString(mVariableSystemMatrix));
345 SPDLOG_LOGGER_INFO(mSLog, "Right side vector: {}",
346 Logger::matrixToString(mRightSideVector));
347 } else {
348 if (mSwitches.size() < 1) {
349 SPDLOG_LOGGER_INFO(mSLog, "System matrix: \n{}",
350 mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)][0]);
351 } else {
352 SPDLOG_LOGGER_INFO(mSLog, "Initial switch status: {:s}",
353 mCurrentSwitchStatus.to_string());
354
355 for (auto sys : mSwitchedMatrices) {
356 SPDLOG_LOGGER_INFO(mSLog, "Switching System matrix {:s} \n{:s}",
357 sys.first.to_string(),
358 Logger::matrixToString(sys.second[0]));
359 }
360 }
361 SPDLOG_LOGGER_INFO(mSLog, "Right side vector: \n{}", mRightSideVector);
362 }
363}
364
365template <typename VarType> void MnaSolverDirect<VarType>::logLUTimes() {
368 logSolveTime();
369}
370
371template <typename VarType> void MnaSolverDirect<VarType>::logSolveTime() {
372 Real solveSum = 0.0;
373 Real solveMax = 0.0;
374 for (auto meas : mSolveTimes) {
375 solveSum += meas;
376 if (meas > solveMax)
377 solveMax = meas;
378 }
379 SPDLOG_LOGGER_INFO(mSLog, "Cumulative solve times: {:.12f}", solveSum);
380 SPDLOG_LOGGER_INFO(mSLog, "Average solve time: {:.12f}",
381 solveSum / static_cast<double>(mSolveTimes.size()));
382 SPDLOG_LOGGER_INFO(mSLog, "Maximum solve time: {:.12f}", solveMax);
383 SPDLOG_LOGGER_INFO(mSLog, "Number of solves: {:d}", mSolveTimes.size());
384}
385
386template <typename VarType>
388 for (auto meas : mFactorizeTimes) {
389 SPDLOG_LOGGER_INFO(mSLog, "LU factorization time: {:.12f}", meas);
390 }
391}
392
393template <typename VarType>
395 Real recompSum = 0.0;
396 Real recompMax = 0.0;
397 for (auto meas : mRecomputationTimes) {
398 recompSum += meas;
399 if (meas > recompMax)
400 recompMax = meas;
401 }
402 // Sometimes, refactorization is not used
403 if (mRecomputationTimes.size() != 0) {
404 SPDLOG_LOGGER_INFO(mSLog, "Cumulative refactorization times: {:.12f}",
405 recompSum);
406 SPDLOG_LOGGER_INFO(mSLog, "Average refactorization time: {:.12f}",
407 recompSum / ((double)mRecomputationTimes.size()));
408 SPDLOG_LOGGER_INFO(mSLog, "Maximum refactorization time: {:.12f}",
409 recompMax);
410 SPDLOG_LOGGER_INFO(mSLog, "Number of refactorizations: {:d}",
411 mRecomputationTimes.size());
412 }
413}
414
415template <typename VarType>
416std::shared_ptr<DirectLinearSolver>
418 CPS::Logger::Log mSLog) {
419 switch (this->mImplementationInUse) {
420 case DirectLinearSolverImpl::DenseLU:
421 return std::make_shared<DenseLUAdapter>(mSLog);
422 case DirectLinearSolverImpl::SparseLU:
423 return std::make_shared<SparseLUAdapter>(mSLog);
424#ifdef WITH_KLU
425 case DirectLinearSolverImpl::KLU:
426 return std::make_shared<KLUAdapter>(mSLog);
427#endif
428#ifdef WITH_CUDA
429 case DirectLinearSolverImpl::CUDADense:
430 return std::make_shared<GpuDenseAdapter>(mSLog);
431#ifdef WITH_CUDA_SPARSE
432 case DirectLinearSolverImpl::CUDASparse:
433 return std::make_shared<GpuSparseAdapter>(mSLog);
434#endif
435#ifdef WITH_MAGMA
436 case DirectLinearSolverImpl::CUDAMagma:
437 return std::make_shared<GpuMagmaAdapter>(mSLog);
438#endif
439#endif
440 default:
441 throw CPS::SystemError("unsupported linear solver implementation.");
442 }
443}
444
445template <typename VarType>
447 DirectLinearSolverImpl implementation) {
448 this->mImplementationInUse = implementation;
449}
450
451template <typename VarType>
456
457} // namespace DPsim
458
459template class DPsim::MnaSolverDirect<Real>;
Solver class using Modified Nodal Analysis (MNA).
std::shared_ptr< CPS::Task > createSolveTask() override
Create a solve task for this solver implementation.
void stampVariableSystemMatrix() override
Stamps components into the variable system matrix.
void logSolveTime()
Logging of the right-hand-side solution time.
void logFactorizationTime()
Logging of the LU factorization time.
void solve(Real time, Int timeStepCount) override
Solves system for single frequency.
void logRecomputationTime()
Logging of the LU refactorization time.
virtual void recomputeSystemMatrix(Real time)
Recomputes systems matrix.
SparseMatrix mVariableSystemMatrix
System matrix including stamp of static and variable elements.
SparseMatrix mBaseSystemMatrix
System matrix including all static elements.
std::unordered_map< std::bitset< SWITCH_NUM >, std::vector< SparseMatrix > > mSwitchedMatrices
Map of system matrices where the key is the bitset describing the switch states.
std::shared_ptr< DirectLinearSolver > createDirectSolverImplementation(CPS::Logger::Log mSLog)
Returns a pointer to an object of type DirectLinearSolver.
void setDirectLinearSolverConfiguration(DirectLinearSolverConfiguration &configuration) override
Sets the linear solver configuration.
DirectLinearSolverImpl mImplementationInUse
LU factorization indicator.
std::shared_ptr< DirectLinearSolver > mDirectLinearSolverVariableSystemMatrix
LU factorization of variable system matrix.
void setDirectLinearSolverImplementation(DirectLinearSolverImpl implementation)
Sets the linear solver to "implementation" and creates an object.
std::shared_ptr< CPS::Task > createSolveTaskHarm(UInt freqIdx) override
Create a solve task for this solver implementation.
std::shared_ptr< CPS::Task > createSolveTaskRecomp() override
Create a solve task for recomputation solver.
void logSystemMatrices() override
Logging of system matrices and source vector.
void createEmptySystemMatrix() override
Create system matrix.
std::shared_ptr< CPS::Task > createLogTask() override
Create a solve task for this solver implementation.
void logLUTimes() override
log LU decomposition times
void switchedMatrixEmpty(std::size_t index) override
Sets all entries in the matrix with the given switch index to zero.
void solveWithSystemMatrixRecomputation(Real time, Int timeStepCount) override
Solves the system with variable system matrix.
void switchedMatrixStamp(std::size_t index, std::vector< std::shared_ptr< CPS::MNAInterface > > &comp) override
Applies a component stamp to the matrix with the given switch index.
std::unordered_map< std::bitset< SWITCH_NUM >, std::vector< std::shared_ptr< DirectLinearSolver > > > mDirectLinearSolvers
Map of direct linear solvers related to the system matrices.
MnaSolverDirect(String name, CPS::Domain domain=CPS::Domain::DP, CPS::Logger::Level logLevel=CPS::Logger::Level::info)
DirectLinearSolverConfiguration mConfigurationInUse
LU factorization configuration.
void solveWithHarmonics(Real time, Int timeStepCount, Int freqIdx) override
Solves system for multiple frequencies.
std::bitset< SWITCH_NUM > mCurrentSwitchStatus
Current status of all switches encoded as bitset.
Definition MNASolver.h:78
std::vector< Matrix > mRightSideVectorHarm
Source vector of known quantities.
Definition MNASolver.h:89
Matrix mRightSideVector
Source vector of known quantities.
Definition MNASolver.h:83
CPS::SystemTopology mSystem
System topology.
Definition MNASolver.h:63
std::vector< Real > mRecomputationTimes
LU refactorization measurements.
Definition MNASolver.h:121
std::vector< Real > mFactorizeTimes
LU factorization measurements.
Definition MNASolver.h:117
std::vector< CPS::Attribute< Matrix >::Ptr > mLeftSideVectorHarm
Solution vector of unknown quantities (parallel frequencies)
Definition MNASolver.h:199
Bool hasVariableComponentChanged()
Checks whether the status of variable MNA elements have changed.
CPS::MNAInterface::List mMNAIntfVariableComps
List of variable components if they must be accessed as MNAInterface objects.
Definition MNASolver.h:98
UInt mNumNetNodes
Number of network nodes, single line equivalent.
Definition MNASolver.h:46
UInt mNumTotalMatrixNodeIndices
Total number of network and virtual nodes, considering individual phases and additional frequencies.
Definition MNASolver.h:58
CPS::MNASyncGenInterface::List mSyncGen
List of synchronous generators that need iterate to solve the differential equations.
Definition MNASolver.h:80
std::vector< const Matrix * > mRightVectorStamps
List of all right side vector contributions.
Definition MNASolver.h:85
void updateSwitchStatus()
Collects the status of switches to select correct system matrix.
std::vector< Real > mSolveTimes
Right-hand side solution measurements.
Definition MNASolver.h:119
std::vector< std::pair< UInt, UInt > > mListVariableSystemMatrixEntries
List of index pairs of varying matrix entries.
Definition MNASolver.h:60
CPS::MNAVariableCompInterface::List mVariableComps
Definition MNASolver.h:96
Int mNumRecomputations
Number of system matrix recomputations.
Definition MNASolver.h:93
CPS::MNAInterface::List mMNAComponents
List of MNA components with static stamp into system matrix.
Definition MNASolver.h:69
UInt mNumMatrixNodeIndices
Number of network and virtual nodes, considering individual phases.
Definition MNASolver.h:50
MnaSolver(String name, CPS::Domain domain=CPS::Domain::DP, CPS::Logger::Level logLevel=CPS::Logger::Level::info)
Constructor should not be called by users but by Simulation.
Definition MNASolver.cpp:19
CPS::Attribute< Matrix >::Ptr mLeftSideVector
Solution vector of unknown quantities.
Definition MNASolver.h:196
CPS::MNASwitchInterface::List mSwitches
Definition MNASolver.h:72
CPS::SimNode< VarType >::List mNodes
List of simulation nodes.
Definition MNASolver.h:65
Bool mSystemMatrixRecomputation
Enable recomputation of system matrix during simulation.
Definition Solver.h:64
CPS::Logger::Log mSLog
Logger.
Definition Solver.h:45
Bool mIsInInitialization
Determines if solver is in initialization phase, which requires different behavior.
Definition Solver.h:59
Bool mLogSolveTimes
Collect step time for logging.
Definition Solver.h:43
Bool mFrequencyParallel
Activates parallelized computation of frequencies.
Definition Solver.h:49