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
117
118 // Calculate new solution vector
119 auto start = std::chrono::steady_clock::now();
122 auto end = std::chrono::steady_clock::now();
123 std::chrono::duration<Real> diff = end - start;
124 mSolveTimes.push_back(diff.count());
125
126 // TODO split into separate task? (dependent on x, updating all v attributes)
127 for (UInt nodeIdx = 0; nodeIdx < mNumNetNodes; ++nodeIdx)
128 mNodes[nodeIdx]->mnaUpdateVoltage(**mLeftSideVector);
129
130 // Components' states will be updated by the post-step tasks
131}
132
133template <typename VarType>
135 // Start from base matrix
137
138 // Now stamp variable elements and switches into matrix
139 for (auto comp : mMNAIntfVariableComps)
140 comp->mnaApplySystemMatrixStamp(mVariableSystemMatrix);
141
142 // Refactorization of matrix assuming that structure remained
143 // constant by omitting analyzePattern
144 auto start = std::chrono::steady_clock::now();
145 mDirectLinearSolverVariableSystemMatrix->partialRefactorize(
147 auto end = std::chrono::steady_clock::now();
148 std::chrono::duration<Real> diff = end - start;
149 mRecomputationTimes.push_back(diff.count());
151}
152
167
169 if (mSwitches.size() > SWITCH_NUM)
170 throw SystemError("Too many Switches.");
171
177 } else {
178 for (std::size_t i = 0; i < (1ULL << mSwitches.size()); i++) {
179 auto bit = std::bitset<SWITCH_NUM>(i);
180 mSwitchedMatrices[bit].push_back(
182 mDirectLinearSolvers[bit].push_back(
184 }
185 }
186}
187
189 if (mSwitches.size() > SWITCH_NUM)
190 throw SystemError("Too many Switches.");
191
192 if (mFrequencyParallel) {
193 for (UInt i = 0; i < std::pow(2, mSwitches.size()); ++i) {
194 for (Int freq = 0; freq < mSystem.mFrequencies.size(); ++freq) {
195 auto bit = std::bitset<SWITCH_NUM>(i);
196 mSwitchedMatrices[bit].push_back(SparseMatrix(
198 mDirectLinearSolvers[bit].push_back(
200 }
201 }
202 } else if (mSystemMatrixRecomputation) {
204 SparseMatrix(2 * (mNumMatrixNodeIndices), 2 * (mNumMatrixNodeIndices));
206 SparseMatrix(2 * (mNumMatrixNodeIndices), 2 * (mNumMatrixNodeIndices));
207 } else {
208 for (std::size_t i = 0; i < (1ULL << mSwitches.size()); i++) {
209 auto bit = std::bitset<SWITCH_NUM>(i);
210 mSwitchedMatrices[bit].push_back(SparseMatrix(
212 mDirectLinearSolvers[bit].push_back(
214 }
215 }
216}
217
218template <typename VarType>
219std::shared_ptr<CPS::Task> MnaSolverDirect<VarType>::createSolveTask() {
220 return std::make_shared<MnaSolverDirect<VarType>::SolveTask>(*this);
221}
222
223template <typename VarType>
225 return std::make_shared<MnaSolverDirect<VarType>::SolveTaskRecomp>(*this);
226}
227
228template <typename VarType>
229std::shared_ptr<CPS::Task>
231 return std::make_shared<MnaSolverDirect<VarType>::SolveTaskHarm>(*this,
232 freqIdx);
233}
234
235template <typename VarType>
236std::shared_ptr<CPS::Task>
241
242template <typename VarType>
243std::shared_ptr<CPS::Task> MnaSolverDirect<VarType>::createLogTask() {
244 return std::make_shared<MnaSolverDirect<VarType>::LogTask>(*this);
245}
246
247template <typename VarType>
248void MnaSolverDirect<VarType>::solve(Real time, Int timeStepCount) {
249 const auto previousSwitchStatus = mCurrentSwitchStatus;
250 // Reset source vector
251 mRightSideVector.setZero();
252
253 // Add together the right side vector (computed by the components' pre-step tasks)
254 for (auto stamp : mRightVectorStamps)
255 mRightSideVector += *stamp;
256
259
260 if (mSwitchedMatrices.size() > 0) {
261 std::chrono::steady_clock::time_point start;
263 start = std::chrono::steady_clock::now();
264
267
269 auto end = std::chrono::steady_clock::now();
270 std::chrono::duration<Real> diff = end - start;
271 mSolveTimes.push_back(diff.count());
272 }
273 }
274
275 // CHECK: Is this really required? Or can operations actually become part of
276 // correctorStep and mnaPostStep?
277 for (auto syncGen : mSyncGen)
278 syncGen->updateVoltage(**mLeftSideVector);
279
280 // Reset number of iterations
281 mIter = 0;
282
283 // Additional solve steps for iterative models
284 if (mSyncGen.size() > 0) {
285 UInt numCompsRequireIter;
286 do {
287 // count synchronous generators that require iteration
288 numCompsRequireIter = 0;
289 for (auto syncGen : mSyncGen)
290 if (syncGen->requiresIteration())
291 numCompsRequireIter++;
292
293 // recompute solve step if at least one component demands iteration
294 if (numCompsRequireIter > 0) {
295 mIter++;
296
297 // Reset source vector
298 mRightSideVector.setZero();
299
302
303 for (auto syncGen : mSyncGen)
304 syncGen->correctorStep();
305
306 // Add together the right side vector (computed by the components' pre-step tasks)
307 for (auto stamp : mRightVectorStamps)
308 mRightSideVector += *stamp;
309
310 if (mSwitchedMatrices.size() > 0) {
311 auto start = std::chrono::steady_clock::now();
315 auto end = std::chrono::steady_clock::now();
316 std::chrono::duration<Real> diff = end - start;
317 mSolveTimes.push_back(diff.count());
318 }
319
320 // CHECK: Is this really required? Or can operations actually become part of
321 // correctorStep and mnaPostStep?
322 for (auto syncGen : mSyncGen)
323 syncGen->updateVoltage(**mLeftSideVector);
324 }
325 } while (numCompsRequireIter > 0);
326 }
327
328 mSystemMatrixChanged = (mCurrentSwitchStatus != previousSwitchStatus);
329
330 // TODO split into separate task? (dependent on x, updating all v attributes)
331 for (UInt nodeIdx = 0; nodeIdx < mNumNetNodes; ++nodeIdx)
332 mNodes[nodeIdx]->mnaUpdateVoltage(**mLeftSideVector);
333
334 // Components' states will be updated by the post-step tasks
335}
336
337template <typename VarType>
338void MnaSolverDirect<VarType>::solveWithHarmonics(Real time, Int timeStepCount,
339 Int freqIdx) {
340 mRightSideVectorHarm[freqIdx].setZero();
341
342 // Sum of right side vectors (computed by the components' pre-step tasks)
343 for (auto stamp : mRightVectorStamps)
344 mRightSideVectorHarm[freqIdx] += stamp->col(freqIdx);
345
346 **mLeftSideVectorHarm[freqIdx] =
348 mRightSideVectorHarm[freqIdx]);
349}
350
351template <typename VarType> void MnaSolverDirect<VarType>::logSystemMatrices() {
352 if (mFrequencyParallel) {
353 for (UInt i = 0; i < mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)].size();
354 ++i) {
355 SPDLOG_LOGGER_INFO(mSLog, "System matrix for frequency: {:d} \n{:s}", i,
356 Logger::matrixToString(
357 mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)][i]));
358 }
359
360 for (UInt i = 0; i < mRightSideVectorHarm.size(); ++i) {
361 SPDLOG_LOGGER_INFO(mSLog, "Right side vector for frequency: {:d} \n{:s}",
362 i, Logger::matrixToString(mRightSideVectorHarm[i]));
363 }
364
365 } else if (mSystemMatrixRecomputation) {
366 SPDLOG_LOGGER_INFO(mSLog, "Summarizing matrices: ");
367 SPDLOG_LOGGER_INFO(mSLog, "Base matrix with only static elements: {}",
368 Logger::matrixToString(mBaseSystemMatrix));
369 SPDLOG_LOGGER_INFO(mSLog, "Initial system matrix with variable elements {}",
370 Logger::matrixToString(mVariableSystemMatrix));
371 SPDLOG_LOGGER_INFO(mSLog, "Right side vector: {}",
372 Logger::matrixToString(mRightSideVector));
373 } else {
374 if (mSwitches.size() < 1) {
375 SPDLOG_LOGGER_INFO(mSLog, "System matrix: \n{}",
376 mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)][0]);
377 } else {
378 SPDLOG_LOGGER_INFO(mSLog, "Initial switch status: {:s}",
379 mCurrentSwitchStatus.to_string());
380
381 for (auto sys : mSwitchedMatrices) {
382 SPDLOG_LOGGER_INFO(mSLog, "Switching System matrix {:s} \n{:s}",
383 sys.first.to_string(),
384 Logger::matrixToString(sys.second[0]));
385 }
386 }
387 SPDLOG_LOGGER_INFO(mSLog, "Right side vector: \n{}", mRightSideVector);
388 }
389}
390
391template <typename VarType> void MnaSolverDirect<VarType>::logLUTimes() {
394 logSolveTime();
395}
396
397template <typename VarType> void MnaSolverDirect<VarType>::logSolveTime() {
398 Real solveSum = 0.0;
399 Real solveMax = 0.0;
400 for (auto meas : mSolveTimes) {
401 solveSum += meas;
402 if (meas > solveMax)
403 solveMax = meas;
404 }
405 SPDLOG_LOGGER_INFO(mSLog, "Cumulative solve times: {:.12f}", solveSum);
406 SPDLOG_LOGGER_INFO(mSLog, "Average solve time: {:.12f}",
407 solveSum / static_cast<double>(mSolveTimes.size()));
408 SPDLOG_LOGGER_INFO(mSLog, "Maximum solve time: {:.12f}", solveMax);
409 SPDLOG_LOGGER_INFO(mSLog, "Number of solves: {:d}", mSolveTimes.size());
410}
411
412template <typename VarType>
414 for (auto meas : mFactorizeTimes) {
415 SPDLOG_LOGGER_INFO(mSLog, "LU factorization time: {:.12f}", meas);
416 }
417}
418
419template <typename VarType>
421 Real recompSum = 0.0;
422 Real recompMax = 0.0;
423 for (auto meas : mRecomputationTimes) {
424 recompSum += meas;
425 if (meas > recompMax)
426 recompMax = meas;
427 }
428 // Sometimes, refactorization is not used
429 if (mRecomputationTimes.size() != 0) {
430 SPDLOG_LOGGER_INFO(mSLog, "Cumulative refactorization times: {:.12f}",
431 recompSum);
432 SPDLOG_LOGGER_INFO(mSLog, "Average refactorization time: {:.12f}",
433 recompSum / ((double)mRecomputationTimes.size()));
434 SPDLOG_LOGGER_INFO(mSLog, "Maximum refactorization time: {:.12f}",
435 recompMax);
436 SPDLOG_LOGGER_INFO(mSLog, "Number of refactorizations: {:d}",
437 mRecomputationTimes.size());
438 }
439}
440
441template <typename VarType>
442std::shared_ptr<DirectLinearSolver>
444 CPS::Logger::Log mSLog) {
445 switch (this->mImplementationInUse) {
446 case DirectLinearSolverImpl::DenseLU:
447 return std::make_shared<DenseLUAdapter>(mSLog);
448 case DirectLinearSolverImpl::SparseLU:
449 return std::make_shared<SparseLUAdapter>(mSLog);
450#ifdef WITH_KLU
451 case DirectLinearSolverImpl::KLU:
452 return std::make_shared<KLUAdapter>(mSLog);
453#endif
454#ifdef WITH_CUDA
455 case DirectLinearSolverImpl::CUDADense:
456 return std::make_shared<GpuDenseAdapter>(mSLog);
457#ifdef WITH_CUDA_SPARSE
458 case DirectLinearSolverImpl::CUDASparse:
459 return std::make_shared<GpuSparseAdapter>(mSLog);
460#endif
461#ifdef WITH_MAGMA
462 case DirectLinearSolverImpl::CUDAMagma:
463 return std::make_shared<GpuMagmaAdapter>(mSLog);
464#endif
465#endif
466 default:
467 throw CPS::SystemError("unsupported linear solver implementation.");
468 }
469}
470
471template <typename VarType>
473 DirectLinearSolverImpl implementation) {
474 this->mImplementationInUse = implementation;
475}
476
477template <typename VarType>
482
483} // namespace DPsim
484
485template 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 extractStateSpace()
Runs state-space extraction using the active linear solver.
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.
Bool mSystemMatrixChanged
Tracks active MNA system-matrix changes from the last solve step.
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.
Bool mVariableComponentChanged
Tracks variable-component changes from the last solve step.
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.
std::shared_ptr< CPS::Task > createStateSpaceExtractionTask() override
Create state-space extraction task for this solver implementation.
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:79
std::vector< Matrix > mRightSideVectorHarm
Source vector of known quantities.
Definition MNASolver.h:90
Matrix mRightSideVector
Source vector of known quantities.
Definition MNASolver.h:84
CPS::SystemTopology mSystem
System topology.
Definition MNASolver.h:64
std::vector< Real > mRecomputationTimes
LU refactorization measurements.
Definition MNASolver.h:122
std::vector< Real > mFactorizeTimes
LU factorization measurements.
Definition MNASolver.h:118
std::vector< CPS::Attribute< Matrix >::Ptr > mLeftSideVectorHarm
Solution vector of unknown quantities (parallel frequencies)
Definition MNASolver.h:211
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:99
UInt mNumNetNodes
Number of network nodes, single line equivalent.
Definition MNASolver.h:47
MNAStateSpaceExtractor::Ptr mStateSpaceExtractor
Extractor for the MNA-coupled state-space model.
Definition MNASolver.h:129
UInt mNumTotalMatrixNodeIndices
Total number of network and virtual nodes, considering individual phases and additional frequencies.
Definition MNASolver.h:59
CPS::MNASyncGenInterface::List mSyncGen
List of synchronous generators that need iterate to solve the differential equations.
Definition MNASolver.h:81
std::vector< const Matrix * > mRightVectorStamps
List of all right side vector contributions.
Definition MNASolver.h:86
void updateSwitchStatus()
Collects the status of switches to select correct system matrix.
std::vector< Real > mSolveTimes
Right-hand side solution measurements.
Definition MNASolver.h:120
std::vector< std::pair< UInt, UInt > > mListVariableSystemMatrixEntries
List of index pairs of varying matrix entries.
Definition MNASolver.h:61
CPS::MNAVariableCompInterface::List mVariableComps
Definition MNASolver.h:97
Int mNumRecomputations
Number of system matrix recomputations.
Definition MNASolver.h:94
CPS::MNAInterface::List mMNAComponents
List of MNA components with static stamp into system matrix.
Definition MNASolver.h:70
UInt mNumMatrixNodeIndices
Number of network and virtual nodes, considering individual phases.
Definition MNASolver.h:51
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:21
CPS::Attribute< Matrix >::Ptr mLeftSideVector
Solution vector of unknown quantities.
Definition MNASolver.h:208
CPS::MNASwitchInterface::List mSwitches
Definition MNASolver.h:73
CPS::SimNode< VarType >::List mNodes
List of simulation nodes.
Definition MNASolver.h:66
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