DPsim
Loading...
Searching...
No Matches
MNASolver.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/MNASolver.h>
10#include <dpsim/SequentialScheduler.h>
11#include <memory>
12#include <stdexcept>
13#include <type_traits>
14
15using namespace DPsim;
16using namespace CPS;
17
18namespace DPsim {
19
20template <typename VarType>
21MnaSolver<VarType>::MnaSolver(String name, CPS::Domain domain,
22 CPS::Logger::Level logLevel)
23 : Solver(name, logLevel), mDomain(domain) {
24
25 // Raw source and solution vector logging
26 mLeftVectorLog = std::make_shared<DataLogger>(
27 name + "_LeftVector", logLevel == CPS::Logger::Level::trace);
28 mRightVectorLog = std::make_shared<DataLogger>(
29 name + "_RightVector", logLevel == CPS::Logger::Level::trace);
30}
31
32template <typename VarType>
33void MnaSolver<VarType>::setSystem(const CPS::SystemTopology &system) {
34 mSystem = system;
35}
36
37template <typename VarType>
41
42template <typename VarType>
46 throw std::logic_error(
47 "MNA state-space extractor has not been initialized.");
48
50}
51
52template <typename VarType> void MnaSolver<VarType>::initialize() {
53 // TODO: check that every system matrix has the same dimensions
54 SPDLOG_LOGGER_INFO(mSLog, "---- Start initialization ----");
55 mLeftVectorLog->start();
56 mRightVectorLog->start();
57
58 // Register attribute for solution vector
60 // Best case we have some kind of sub-attributes for attribute vectors / tensor attributes...
62 SPDLOG_LOGGER_INFO(mSLog, "Computing network harmonics in parallel.");
63 for (Int freq = 0; freq < mSystem.mFrequencies.size(); ++freq) {
65 }
66 } else {
68 }
69
70 SPDLOG_LOGGER_INFO(mSLog, "-- Process topology");
71 for (auto comp : mSystem.mComponents)
72 SPDLOG_LOGGER_INFO(mSLog, "Added {:s} '{:s}' to simulation.", comp->type(),
73 comp->name());
74
75 // Otherwise LU decomposition will fail
76 if (mSystem.mComponents.size() == 0)
77 throw SolverException();
78
79 // We need to differentiate between power and signal components and
80 // ground nodes should be ignored.
82 // These steps complete the network information.
85
86 SPDLOG_LOGGER_INFO(mSLog, "-- Create empty MNA system matrices and vectors");
89
90 // Initialize components from powerflow solution and
91 // calculate MNA specific initialization values.
93
94 if (mSteadyStateInit) {
96 steadyStateInitialization();
97 }
98 mIsInInitialization = false;
99
100 // Some components feature a different behaviour for simulation and initialization
101 for (auto comp : mSystem.mComponents) {
102 auto powerComp = std::dynamic_pointer_cast<CPS::TopologicalPowerComp>(comp);
103 if (powerComp)
104 powerComp->setBehaviour(TopologicalPowerComp::Behaviour::MNASimulation);
105
106 auto sigComp = std::dynamic_pointer_cast<CPS::SimSignalComp>(comp);
107 if (sigComp)
108 sigComp->setBehaviour(SimSignalComp::Behaviour::Simulation);
109 }
110
111 // Initialize system matrices and source vector.
113
116
117 SPDLOG_LOGGER_INFO(mSLog, "--- Initialization finished ---");
118 SPDLOG_LOGGER_INFO(mSLog, "--- Initial system matrices and vectors ---");
120
121 mSLog->flush();
122}
123
124template <> void MnaSolver<Real>::initializeComponents() {
125 SPDLOG_LOGGER_INFO(mSLog, "-- Initialize components from power flow");
126
127 CPS::MNAInterface::List allMNAComps;
128 allMNAComps.insert(allMNAComps.end(), mMNAComponents.begin(),
129 mMNAComponents.end());
130 allMNAComps.insert(allMNAComps.end(), mMNAIntfVariableComps.begin(),
131 mMNAIntfVariableComps.end());
132
133 for (auto comp : allMNAComps) {
134 auto pComp = std::dynamic_pointer_cast<SimPowerComp<Real>>(comp);
135 if (!pComp)
136 continue;
137 pComp->checkForUnconnectedTerminals();
138 if (mInitFromNodesAndTerminals)
139 pComp->initializeFromNodesAndTerminals(mSystem.mSystemFrequency);
140 }
141
142 // Initialize signal components.
143 for (auto comp : mSimSignalComps)
144 comp->initialize(mSystem.mSystemOmega, mTimeStep);
145
146 // Initialize MNA specific parts of components.
147 for (auto comp : allMNAComps) {
148 comp->mnaInitialize(mSystem.mSystemOmega, mTimeStep, mLeftSideVector);
149 const Matrix &stamp = comp->getRightVector()->get();
150 if (stamp.size() != 0) {
151 mRightVectorStamps.push_back(&stamp);
152 }
153 }
154
155 for (auto comp : mMNAIntfSwitches)
156 comp->mnaInitialize(mSystem.mSystemOmega, mTimeStep, mLeftSideVector);
157
158 // Initialize nodes
159 for (UInt nodeIdx = 0; nodeIdx < mNodes.size(); ++nodeIdx)
160 mNodes[nodeIdx]->initialize();
161}
162
164 SPDLOG_LOGGER_INFO(mSLog, "-- Initialize components from power flow");
165
166 CPS::MNAInterface::List allMNAComps;
167 allMNAComps.insert(allMNAComps.end(), mMNAComponents.begin(),
168 mMNAComponents.end());
169 allMNAComps.insert(allMNAComps.end(), mMNAIntfVariableComps.begin(),
170 mMNAIntfVariableComps.end());
171
172 // Initialize power components with frequencies and from powerflow results
173 for (auto comp : allMNAComps) {
174 auto pComp = std::dynamic_pointer_cast<SimPowerComp<Complex>>(comp);
175 if (!pComp)
176 continue;
177 pComp->checkForUnconnectedTerminals();
178 if (mInitFromNodesAndTerminals)
179 pComp->initializeFromNodesAndTerminals(mSystem.mSystemFrequency);
180 }
181
182 // Initialize signal components.
183 for (auto comp : mSimSignalComps)
184 comp->initialize(mSystem.mSystemOmega, mTimeStep);
185
186 SPDLOG_LOGGER_INFO(mSLog, "-- Initialize MNA properties of components");
187 if (mFrequencyParallel) {
188 // Initialize MNA specific parts of components.
189 for (auto comp : mMNAComponents) {
190 // Initialize MNA specific parts of components.
191 comp->mnaInitializeHarm(mSystem.mSystemOmega, mTimeStep,
192 mLeftSideVectorHarm);
193 const Matrix &stamp = comp->getRightVector()->get();
194 if (stamp.size() != 0)
195 mRightVectorStamps.push_back(&stamp);
196 }
197 // Initialize nodes
198 for (UInt nodeIdx = 0; nodeIdx < mNodes.size(); ++nodeIdx) {
199 mNodes[nodeIdx]->mnaInitializeHarm(mLeftSideVectorHarm);
200 }
201 } else {
202 // Initialize MNA specific parts of components.
203 for (auto comp : allMNAComps) {
204 comp->mnaInitialize(mSystem.mSystemOmega, mTimeStep, mLeftSideVector);
205 const Matrix &stamp = comp->getRightVector()->get();
206 if (stamp.size() != 0) {
207 mRightVectorStamps.push_back(&stamp);
208 }
209 }
210
211 for (auto comp : mMNAIntfSwitches)
212 comp->mnaInitialize(mSystem.mSystemOmega, mTimeStep, mLeftSideVector);
213
214 // Initialize nodes
215 for (UInt nodeIdx = 0; nodeIdx < mNodes.size(); ++nodeIdx)
216 mNodes[nodeIdx]->initialize();
217 }
218}
219
220template <typename VarType> void MnaSolver<VarType>::initializeSystem() {
221 SPDLOG_LOGGER_INFO(mSLog,
222 "-- Initialize MNA system matrices and source vector");
223 mRightSideVector.setZero();
224
225 // just a sanity check in case we change the static
226 // initialization of the switch number in the future
227 if (mSwitches.size() > sizeof(std::size_t) * 8) {
228 throw SystemError("Too many Switches.");
229 }
230
235 else
237}
238
239template <typename VarType>
241 // iterate over all possible switch state combinations and frequencies
242 for (std::size_t sw = 0; sw < (1ULL << mSwitches.size()); ++sw) {
243 for (Int freq = 0; freq < mSystem.mFrequencies.size(); ++freq) {
244 switchedMatrixEmpty(sw, freq);
246 }
247 }
248
249 if (mSwitches.size() > 0)
251
252 // Initialize source vector
253 for (Int freq = 0; freq < mSystem.mFrequencies.size(); ++freq) {
254 for (auto comp : mMNAComponents)
255 comp->mnaApplyRightSideVectorStampHarm(mRightSideVectorHarm[freq], freq);
256 }
257}
258
259template <typename VarType>
261 // iterate over all possible switch state combinations
262 for (std::size_t i = 0; i < (1ULL << mSwitches.size()); i++) {
264 }
265
266 if (mSwitches.size() < 1) {
268 } else {
269 // Generate switching state dependent system matrices
270 for (std::size_t i = 0; i < (1ULL << mSwitches.size()); i++) {
272 }
274 }
275
276 // Initialize source vector for debugging
277 // CAUTION: this does not always deliver proper source vector initialization
278 // as not full pre-step is executed (not involving necessary electrical or signal
279 // subcomp updates before right vector calculation)
280 for (auto comp : mMNAComponents) {
281 comp->mnaApplyRightSideVectorStamp(mRightSideVector);
282 auto idObj = std::dynamic_pointer_cast<IdentifiedObject>(comp);
283 SPDLOG_LOGGER_DEBUG(mSLog, "Stamping {:s} {:s} into source vector",
284 idObj->type(), idObj->name());
285 if (mSLog->should_log(spdlog::level::trace))
286 mSLog->trace("\n{:s}", Logger::matrixToString(mRightSideVector));
287 }
288}
289
290template <typename VarType>
292
293 // Collect index pairs of varying matrix entries from components
294 for (auto varElem : mVariableComps)
295 for (auto varEntry : varElem->mVariableSystemMatrixEntries)
296 mListVariableSystemMatrixEntries.push_back(varEntry);
297 SPDLOG_LOGGER_INFO(mSLog, "List of index pairs of varying matrix entries: ");
298 for (auto indexPair : mListVariableSystemMatrixEntries)
299 SPDLOG_LOGGER_INFO(mSLog, "({}, {})", indexPair.first, indexPair.second);
300
302
303 // Initialize source vector for debugging
304 // CAUTION: this does not always deliver proper source vector initialization
305 // as not full pre-step is executed (not involving necessary electrical or signal
306 // subcomp updates before right vector calculation)
307 for (auto comp : mMNAComponents) {
308 comp->mnaApplyRightSideVectorStamp(mRightSideVector);
309 auto idObj = std::dynamic_pointer_cast<IdentifiedObject>(comp);
310 SPDLOG_LOGGER_DEBUG(mSLog, "Stamping {:s} {:s} into source vector",
311 idObj->type(), idObj->name());
312 if (mSLog->should_log(spdlog::level::trace))
313 mSLog->trace("\n{:s}", Logger::matrixToString(mRightSideVector));
314 }
315}
316
317template <typename VarType>
319 if (mDomain != CPS::Domain::EMT) {
320 throw std::logic_error(
321 "MNA state-space extraction supports EMT domain only.");
322 }
323
324 if (!std::is_same<VarType, Real>::value) {
325 throw std::logic_error(
326 "MNA state-space extraction supports real-valued MNA systems only.");
327 }
328
329 if (mFrequencyParallel) {
330 throw std::logic_error(
331 "MNA state-space extraction does not support frequency-parallel "
332 "MNA systems.");
333 }
334
335 CPS::MNAInterface::List stateSpaceComponents;
336 stateSpaceComponents.insert(stateSpaceComponents.end(),
337 mMNAComponents.begin(), mMNAComponents.end());
338 stateSpaceComponents.insert(stateSpaceComponents.end(),
339 mMNAIntfVariableComps.begin(),
341
342 const UInt mnaVectorSize = static_cast<UInt>((**mLeftSideVector).rows());
343
344 mStateSpaceExtractor = std::make_shared<MNAStateSpaceExtractor>();
345 mStateSpaceExtractor->initialize(stateSpaceComponents, mnaVectorSize,
346 mTimeStep);
347
348 SPDLOG_LOGGER_INFO(
349 mSLog,
350 "Initialized MNA state-space extractor with {:d} extraction states.",
351 mStateSpaceExtractor->getStateCount());
352}
353
354template <typename VarType>
356 for (auto varElem : mVariableComps) {
357 if (varElem->hasParameterChanged()) {
358 auto idObj = std::dynamic_pointer_cast<IdentifiedObject>(varElem);
359 SPDLOG_LOGGER_DEBUG(
360 mSLog, "Component ({:s} {:s}) value changed -> Update System Matrix",
361 idObj->type(), idObj->name());
362 return true;
363 }
364 }
365 return false;
366}
367
368template <typename VarType> void MnaSolver<VarType>::updateSwitchStatus() {
369 for (UInt i = 0; i < mSwitches.size(); ++i) {
370 mCurrentSwitchStatus.set(i, mSwitches[i]->mnaIsClosed());
371 }
372}
373
374template <typename VarType> void MnaSolver<VarType>::identifyTopologyObjects() {
375 for (auto baseNode : mSystem.mNodes) {
376 // Add nodes to the list and ignore ground nodes.
377 if (!baseNode->isGround()) {
378 auto node = std::dynamic_pointer_cast<CPS::SimNode<VarType>>(baseNode);
379 mNodes.push_back(node);
380 SPDLOG_LOGGER_INFO(mSLog, "Added node {:s}", node->name());
381 }
382 }
383
384 for (auto comp : mSystem.mComponents) {
385
386 auto genComp = std::dynamic_pointer_cast<CPS::MNASyncGenInterface>(comp);
387 if (genComp) {
388 mSyncGen.push_back(genComp);
389 }
390
391 auto swComp = std::dynamic_pointer_cast<CPS::MNASwitchInterface>(comp);
392 if (swComp) {
393 mSwitches.push_back(swComp);
394 auto mnaComp = std::dynamic_pointer_cast<CPS::MNAInterface>(swComp);
395 if (mnaComp)
396 mMNAIntfSwitches.push_back(mnaComp);
397 }
398
399 auto varComp =
400 std::dynamic_pointer_cast<CPS::MNAVariableCompInterface>(comp);
401 if (varComp) {
402 mVariableComps.push_back(varComp);
403 auto mnaComp = std::dynamic_pointer_cast<CPS::MNAInterface>(varComp);
404 if (mnaComp)
405 mMNAIntfVariableComps.push_back(mnaComp);
406 }
407
408 if (!(swComp || varComp)) {
409 auto mnaComp = std::dynamic_pointer_cast<CPS::MNAInterface>(comp);
410 if (mnaComp)
411 mMNAComponents.push_back(mnaComp);
412
413 auto sigComp = std::dynamic_pointer_cast<CPS::SimSignalComp>(comp);
414 if (sigComp)
415 mSimSignalComps.push_back(sigComp);
416 }
417 }
418}
419
420template <typename VarType> void MnaSolver<VarType>::assignMatrixNodeIndices() {
421 UInt matrixNodeIndexIdx = 0;
422 for (UInt idx = 0; idx < mNodes.size(); ++idx) {
423 mNodes[idx]->setMatrixNodeIndex(0, matrixNodeIndexIdx);
424 SPDLOG_LOGGER_INFO(mSLog, "Assigned index {} to phase A of node {}",
425 matrixNodeIndexIdx, idx);
426 ++matrixNodeIndexIdx;
427 if (mNodes[idx]->phaseType() == CPS::PhaseType::ABC) {
428 mNodes[idx]->setMatrixNodeIndex(1, matrixNodeIndexIdx);
429 SPDLOG_LOGGER_INFO(mSLog, "Assigned index {} to phase B of node {}",
430 matrixNodeIndexIdx, idx);
431 ++matrixNodeIndexIdx;
432 mNodes[idx]->setMatrixNodeIndex(2, matrixNodeIndexIdx);
433 SPDLOG_LOGGER_INFO(mSLog, "Assigned index {} to phase C of node {}",
434 matrixNodeIndexIdx, idx);
435 ++matrixNodeIndexIdx;
436 }
437 // This should be true when the final network node is reached, not considering virtual nodes
438 if (idx == mNumNetNodes - 1)
439 mNumNetMatrixNodeIndices = matrixNodeIndexIdx;
440 }
441 // Total number of network nodes including virtual nodes is matrixNodeIndexIdx + 1, which is why the variable is incremented after assignment
442 mNumMatrixNodeIndices = matrixNodeIndexIdx;
446 static_cast<UInt>(mSystem.mFrequencies.size() - 1) *
449 static_cast<UInt>(mSystem.mFrequencies.size()) * mNumMatrixNodeIndices;
450
451 SPDLOG_LOGGER_INFO(mSLog, "Assigned simulation nodes to topology nodes:");
452 SPDLOG_LOGGER_INFO(mSLog, "Number of network simulation nodes: {:d}",
454 SPDLOG_LOGGER_INFO(mSLog, "Number of simulation nodes: {:d}",
456 SPDLOG_LOGGER_INFO(mSLog, "Number of harmonic simulation nodes: {:d}",
458}
459
460template <> void MnaSolver<Real>::createEmptyVectors() {
461 mRightSideVector = Matrix::Zero(mNumMatrixNodeIndices, 1);
462 **mLeftSideVector = Matrix::Zero(mNumMatrixNodeIndices, 1);
463}
464
466 if (mFrequencyParallel) {
467 for (Int freq = 0; freq < mSystem.mFrequencies.size(); ++freq) {
468 mRightSideVectorHarm.push_back(
469 Matrix::Zero(2 * (mNumMatrixNodeIndices), 1));
470 mLeftSideVectorHarm.push_back(AttributeStatic<Matrix>::make(
471 Matrix::Zero(2 * (mNumMatrixNodeIndices), 1)));
472 }
473 } else {
474 mRightSideVector = Matrix::Zero(
475 2 * (mNumMatrixNodeIndices + mNumHarmMatrixNodeIndices), 1);
476 **mLeftSideVector = Matrix::Zero(
477 2 * (mNumMatrixNodeIndices + mNumHarmMatrixNodeIndices), 1);
478 }
479}
480
481template <typename VarType> void MnaSolver<VarType>::collectVirtualNodes() {
482 // We have not added virtual nodes yet so the list has only network nodes
483 mNumNetNodes = (UInt)mNodes.size();
484 // virtual nodes are placed after network nodes
485 UInt virtualNode = mNumNetNodes - 1;
486
487 for (auto comp : mMNAComponents) {
488 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
489 if (!pComp)
490 continue;
491
492 // Check if component requires virtual node and if so get a reference
493 if (pComp->hasVirtualNodes()) {
494 for (UInt node = 0; node < pComp->virtualNodesNumber(); ++node) {
495 mNodes.push_back(pComp->virtualNode(node));
496 SPDLOG_LOGGER_INFO(mSLog, "Collected virtual node {} of {}",
497 virtualNode, node, pComp->name());
498 }
499 }
500
501 // Repeat the same steps for virtual nodes of sub components
502 // TODO: recursive behavior
503 if (pComp->hasSubComponents()) {
504 for (auto pSubComp : pComp->subComponents()) {
505 for (UInt node = 0; node < pSubComp->virtualNodesNumber(); ++node) {
506 mNodes.push_back(pSubComp->virtualNode(node));
507 SPDLOG_LOGGER_INFO(mSLog, "Collected virtual node {} of {}",
508 virtualNode, node, pComp->name());
509 }
510 }
511 }
512 }
513
514 // collect virtual nodes of variable components
515 for (auto comp : mVariableComps) {
516 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
517 if (!pComp)
518 continue;
519
520 // Check if component requires virtual node and if so get a reference
521 if (pComp->hasVirtualNodes()) {
522 for (UInt node = 0; node < pComp->virtualNodesNumber(); ++node) {
523 mNodes.push_back(pComp->virtualNode(node));
524 SPDLOG_LOGGER_INFO(mSLog,
525 "Collected virtual node {} of Varible Comp {}", node,
526 pComp->name());
527 }
528 }
529 }
530
531 // Update node number to create matrices and vectors
532 mNumNodes = (UInt)mNodes.size();
534 SPDLOG_LOGGER_INFO(mSLog, "Created virtual nodes:");
535 SPDLOG_LOGGER_INFO(mSLog, "Number of network nodes: {:d}", mNumNetNodes);
536 SPDLOG_LOGGER_INFO(mSLog, "Number of network and virtual nodes: {:d}",
537 mNumNodes);
538}
539
540template <typename VarType>
541void MnaSolver<VarType>::steadyStateInitialization() {
542 SPDLOG_LOGGER_INFO(mSLog, "--- Run steady-state initialization ---");
543
544 DataLogger initLeftVectorLog(mName + "_InitLeftVector",
545 mLogLevel != CPS::Logger::Level::off);
546 initLeftVectorLog.start();
547 DataLogger initRightVectorLog(mName + "_InitRightVector",
548 mLogLevel != CPS::Logger::Level::off);
549 initRightVectorLog.start();
550
551 TopologicalPowerComp::Behaviour initBehaviourPowerComps =
552 TopologicalPowerComp::Behaviour::Initialization;
553 SimSignalComp::Behaviour initBehaviourSignalComps =
554 SimSignalComp::Behaviour::Initialization;
555
556 // TODO: enable use of timestep distinct from simulation timestep
557 Real initTimeStep = mTimeStep;
558
559 Int timeStepCount = 0;
560 Real time = 0;
561 Real maxDiff = 1.0;
562 Real max = 1.0;
563 Matrix diff = Matrix::Zero(2 * mNumNodes, 1);
564 Matrix prevLeftSideVector = Matrix::Zero(2 * mNumNodes, 1);
565
566 SPDLOG_LOGGER_INFO(mSLog,
567 "Time step is {:f}s for steady-state initialization",
568 initTimeStep);
569
570 for (auto comp : mSystem.mComponents) {
571 auto powerComp = std::dynamic_pointer_cast<CPS::TopologicalPowerComp>(comp);
572 if (powerComp)
573 powerComp->setBehaviour(initBehaviourPowerComps);
574
575 auto sigComp = std::dynamic_pointer_cast<CPS::SimSignalComp>(comp);
576 if (sigComp)
577 sigComp->setBehaviour(initBehaviourSignalComps);
578 }
579
580 initializeSystem();
581 logSystemMatrices();
582
583 // Use sequential scheduler
585 CPS::Task::List tasks;
586 Scheduler::Edges inEdges, outEdges;
587
588 for (auto node : mNodes) {
589 for (auto task : node->mnaTasks())
590 tasks.push_back(task);
591 }
592 for (auto comp : mMNAComponents) {
593 for (auto task : comp->mnaTasks()) {
594 tasks.push_back(task);
595 }
596 }
597 // TODO signal components should be moved out of MNA solver
598 for (auto comp : mSimSignalComps) {
599 for (auto task : comp->getTasks()) {
600 tasks.push_back(task);
601 }
602 }
603 tasks.push_back(createSolveTask());
604
605 sched.resolveDeps(tasks, inEdges, outEdges);
606 sched.createSchedule(tasks, inEdges, outEdges);
607
608 while (time < mSteadStIniTimeLimit) {
609 // Reset source vector
610 mRightSideVector.setZero();
611
612 sched.step(time, timeStepCount);
613
614 if (mDomain == CPS::Domain::EMT) {
615 initLeftVectorLog.logEMTNodeValues(time, leftSideVector());
616 initRightVectorLog.logEMTNodeValues(time, rightSideVector());
617 } else {
618 initLeftVectorLog.logPhasorNodeValues(time, leftSideVector());
619 initRightVectorLog.logPhasorNodeValues(time, rightSideVector());
620 }
621
622 // Calculate new simulation time
623 time = time + initTimeStep;
624 ++timeStepCount;
625
626 // Calculate difference
627 diff = prevLeftSideVector - **mLeftSideVector;
628 prevLeftSideVector = **mLeftSideVector;
629 maxDiff = diff.lpNorm<Eigen::Infinity>();
630 max = (**mLeftSideVector).lpNorm<Eigen::Infinity>();
631 // If difference is smaller than some epsilon, break
632 if ((maxDiff / max) < mSteadStIniAccLimit)
633 break;
634 }
635
636 SPDLOG_LOGGER_INFO(mSLog, "Max difference: {:f} or {:f}% at time {:f}",
637 maxDiff, maxDiff / max, time);
638
639 // Reset system for actual simulation
640 mRightSideVector.setZero();
641
642 SPDLOG_LOGGER_INFO(mSLog, "--- Finished steady-state initialization ---");
643}
644
645template <typename VarType> Task::List MnaSolver<VarType>::getTasks() {
646 Task::List l;
647
648 for (auto comp : mMNAComponents) {
649 for (auto task : comp->mnaTasks()) {
650 l.push_back(task);
651 }
652 }
653 for (auto comp : mMNAIntfSwitches) {
654 for (auto task : comp->mnaTasks()) {
655 l.push_back(task);
656 }
657 }
658 for (auto node : mNodes) {
659 for (auto task : node->mnaTasks())
660 l.push_back(task);
661 }
662 // TODO signal components should be moved out of MNA solver
663 for (auto comp : mSimSignalComps) {
664 for (auto task : comp->getTasks()) {
665 l.push_back(task);
666 }
667 }
668 if (mFrequencyParallel) {
669 for (UInt i = 0; i < mSystem.mFrequencies.size(); ++i)
670 l.push_back(createSolveTaskHarm(i));
671 } else if (mSystemMatrixRecomputation) {
672 for (auto comp : this->mMNAIntfVariableComps) {
673 for (auto task : comp->mnaTasks())
674 l.push_back(task);
675 }
676 l.push_back(createSolveTaskRecomp());
678 l.push_back(createStateSpaceExtractionTask());
679 }
680 } else {
681 l.push_back(createSolveTask());
683 l.push_back(createStateSpaceExtractionTask());
684 }
685 l.push_back(createLogTask());
686 }
687 return l;
688}
689
690template <typename VarType>
691void MnaSolver<VarType>::log(Real time, Int timeStepCount) {
692 if (mLogLevel == Logger::Level::off)
693 return;
694
695 if (mDomain == CPS::Domain::EMT) {
696 mLeftVectorLog->logEMTNodeValues(time, leftSideVector());
697 mRightVectorLog->logEMTNodeValues(time, rightSideVector());
698 } else {
699 mLeftVectorLog->logPhasorNodeValues(time, leftSideVector());
700 mRightVectorLog->logPhasorNodeValues(time, rightSideVector());
701 }
702}
703
704} // namespace DPsim
705
706template class DPsim::MnaSolver<Real>;
707template class DPsim::MnaSolver<Complex>;
Solver class using Modified Nodal Analysis (MNA).
Definition MNASolver.h:39
std::bitset< SWITCH_NUM > mCurrentSwitchStatus
Current status of all switches encoded as bitset.
Definition MNASolver.h:79
CPS::Domain mDomain
Simulation domain, which can be dynamic phasor (DP) or EMT.
Definition MNASolver.h:43
void identifyTopologyObjects()
Identify Nodes and SimPowerComps and SimSignalComps.
std::vector< Matrix > mRightSideVectorHarm
Source vector of known quantities.
Definition MNASolver.h:90
Matrix mRightSideVector
Source vector of known quantities.
Definition MNASolver.h:84
Bool mStateSpaceExtraction
Enables extraction of the MNA-coupled discrete-time state matrix.
Definition MNASolver.h:126
CPS::SystemTopology mSystem
System topology.
Definition MNASolver.h:64
virtual std::shared_ptr< CPS::Task > createStateSpaceExtractionTask()=0
Create state-space extraction task for this solver implementation.
void initializeSystemWithVariableMatrix()
Initialization of system matrices and source vector.
virtual void initialize() override
Calls subroutines to set up everything that is required before simulation.
Definition MNASolver.cpp:52
virtual void logSystemMatrices()=0
Logging of system matrices and source vector.
virtual void initializeSystem()
Initialization of system matrices and source vector.
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 mNumNetMatrixNodeIndices
Number of network nodes, considering individual phases.
Definition MNASolver.h:53
UInt mNumNetNodes
Number of network nodes, single line equivalent.
Definition MNASolver.h:47
virtual void switchedMatrixStamp(std::size_t index, std::vector< std::shared_ptr< CPS::MNAInterface > > &comp)=0
Applies a component stamp to the matrix with the given switch index.
MNAStateSpaceExtractor::Ptr mStateSpaceExtractor
Extractor for the MNA-coupled state-space model.
Definition MNASolver.h:129
virtual void log(Real time, Int timeStepCount) override
Logs left and right vector.
UInt mNumTotalMatrixNodeIndices
Total number of network and virtual nodes, considering individual phases and additional frequencies.
Definition MNASolver.h:59
UInt mNumVirtualMatrixNodeIndices
Number of virtual nodes, considering individual phases.
Definition MNASolver.h:55
CPS::MNASyncGenInterface::List mSyncGen
List of synchronous generators that need iterate to solve the differential equations.
Definition MNASolver.h:81
CPS::MNAInterface::List mMNAIntfSwitches
List of switches if they must be accessed as MNAInterface objects.
Definition MNASolver.h:75
std::shared_ptr< DataLogger > mRightVectorLog
Right side vector logger.
Definition MNASolver.h:115
virtual std::shared_ptr< CPS::Task > createSolveTaskHarm(UInt freqIdx)=0
Create a solve task for this solver implementation.
void initializeComponents()
Initialization of individual components.
void updateSwitchStatus()
Collects the status of switches to select correct system matrix.
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
virtual std::shared_ptr< CPS::Task > createSolveTaskRecomp()=0
Create a solve task for recomputation solver.
CPS::MNAInterface::List mMNAComponents
List of MNA components with static stamp into system matrix.
Definition MNASolver.h:70
virtual void stampVariableSystemMatrix()=0
Stamps components into the variable system matrix.
std::shared_ptr< DataLogger > mLeftVectorLog
Left side vector logger.
Definition MNASolver.h:113
UInt mNumMatrixNodeIndices
Number of network and virtual nodes, considering individual phases.
Definition MNASolver.h:51
void initializeSystemWithParallelFrequencies()
Initialization of system matrices and source vector.
void collectVirtualNodes()
UInt mNumHarmMatrixNodeIndices
Number of nodes, excluding the primary frequency.
Definition MNASolver.h:57
UInt mNumNodes
Number of network and virtual nodes, single line equivalent.
Definition MNASolver.h:45
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
void assignMatrixNodeIndices()
Assign simulation node index according to index in the vector.
UInt mNumVirtualNodes
Number of virtual nodes, single line equivalent.
Definition MNASolver.h:49
void initializeSystemWithPrecomputedMatrices()
Initialization of system matrices and source vector.
CPS::Attribute< Matrix >::Ptr mLeftSideVector
Solution vector of unknown quantities.
Definition MNASolver.h:208
CPS::SimSignalComp::List mSimSignalComps
List of signal type components that do not directly interact with the MNA solver.
Definition MNASolver.h:77
virtual void createEmptySystemMatrix()=0
Create system matrix.
virtual std::shared_ptr< CPS::Task > createLogTask()=0
Create a solve task for this solver implementation.
const MNAStateSpaceExtractor & getStateSpaceExtractor() const
Read-only access to the MNA state-space extractor.
Definition MNASolver.cpp:44
void doStateSpaceExtraction(Bool value=true)
Enable or disable MNA state-space extraction.
Definition MNASolver.cpp:38
CPS::MNASwitchInterface::List mSwitches
Definition MNASolver.h:73
void createEmptyVectors()
Create left and right side vector.
virtual void switchedMatrixEmpty(std::size_t index)=0
Sets all entries in the matrix with the given switch index to zero.
virtual std::shared_ptr< CPS::Task > createSolveTask()=0
Create a solve task for this solver implementation.
CPS::SimNode< VarType >::List mNodes
List of simulation nodes.
Definition MNASolver.h:66
void initializeStateSpaceExtractor()
Initialization of state-space extraction.
virtual CPS::Task::List getTasks() override
Get tasks for scheduler.
void resolveDeps(CPS::Task::List &tasks, Edges &inEdges, Edges &outEdges)
Definition Scheduler.cpp:78
std::unordered_map< CPS::Task::Ptr, std::deque< CPS::Task::Ptr > > Edges
Definition Scheduler.h:31
void step(Real time, Int timeStepCount)
Performs a single simulation step.
void createSchedule(const CPS::Task::List &tasks, const Edges &inEdges, const Edges &outEdges)
Creates the schedule for the given dependency graph.
Real mTimeStep
Time step for fixed step solvers.
Definition Solver.h:47
Bool mSystemMatrixRecomputation
Enable recomputation of system matrix during simulation.
Definition Solver.h:64
CPS::Logger::Log mSLog
Logger.
Definition Solver.h:45
CPS::Logger::Level mLogLevel
Logging level.
Definition Solver.h:41
Bool mIsInInitialization
Determines if solver is in initialization phase, which requires different behavior.
Definition Solver.h:59
Bool mFrequencyParallel
Activates parallelized computation of frequencies.
Definition Solver.h:49
Bool mSteadyStateInit
Activates steady state initialization.
Definition Solver.h:57