9 #include <dpsim/MNASolverDirect.h>
10 #include <dpsim/SequentialScheduler.h>
12 using namespace DPsim;
17 template <
typename VarType>
19 CPS::Logger::Level logLevel)
20 :
MnaSolver<VarType>(name, domain, logLevel) {
24 template <
typename VarType>
26 mSwitchedMatrices[std::bitset<SWITCH_NUM>(index)][0].setZero();
29 template <
typename VarType>
32 mSwitchedMatrices[std::bitset<SWITCH_NUM>(swIdx)][freqIdx].setZero();
35 template <
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);
43 for (UInt i = 0; i < mSwitches.size(); ++i)
44 mSwitches[i]->mnaApplySwitchSystemMatrixStamp(bit[i], sys, 0);
47 mDirectLinearSolvers[bit][0]->preprocessing(sys,
48 mListVariableSystemMatrixEntries);
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());
56 template <
typename VarType>
59 this->mDirectLinearSolverVariableSystemMatrix =
60 createDirectSolverImplementation(mSLog);
62 this->mDirectLinearSolverVariableSystemMatrix->setConfiguration(
65 SPDLOG_LOGGER_INFO(mSLog,
66 "Number of variable Elements: {}"
67 "\nNumber of MNA components: {}",
68 mVariableComps.size(), mMNAComponents.size());
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));
79 mVariableSystemMatrix = mBaseSystemMatrix;
82 SPDLOG_LOGGER_INFO(mSLog,
"Stamping switches");
83 for (
auto sw : mMNAIntfSwitches)
84 sw->mnaApplySystemMatrixStamp(mVariableSystemMatrix);
87 SPDLOG_LOGGER_INFO(mSLog,
"Stamping variable elements");
88 for (
auto varElem : mMNAIntfVariableComps)
89 varElem->mnaApplySystemMatrixStamp(mVariableSystemMatrix);
91 SPDLOG_LOGGER_INFO(mSLog,
"Initial system matrix with variable elements {}",
92 Logger::matrixToString(mVariableSystemMatrix));
97 mDirectLinearSolverVariableSystemMatrix->preprocessing(
98 mVariableSystemMatrix, mListVariableSystemMatrixEntries);
100 auto start = std::chrono::steady_clock::now();
101 mDirectLinearSolverVariableSystemMatrix->factorize(mVariableSystemMatrix);
102 auto end = std::chrono::steady_clock::now();
103 std::chrono::duration<Real> diff = end - start;
104 mFactorizeTimes.push_back(diff.count());
107 template <
typename VarType>
109 Real time, Int timeStepCount) {
111 mRightSideVector.setZero();
115 for (
auto stamp : mRightVectorStamps)
116 mRightSideVector += *stamp;
119 if (hasVariableComponentChanged())
120 recomputeSystemMatrix(time);
123 auto start = std::chrono::steady_clock::now();
125 mDirectLinearSolverVariableSystemMatrix->solve(mRightSideVector);
126 auto end = std::chrono::steady_clock::now();
127 std::chrono::duration<Real> diff = end - start;
128 mSolveTimes.push_back(diff.count());
131 for (UInt nodeIdx = 0; nodeIdx < mNumNetNodes; ++nodeIdx)
132 mNodes[nodeIdx]->mnaUpdateVoltage(**mLeftSideVector);
137 template <
typename VarType>
140 mVariableSystemMatrix = mBaseSystemMatrix;
143 for (
auto sw : mMNAIntfSwitches)
144 sw->mnaApplySystemMatrixStamp(mVariableSystemMatrix);
147 for (
auto comp : mMNAIntfVariableComps)
148 comp->mnaApplySystemMatrixStamp(mVariableSystemMatrix);
152 auto start = std::chrono::steady_clock::now();
153 mDirectLinearSolverVariableSystemMatrix->partialRefactorize(
154 mVariableSystemMatrix, mListVariableSystemMatrixEntries);
155 auto end = std::chrono::steady_clock::now();
156 std::chrono::duration<Real> diff = end - start;
157 mRecomputationTimes.push_back(diff.count());
158 ++mNumRecomputations;
162 if (mSwitches.size() > SWITCH_NUM)
165 if (mSystemMatrixRecomputation) {
167 SparseMatrix(mNumMatrixNodeIndices, mNumMatrixNodeIndices);
168 mVariableSystemMatrix =
169 SparseMatrix(mNumMatrixNodeIndices, mNumMatrixNodeIndices);
171 for (std::size_t i = 0; i < (1ULL << mSwitches.size()); i++) {
172 auto bit = std::bitset<SWITCH_NUM>(i);
173 mSwitchedMatrices[bit].push_back(
174 SparseMatrix(mNumMatrixNodeIndices, mNumMatrixNodeIndices));
175 mDirectLinearSolvers[bit].push_back(
176 createDirectSolverImplementation(mSLog));
182 if (mSwitches.size() > SWITCH_NUM)
185 if (mFrequencyParallel) {
186 for (UInt i = 0; i < std::pow(2, mSwitches.size()); ++i) {
187 for (Int freq = 0; freq < mSystem.mFrequencies.size(); ++freq) {
188 auto bit = std::bitset<SWITCH_NUM>(i);
189 mSwitchedMatrices[bit].push_back(SparseMatrix(
190 2 * (mNumMatrixNodeIndices), 2 * (mNumMatrixNodeIndices)));
191 mDirectLinearSolvers[bit].push_back(
192 createDirectSolverImplementation(mSLog));
195 }
else if (mSystemMatrixRecomputation) {
197 SparseMatrix(2 * (mNumMatrixNodeIndices), 2 * (mNumMatrixNodeIndices));
198 mVariableSystemMatrix =
199 SparseMatrix(2 * (mNumMatrixNodeIndices), 2 * (mNumMatrixNodeIndices));
201 for (std::size_t i = 0; i < (1ULL << mSwitches.size()); i++) {
202 auto bit = std::bitset<SWITCH_NUM>(i);
203 mSwitchedMatrices[bit].push_back(SparseMatrix(
204 2 * (mNumTotalMatrixNodeIndices), 2 * (mNumTotalMatrixNodeIndices)));
205 mDirectLinearSolvers[bit].push_back(
206 createDirectSolverImplementation(mSLog));
211 template <
typename VarType>
213 return std::make_shared<MnaSolverDirect<VarType>::SolveTask>(*this);
216 template <
typename VarType>
218 return std::make_shared<MnaSolverDirect<VarType>::SolveTaskRecomp>(*this);
221 template <
typename VarType>
222 std::shared_ptr<CPS::Task>
224 return std::make_shared<MnaSolverDirect<VarType>::SolveTaskHarm>(*
this,
228 template <
typename VarType>
230 return std::make_shared<MnaSolverDirect<VarType>::LogTask>(*this);
233 template <
typename VarType>
236 mRightSideVector.setZero();
239 for (
auto stamp : mRightVectorStamps)
240 mRightSideVector += *stamp;
242 if (!mIsInInitialization)
245 if (mSwitchedMatrices.size() > 0) {
246 auto start = std::chrono::steady_clock::now();
248 mDirectLinearSolvers[mCurrentSwitchStatus][0]->solve(mRightSideVector);
249 auto end = std::chrono::steady_clock::now();
250 std::chrono::duration<Real> diff = end - start;
251 mSolveTimes.push_back(diff.count());
256 for (
auto syncGen : mSyncGen)
257 syncGen->updateVoltage(**mLeftSideVector);
263 if (mSyncGen.size() > 0) {
264 UInt numCompsRequireIter;
267 numCompsRequireIter = 0;
268 for (
auto syncGen : mSyncGen)
269 if (syncGen->requiresIteration())
270 numCompsRequireIter++;
273 if (numCompsRequireIter > 0) {
277 mRightSideVector.setZero();
279 if (!mIsInInitialization)
282 for (
auto syncGen : mSyncGen)
283 syncGen->correctorStep();
286 for (
auto stamp : mRightVectorStamps)
287 mRightSideVector += *stamp;
289 if (mSwitchedMatrices.size() > 0) {
290 auto start = std::chrono::steady_clock::now();
292 mDirectLinearSolvers[mCurrentSwitchStatus][0]->solve(
294 auto end = std::chrono::steady_clock::now();
295 std::chrono::duration<Real> diff = end - start;
296 mSolveTimes.push_back(diff.count());
301 for (
auto syncGen : mSyncGen)
302 syncGen->updateVoltage(**mLeftSideVector);
304 }
while (numCompsRequireIter > 0);
308 for (UInt nodeIdx = 0; nodeIdx < mNumNetNodes; ++nodeIdx)
309 mNodes[nodeIdx]->mnaUpdateVoltage(**mLeftSideVector);
314 template <
typename VarType>
317 mRightSideVectorHarm[freqIdx].setZero();
320 for (
auto stamp : mRightVectorStamps)
321 mRightSideVectorHarm[freqIdx] += stamp->col(freqIdx);
323 **mLeftSideVectorHarm[freqIdx] =
324 mDirectLinearSolvers[mCurrentSwitchStatus][freqIdx]->solve(
325 mRightSideVectorHarm[freqIdx]);
329 if (mFrequencyParallel) {
330 for (UInt i = 0; i < mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)].size();
332 SPDLOG_LOGGER_INFO(mSLog,
"System matrix for frequency: {:d} \n{:s}", i,
333 Logger::matrixToString(
334 mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)][i]));
337 for (UInt i = 0; i < mRightSideVectorHarm.size(); ++i) {
338 SPDLOG_LOGGER_INFO(mSLog,
"Right side vector for frequency: {:d} \n{:s}",
339 i, Logger::matrixToString(mRightSideVectorHarm[i]));
342 }
else if (mSystemMatrixRecomputation) {
343 SPDLOG_LOGGER_INFO(mSLog,
"Summarizing matrices: ");
344 SPDLOG_LOGGER_INFO(mSLog,
"Base matrix with only static elements: {}",
345 Logger::matrixToString(mBaseSystemMatrix));
346 SPDLOG_LOGGER_INFO(mSLog,
"Initial system matrix with variable elements {}",
347 Logger::matrixToString(mVariableSystemMatrix));
348 SPDLOG_LOGGER_INFO(mSLog,
"Right side vector: {}",
349 Logger::matrixToString(mRightSideVector));
351 if (mSwitches.size() < 1) {
352 SPDLOG_LOGGER_INFO(mSLog,
"System matrix: \n{}",
353 mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)][0]);
355 SPDLOG_LOGGER_INFO(mSLog,
"Initial switch status: {:s}",
356 mCurrentSwitchStatus.to_string());
358 for (
auto sys : mSwitchedMatrices) {
359 SPDLOG_LOGGER_INFO(mSLog,
"Switching System matrix {:s} \n{:s}",
360 sys.first.to_string(),
361 Logger::matrixToString(sys.second[0]));
364 SPDLOG_LOGGER_INFO(mSLog,
"Right side vector: \n{}", mRightSideVector);
369 logFactorizationTime();
370 logRecomputationTime();
377 for (
auto meas : mSolveTimes) {
382 SPDLOG_LOGGER_INFO(mSLog,
"Cumulative solve times: {:.12f}", solveSum);
383 SPDLOG_LOGGER_INFO(mSLog,
"Average solve time: {:.12f}",
384 solveSum /
static_cast<double>(mSolveTimes.size()));
385 SPDLOG_LOGGER_INFO(mSLog,
"Maximum solve time: {:.12f}", solveMax);
386 SPDLOG_LOGGER_INFO(mSLog,
"Number of solves: {:d}", mSolveTimes.size());
389 template <
typename VarType>
391 for (
auto meas : mFactorizeTimes) {
392 SPDLOG_LOGGER_INFO(mSLog,
"LU factorization time: {:.12f}", meas);
396 template <
typename VarType>
398 Real recompSum = 0.0;
399 Real recompMax = 0.0;
400 for (
auto meas : mRecomputationTimes) {
402 if (meas > recompMax)
406 if (mRecomputationTimes.size() != 0) {
407 SPDLOG_LOGGER_INFO(mSLog,
"Cumulative refactorization times: {:.12f}",
409 SPDLOG_LOGGER_INFO(mSLog,
"Average refactorization time: {:.12f}",
410 recompSum / ((
double)mRecomputationTimes.size()));
411 SPDLOG_LOGGER_INFO(mSLog,
"Maximum refactorization time: {:.12f}",
413 SPDLOG_LOGGER_INFO(mSLog,
"Number of refactorizations: {:d}",
414 mRecomputationTimes.size());
418 template <
typename VarType>
419 std::shared_ptr<DirectLinearSolver>
421 CPS::Logger::Log mSLog) {
422 switch (this->mImplementationInUse) {
423 case DirectLinearSolverImpl::DenseLU:
424 return std::make_shared<DenseLUAdapter>(mSLog);
425 case DirectLinearSolverImpl::SparseLU:
426 return std::make_shared<SparseLUAdapter>(mSLog);
428 case DirectLinearSolverImpl::KLU:
429 return std::make_shared<KLUAdapter>(mSLog);
432 case DirectLinearSolverImpl::CUDADense:
433 return std::make_shared<GpuDenseAdapter>(mSLog);
434 #ifdef WITH_CUDA_SPARSE
435 case DirectLinearSolverImpl::CUDASparse:
436 return std::make_shared<GpuSparseAdapter>(mSLog);
439 case DirectLinearSolverImpl::CUDAMagma:
440 return std::make_shared<GpuMagmaAdapter>(mSLog);
448 template <
typename VarType>
450 DirectLinearSolverImpl implementation) {
451 this->mImplementationInUse = implementation;
454 template <
typename VarType>
457 this->mConfigurationInUse = configuration;
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.
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::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.
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.
MnaSolverDirect(String name, CPS::Domain domain=CPS::Domain::DP, CPS::Logger::Level logLevel=CPS::Logger::Level::info)
void solveWithHarmonics(Real time, Int timeStepCount, Int freqIdx) override
Solves system for multiple frequencies.
Solver class using Modified Nodal Analysis (MNA).
void updateSwitchStatus()
Collects the status of switches to select correct system matrix.