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 std::chrono::steady_clock::time_point start;
248 start = std::chrono::steady_clock::now();
251 mDirectLinearSolvers[mCurrentSwitchStatus][0]->solve(mRightSideVector);
254 auto end = std::chrono::steady_clock::now();
255 std::chrono::duration<Real> diff = end - start;
256 mSolveTimes.push_back(diff.count());
262 for (
auto syncGen : mSyncGen)
263 syncGen->updateVoltage(**mLeftSideVector);
269 if (mSyncGen.size() > 0) {
270 UInt numCompsRequireIter;
273 numCompsRequireIter = 0;
274 for (
auto syncGen : mSyncGen)
275 if (syncGen->requiresIteration())
276 numCompsRequireIter++;
279 if (numCompsRequireIter > 0) {
283 mRightSideVector.setZero();
285 if (!mIsInInitialization)
288 for (
auto syncGen : mSyncGen)
289 syncGen->correctorStep();
292 for (
auto stamp : mRightVectorStamps)
293 mRightSideVector += *stamp;
295 if (mSwitchedMatrices.size() > 0) {
296 auto start = std::chrono::steady_clock::now();
298 mDirectLinearSolvers[mCurrentSwitchStatus][0]->solve(
300 auto end = std::chrono::steady_clock::now();
301 std::chrono::duration<Real> diff = end - start;
302 mSolveTimes.push_back(diff.count());
307 for (
auto syncGen : mSyncGen)
308 syncGen->updateVoltage(**mLeftSideVector);
310 }
while (numCompsRequireIter > 0);
314 for (UInt nodeIdx = 0; nodeIdx < mNumNetNodes; ++nodeIdx)
315 mNodes[nodeIdx]->mnaUpdateVoltage(**mLeftSideVector);
320 template <
typename VarType>
323 mRightSideVectorHarm[freqIdx].setZero();
326 for (
auto stamp : mRightVectorStamps)
327 mRightSideVectorHarm[freqIdx] += stamp->col(freqIdx);
329 **mLeftSideVectorHarm[freqIdx] =
330 mDirectLinearSolvers[mCurrentSwitchStatus][freqIdx]->solve(
331 mRightSideVectorHarm[freqIdx]);
335 if (mFrequencyParallel) {
336 for (UInt i = 0; i < mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)].size();
338 SPDLOG_LOGGER_INFO(mSLog,
"System matrix for frequency: {:d} \n{:s}", i,
339 Logger::matrixToString(
340 mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)][i]));
343 for (UInt i = 0; i < mRightSideVectorHarm.size(); ++i) {
344 SPDLOG_LOGGER_INFO(mSLog,
"Right side vector for frequency: {:d} \n{:s}",
345 i, Logger::matrixToString(mRightSideVectorHarm[i]));
348 }
else if (mSystemMatrixRecomputation) {
349 SPDLOG_LOGGER_INFO(mSLog,
"Summarizing matrices: ");
350 SPDLOG_LOGGER_INFO(mSLog,
"Base matrix with only static elements: {}",
351 Logger::matrixToString(mBaseSystemMatrix));
352 SPDLOG_LOGGER_INFO(mSLog,
"Initial system matrix with variable elements {}",
353 Logger::matrixToString(mVariableSystemMatrix));
354 SPDLOG_LOGGER_INFO(mSLog,
"Right side vector: {}",
355 Logger::matrixToString(mRightSideVector));
357 if (mSwitches.size() < 1) {
358 SPDLOG_LOGGER_INFO(mSLog,
"System matrix: \n{}",
359 mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)][0]);
361 SPDLOG_LOGGER_INFO(mSLog,
"Initial switch status: {:s}",
362 mCurrentSwitchStatus.to_string());
364 for (
auto sys : mSwitchedMatrices) {
365 SPDLOG_LOGGER_INFO(mSLog,
"Switching System matrix {:s} \n{:s}",
366 sys.first.to_string(),
367 Logger::matrixToString(sys.second[0]));
370 SPDLOG_LOGGER_INFO(mSLog,
"Right side vector: \n{}", mRightSideVector);
375 logFactorizationTime();
376 logRecomputationTime();
383 for (
auto meas : mSolveTimes) {
388 SPDLOG_LOGGER_INFO(mSLog,
"Cumulative solve times: {:.12f}", solveSum);
389 SPDLOG_LOGGER_INFO(mSLog,
"Average solve time: {:.12f}",
390 solveSum /
static_cast<double>(mSolveTimes.size()));
391 SPDLOG_LOGGER_INFO(mSLog,
"Maximum solve time: {:.12f}", solveMax);
392 SPDLOG_LOGGER_INFO(mSLog,
"Number of solves: {:d}", mSolveTimes.size());
395 template <
typename VarType>
397 for (
auto meas : mFactorizeTimes) {
398 SPDLOG_LOGGER_INFO(mSLog,
"LU factorization time: {:.12f}", meas);
402 template <
typename VarType>
404 Real recompSum = 0.0;
405 Real recompMax = 0.0;
406 for (
auto meas : mRecomputationTimes) {
408 if (meas > recompMax)
412 if (mRecomputationTimes.size() != 0) {
413 SPDLOG_LOGGER_INFO(mSLog,
"Cumulative refactorization times: {:.12f}",
415 SPDLOG_LOGGER_INFO(mSLog,
"Average refactorization time: {:.12f}",
416 recompSum / ((
double)mRecomputationTimes.size()));
417 SPDLOG_LOGGER_INFO(mSLog,
"Maximum refactorization time: {:.12f}",
419 SPDLOG_LOGGER_INFO(mSLog,
"Number of refactorizations: {:d}",
420 mRecomputationTimes.size());
424 template <
typename VarType>
425 std::shared_ptr<DirectLinearSolver>
427 CPS::Logger::Log mSLog) {
428 switch (this->mImplementationInUse) {
429 case DirectLinearSolverImpl::DenseLU:
430 return std::make_shared<DenseLUAdapter>(mSLog);
431 case DirectLinearSolverImpl::SparseLU:
432 return std::make_shared<SparseLUAdapter>(mSLog);
434 case DirectLinearSolverImpl::KLU:
435 return std::make_shared<KLUAdapter>(mSLog);
438 case DirectLinearSolverImpl::CUDADense:
439 return std::make_shared<GpuDenseAdapter>(mSLog);
440 #ifdef WITH_CUDA_SPARSE
441 case DirectLinearSolverImpl::CUDASparse:
442 return std::make_shared<GpuSparseAdapter>(mSLog);
445 case DirectLinearSolverImpl::CUDAMagma:
446 return std::make_shared<GpuMagmaAdapter>(mSLog);
454 template <
typename VarType>
456 DirectLinearSolverImpl implementation) {
457 this->mImplementationInUse = implementation;
460 template <
typename VarType>
463 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.
Bool mLogSolveTimes
Collect step time for logging.