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