9#include <dpsim/MNASolver.h>
10#include <dpsim/SequentialScheduler.h>
18template <
typename VarType>
20 CPS::Logger::Level logLevel)
21 : Solver(name, logLevel),
mDomain(domain) {
25 name +
"_LeftVector", logLevel == CPS::Logger::Level::trace);
27 name +
"_RightVector", logLevel == CPS::Logger::Level::trace);
30template <
typename VarType>
37 SPDLOG_LOGGER_INFO(
mSLog,
"---- Start initialization ----");
45 SPDLOG_LOGGER_INFO(
mSLog,
"Computing network harmonics in parallel.");
46 for (Int freq = 0; freq <
mSystem.mFrequencies.size(); ++freq) {
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(),
59 if (
mSystem.mComponents.size() == 0)
69 SPDLOG_LOGGER_INFO(
mSLog,
"-- Create empty MNA system matrices and vectors");
79 steadyStateInitialization();
84 for (
auto comp :
mSystem.mComponents) {
85 auto powerComp = std::dynamic_pointer_cast<CPS::TopologicalPowerComp>(comp);
87 powerComp->setBehaviour(TopologicalPowerComp::Behaviour::MNASimulation);
89 auto sigComp = std::dynamic_pointer_cast<CPS::SimSignalComp>(comp);
91 sigComp->setBehaviour(SimSignalComp::Behaviour::Simulation);
97 SPDLOG_LOGGER_INFO(
mSLog,
"--- Initialization finished ---");
98 SPDLOG_LOGGER_INFO(
mSLog,
"--- Initial system matrices and vectors ---");
105 SPDLOG_LOGGER_INFO(mSLog,
"-- Initialize components from power flow");
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());
113 for (
auto comp : allMNAComps) {
114 auto pComp = std::dynamic_pointer_cast<SimPowerComp<Real>>(comp);
117 pComp->checkForUnconnectedTerminals();
118 if (mInitFromNodesAndTerminals)
119 pComp->initializeFromNodesAndTerminals(mSystem.mSystemFrequency);
123 for (
auto comp : mSimSignalComps)
124 comp->initialize(mSystem.mSystemOmega, mTimeStep);
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);
135 for (
auto comp : mMNAIntfSwitches)
136 comp->mnaInitialize(mSystem.mSystemOmega, mTimeStep, mLeftSideVector);
139 for (UInt nodeIdx = 0; nodeIdx < mNodes.size(); ++nodeIdx)
140 mNodes[nodeIdx]->initialize();
144 SPDLOG_LOGGER_INFO(mSLog,
"-- Initialize components from power flow");
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());
153 for (
auto comp : allMNAComps) {
154 auto pComp = std::dynamic_pointer_cast<SimPowerComp<Complex>>(comp);
157 pComp->checkForUnconnectedTerminals();
158 if (mInitFromNodesAndTerminals)
159 pComp->initializeFromNodesAndTerminals(mSystem.mSystemFrequency);
163 for (
auto comp : mSimSignalComps)
164 comp->initialize(mSystem.mSystemOmega, mTimeStep);
166 SPDLOG_LOGGER_INFO(mSLog,
"-- Initialize MNA properties of components");
167 if (mFrequencyParallel) {
169 for (
auto comp : mMNAComponents) {
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);
178 for (UInt nodeIdx = 0; nodeIdx < mNodes.size(); ++nodeIdx) {
179 mNodes[nodeIdx]->mnaInitializeHarm(mLeftSideVectorHarm);
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);
191 for (
auto comp : mMNAIntfSwitches)
192 comp->mnaInitialize(mSystem.mSystemOmega, mTimeStep, mLeftSideVector);
195 for (UInt nodeIdx = 0; nodeIdx < mNodes.size(); ++nodeIdx)
196 mNodes[nodeIdx]->initialize();
201 SPDLOG_LOGGER_INFO(
mSLog,
202 "-- Initialize MNA system matrices and source vector");
207 if (
mSwitches.size() >
sizeof(std::size_t) * 8) {
219template <
typename VarType>
222 for (std::size_t sw = 0; sw < (1ULL <<
mSwitches.size()); ++sw) {
223 for (Int freq = 0; freq <
mSystem.mFrequencies.size(); ++freq) {
233 for (Int freq = 0; freq <
mSystem.mFrequencies.size(); ++freq) {
239template <
typename VarType>
242 for (std::size_t i = 0; i < (1ULL <<
mSwitches.size()); i++) {
250 for (std::size_t i = 0; i < (1ULL <<
mSwitches.size()); i++) {
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))
270template <
typename VarType>
275 for (
auto varEntry : varElem->mVariableSystemMatrixEntries)
277 SPDLOG_LOGGER_INFO(
mSLog,
"List of index pairs of varying matrix entries: ");
279 SPDLOG_LOGGER_INFO(
mSLog,
"({}, {})", indexPair.first, indexPair.second);
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))
297template <
typename VarType>
300 if (varElem->hasParameterChanged()) {
301 auto idObj = std::dynamic_pointer_cast<IdentifiedObject>(varElem);
303 mSLog,
"Component ({:s} {:s}) value changed -> Update System Matrix",
304 idObj->type(), idObj->name());
312 for (UInt i = 0; i <
mSwitches.size(); ++i) {
318 for (
auto baseNode :
mSystem.mNodes) {
320 if (!baseNode->isGround()) {
321 auto node = std::dynamic_pointer_cast<CPS::SimNode<VarType>>(baseNode);
323 SPDLOG_LOGGER_INFO(
mSLog,
"Added node {:s}", node->name());
327 for (
auto comp :
mSystem.mComponents) {
329 auto genComp = std::dynamic_pointer_cast<CPS::MNASyncGenInterface>(comp);
334 auto swComp = std::dynamic_pointer_cast<CPS::MNASwitchInterface>(comp);
337 auto mnaComp = std::dynamic_pointer_cast<CPS::MNAInterface>(swComp);
343 std::dynamic_pointer_cast<CPS::MNAVariableCompInterface>(comp);
346 auto mnaComp = std::dynamic_pointer_cast<CPS::MNAInterface>(varComp);
351 if (!(swComp || varComp)) {
352 auto mnaComp = std::dynamic_pointer_cast<CPS::MNAInterface>(comp);
356 auto sigComp = std::dynamic_pointer_cast<CPS::SimSignalComp>(comp);
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;
389 static_cast<UInt
>(
mSystem.mFrequencies.size() - 1) *
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}",
404 mRightSideVector = Matrix::Zero(mNumMatrixNodeIndices, 1);
405 **mLeftSideVector = Matrix::Zero(mNumMatrixNodeIndices, 1);
409 if (mFrequencyParallel) {
410 for (Int freq = 0; freq < mSystem.mFrequencies.size(); ++freq) {
411 mRightSideVectorHarm.push_back(
412 Matrix::Zero(2 * (mNumMatrixNodeIndices), 1));
414 Matrix::Zero(2 * (mNumMatrixNodeIndices), 1)));
417 mRightSideVector = Matrix::Zero(
418 2 * (mNumMatrixNodeIndices + mNumHarmMatrixNodeIndices), 1);
419 **mLeftSideVector = Matrix::Zero(
420 2 * (mNumMatrixNodeIndices + mNumHarmMatrixNodeIndices), 1);
431 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
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());
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());
459 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
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,
477 SPDLOG_LOGGER_INFO(
mSLog,
"Created virtual nodes:");
479 SPDLOG_LOGGER_INFO(
mSLog,
"Number of network and virtual nodes: {:d}",
483template <
typename VarType>
484void MnaSolver<VarType>::steadyStateInitialization() {
485 SPDLOG_LOGGER_INFO(mSLog,
"--- Run steady-state initialization ---");
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();
494 TopologicalPowerComp::Behaviour initBehaviourPowerComps =
495 TopologicalPowerComp::Behaviour::Initialization;
496 SimSignalComp::Behaviour initBehaviourSignalComps =
497 SimSignalComp::Behaviour::Initialization;
500 Real initTimeStep = mTimeStep;
502 Int timeStepCount = 0;
506 Matrix diff = Matrix::Zero(2 * mNumNodes, 1);
507 Matrix prevLeftSideVector = Matrix::Zero(2 * mNumNodes, 1);
509 SPDLOG_LOGGER_INFO(mSLog,
510 "Time step is {:f}s for steady-state initialization",
513 for (
auto comp : mSystem.mComponents) {
514 auto powerComp = std::dynamic_pointer_cast<CPS::TopologicalPowerComp>(comp);
516 powerComp->setBehaviour(initBehaviourPowerComps);
518 auto sigComp = std::dynamic_pointer_cast<CPS::SimSignalComp>(comp);
520 sigComp->setBehaviour(initBehaviourSignalComps);
528 CPS::Task::List tasks;
531 for (
auto node : mNodes) {
532 for (
auto task : node->mnaTasks())
533 tasks.push_back(task);
535 for (
auto comp : mMNAComponents) {
536 for (
auto task : comp->mnaTasks()) {
537 tasks.push_back(task);
541 for (
auto comp : mSimSignalComps) {
542 for (
auto task : comp->getTasks()) {
543 tasks.push_back(task);
546 tasks.push_back(createSolveTask());
551 while (time < mSteadStIniTimeLimit) {
553 mRightSideVector.setZero();
555 sched.
step(time, timeStepCount);
557 if (mDomain == CPS::Domain::EMT) {
558 initLeftVectorLog.logEMTNodeValues(time, leftSideVector());
559 initRightVectorLog.logEMTNodeValues(time, rightSideVector());
561 initLeftVectorLog.logPhasorNodeValues(time, leftSideVector());
562 initRightVectorLog.logPhasorNodeValues(time, rightSideVector());
566 time = time + initTimeStep;
570 diff = prevLeftSideVector - **mLeftSideVector;
571 prevLeftSideVector = **mLeftSideVector;
572 maxDiff = diff.lpNorm<Eigen::Infinity>();
573 max = (**mLeftSideVector).lpNorm<Eigen::Infinity>();
575 if ((maxDiff / max) < mSteadStIniAccLimit)
579 SPDLOG_LOGGER_INFO(mSLog,
"Max difference: {:f} or {:f}% at time {:f}",
580 maxDiff, maxDiff / max, time);
583 mRightSideVector.setZero();
585 SPDLOG_LOGGER_INFO(mSLog,
"--- Finished steady-state initialization ---");
592 for (
auto task : comp->mnaTasks()) {
597 for (
auto task : comp->mnaTasks()) {
601 for (
auto node :
mNodes) {
602 for (
auto task : node->mnaTasks())
607 for (
auto task : comp->getTasks()) {
612 for (UInt i = 0; i <
mSystem.mFrequencies.size(); ++i)
616 for (
auto task : comp->mnaTasks())
627template <
typename VarType>
632 if (
mDomain == CPS::Domain::EMT) {
Solver class using Modified Nodal Analysis (MNA).
std::bitset< SWITCH_NUM > mCurrentSwitchStatus
Current status of all switches encoded as bitset.
CPS::Domain mDomain
Simulation domain, which can be dynamic phasor (DP) or EMT.
void identifyTopologyObjects()
Identify Nodes and SimPowerComps and SimSignalComps.
std::vector< Matrix > mRightSideVectorHarm
Source vector of known quantities.
Matrix mRightSideVector
Source vector of known quantities.
CPS::SystemTopology mSystem
System topology.
void initializeSystemWithVariableMatrix()
Initialization of system matrices and source vector.
virtual void initialize() override
Calls subroutines to set up everything that is required before simulation.
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)
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.
UInt mNumNetMatrixNodeIndices
Number of network nodes, considering individual phases.
UInt mNumNetNodes
Number of network nodes, single line equivalent.
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.
UInt mNumVirtualMatrixNodeIndices
Number of virtual nodes, considering individual phases.
CPS::MNASyncGenInterface::List mSyncGen
List of synchronous generators that need iterate to solve the differential equations.
CPS::MNAInterface::List mMNAIntfSwitches
List of switches if they must be accessed as MNAInterface objects.
std::shared_ptr< DataLogger > mRightVectorLog
Right side vector logger.
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.
CPS::MNAVariableCompInterface::List mVariableComps
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.
virtual void stampVariableSystemMatrix()=0
Stamps components into the variable system matrix.
std::shared_ptr< DataLogger > mLeftVectorLog
Left side vector logger.
UInt mNumMatrixNodeIndices
Number of network and virtual nodes, considering individual phases.
void initializeSystemWithParallelFrequencies()
Initialization of system matrices and source vector.
void collectVirtualNodes()
UInt mNumHarmMatrixNodeIndices
Number of nodes, excluding the primary frequency.
UInt mNumNodes
Number of network and virtual nodes, single line equivalent.
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.
void assignMatrixNodeIndices()
Assign simulation node index according to index in the vector.
UInt mNumVirtualNodes
Number of virtual nodes, single line equivalent.
void initializeSystemWithPrecomputedMatrices()
Initialization of system matrices and source vector.
CPS::Attribute< Matrix >::Ptr mLeftSideVector
Solution vector of unknown quantities.
CPS::SimSignalComp::List mSimSignalComps
List of signal type components that do not directly interact with the MNA solver.
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
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.
virtual CPS::Task::List getTasks() override
Get tasks for scheduler.
void resolveDeps(CPS::Task::List &tasks, Edges &inEdges, Edges &outEdges)
std::unordered_map< CPS::Task::Ptr, std::deque< CPS::Task::Ptr > > Edges
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.
CPS::Logger::Log mSLog
Logger.
CPS::Logger::Level mLogLevel
Logging level.
Bool mIsInInitialization
Determines if solver is in initialization phase, which requires different behavior.
Bool mFrequencyParallel
Activates parallelized computation of frequencies.
Bool mSteadyStateInit
Activates steady state initialization.