22template <
typename VarType>
29 name +
"_LeftVector", logLevel == CPS::Logger::Level::trace);
31 name +
"_RightVector", logLevel == CPS::Logger::Level::trace);
34template <
typename VarType>
39template <
typename VarType>
44template <
typename VarType>
48 throw std::logic_error(
49 "MNA state-space extractor has not been initialized.");
56 SPDLOG_LOGGER_INFO(
mSLog,
"---- Start initialization ----");
64 SPDLOG_LOGGER_INFO(
mSLog,
"Computing network harmonics in parallel.");
65 for (
Int freq = 0; freq <
mSystem.mFrequencies.size(); ++freq) {
72 SPDLOG_LOGGER_INFO(
mSLog,
"-- Process topology");
73 for (
auto comp :
mSystem.mComponents)
74 SPDLOG_LOGGER_INFO(
mSLog,
"Added {:s} '{:s}' to simulation.", comp->type(),
78 if (
mSystem.mComponents.size() == 0)
88 "frequency-parallel MNA.");
114 std::dynamic_pointer_cast<CPS::SimPowerComp<VarType>>(comp);
116 pComp ? pComp->subComponents()
119 comp->createSubComponents();
122 for (
auto subComp : pComp->subComponents()) {
123 bool isNew = std::find(subCompsBefore.begin(), subCompsBefore.end(),
124 subComp) == subCompsBefore.end();
128 std::dynamic_pointer_cast<CPS::MNAInterface>(subComp))
129 createSubComponentsRec(subMna);
133 for (
auto comp : allMNAComps)
134 createSubComponentsRec(comp);
139 SPDLOG_LOGGER_INFO(
mSLog,
"-- Create empty MNA system matrices and vectors");
154 for (
auto comp :
mSystem.mComponents) {
155 auto powerComp = std::dynamic_pointer_cast<CPS::TopologicalPowerComp>(comp);
159 auto sigComp = std::dynamic_pointer_cast<CPS::SimSignalComp>(comp);
170 SPDLOG_LOGGER_INFO(
mSLog,
"--- Initialization finished ---");
171 SPDLOG_LOGGER_INFO(
mSLog,
"--- Initial system matrices and vectors ---");
178 SPDLOG_LOGGER_INFO(
mSLog,
"-- Initialize components from power flow");
186 for (
auto comp : allMNAComps) {
187 auto pComp = std::dynamic_pointer_cast<SimPowerComp<Real>>(comp);
190 pComp->checkForUnconnectedTerminals();
192 pComp->initializeFromNodesAndTerminals(
mSystem.mSystemFrequency);
200 for (
auto comp : allMNAComps) {
202 const Matrix &stamp = comp->getRightVector()->get();
203 if (stamp.size() != 0) {
212 for (
UInt nodeIdx = 0; nodeIdx <
mNodes.size(); ++nodeIdx)
217 SPDLOG_LOGGER_INFO(
mSLog,
"-- Initialize components from power flow");
226 for (
auto comp : allMNAComps) {
227 auto pComp = std::dynamic_pointer_cast<SimPowerComp<Complex>>(comp);
230 pComp->checkForUnconnectedTerminals();
232 pComp->initializeFromNodesAndTerminals(
mSystem.mSystemFrequency);
239 SPDLOG_LOGGER_INFO(
mSLog,
"-- Initialize MNA properties of components");
246 const Matrix &stamp = comp->getRightVector()->get();
247 if (stamp.size() != 0)
251 for (
UInt nodeIdx = 0; nodeIdx <
mNodes.size(); ++nodeIdx) {
256 for (
auto comp : allMNAComps) {
258 const Matrix &stamp = comp->getRightVector()->get();
259 if (stamp.size() != 0) {
268 for (
UInt nodeIdx = 0; nodeIdx <
mNodes.size(); ++nodeIdx)
274 SPDLOG_LOGGER_INFO(
mSLog,
275 "-- Initialize MNA system matrices and source vector");
280 if (
mSwitches.size() >
sizeof(std::size_t) * 8) {
292template <
typename VarType>
295 for (std::size_t sw = 0; sw < (1ULL <<
mSwitches.size()); ++sw) {
296 for (
Int freq = 0; freq <
mSystem.mFrequencies.size(); ++freq) {
306 for (
Int freq = 0; freq <
mSystem.mFrequencies.size(); ++freq) {
312template <
typename VarType>
315 for (std::size_t i = 0; i < (1ULL <<
mSwitches.size()); i++) {
323 for (std::size_t i = 0; i < (1ULL <<
mSwitches.size()); i++) {
335 auto idObj = std::dynamic_pointer_cast<IdentifiedObject>(comp);
336 SPDLOG_LOGGER_DEBUG(
mSLog,
"Stamping {:s} {:s} into source vector",
337 idObj->type(), idObj->name());
338 if (
mSLog->should_log(spdlog::level::trace))
343template <
typename VarType>
348 for (
auto varEntry : varElem->mVariableSystemMatrixEntries)
350 SPDLOG_LOGGER_INFO(
mSLog,
"List of index pairs of varying matrix entries: ");
352 SPDLOG_LOGGER_INFO(
mSLog,
"({}, {})", indexPair.first, indexPair.second);
362 auto idObj = std::dynamic_pointer_cast<IdentifiedObject>(comp);
363 SPDLOG_LOGGER_DEBUG(
mSLog,
"Stamping {:s} {:s} into source vector",
364 idObj->type(), idObj->name());
365 if (
mSLog->should_log(spdlog::level::trace))
370template <
typename VarType>
373 throw std::logic_error(
374 "MNA state-space extraction supports EMT and DP domains only.");
378 throw std::logic_error(
379 "MNA state-space extraction does not support frequency-parallel "
384 stateSpaceComponents.insert(stateSpaceComponents.end(),
386 stateSpaceComponents.insert(stateSpaceComponents.end(),
390 const UInt mnaVectorSize =
static_cast<UInt>((**mLeftSideVector).rows());
398 "Initialized MNA state-space extractor with {:d} extraction states.",
402template <
typename VarType>
405 if (varElem->hasParameterChanged()) {
406 auto idObj = std::dynamic_pointer_cast<IdentifiedObject>(varElem);
408 mSLog,
"Component ({:s} {:s}) value changed -> Update System Matrix",
409 idObj->type(), idObj->name());
422template <
typename VarType>
426 const auto recomputationComp = std::find_if(
428 const auto switchComp =
429 std::dynamic_pointer_cast<CPS::MNASwitchInterface>(comp);
431 return !switchComp || !switchComp->supportsPrecomputedSystemMatrices();
440 if (hasRecomputationComp) {
441 const auto component =
442 std::dynamic_pointer_cast<CPS::IdentifiedObject>(*recomputationComp);
446 "System-matrix recomputation enabled automatically for {:s} '{:s}'.",
447 component->type(), component->name());
449 SPDLOG_LOGGER_INFO(
mSLog,
450 "System-matrix recomputation disabled automatically.");
456 SPDLOG_LOGGER_INFO(
mSLog,
"System-matrix recomputation enabled.");
462 if (hasRecomputationComp) {
463 const auto component =
464 std::dynamic_pointer_cast<CPS::IdentifiedObject>(*recomputationComp);
468 "System-matrix recomputation disabled, but {:s} '{:s}' may require "
470 component->type(), component->name());
472 SPDLOG_LOGGER_INFO(
mSLog,
"System-matrix recomputation disabled.");
479 for (
auto baseNode :
mSystem.mNodes) {
481 if (!baseNode->isGround()) {
482 auto node = std::dynamic_pointer_cast<CPS::SimNode<VarType>>(baseNode);
484 SPDLOG_LOGGER_INFO(
mSLog,
"Added node {:s}", node->name());
488 for (
auto comp :
mSystem.mComponents) {
490 auto genComp = std::dynamic_pointer_cast<CPS::MNASyncGenInterface>(comp);
495 auto swComp = std::dynamic_pointer_cast<CPS::MNASwitchInterface>(comp);
498 auto mnaComp = std::dynamic_pointer_cast<CPS::MNAInterface>(swComp);
504 std::dynamic_pointer_cast<CPS::MNAVariableCompInterface>(comp);
507 auto mnaComp = std::dynamic_pointer_cast<CPS::MNAInterface>(varComp);
512 if (!(swComp || varComp)) {
513 auto mnaComp = std::dynamic_pointer_cast<CPS::MNAInterface>(comp);
517 auto sigComp = std::dynamic_pointer_cast<CPS::SimSignalComp>(comp);
525 UInt matrixNodeIndexIdx = 0;
526 for (
UInt idx = 0; idx <
mNodes.size(); ++idx) {
527 mNodes[idx]->setMatrixNodeIndex(0, matrixNodeIndexIdx);
529 SPDLOG_LOGGER_INFO(
mSLog,
"Assigned index {} to DC node {}",
530 matrixNodeIndexIdx, idx);
532 SPDLOG_LOGGER_INFO(
mSLog,
"Assigned index {} to phase A of node {}",
533 matrixNodeIndexIdx, idx);
534 ++matrixNodeIndexIdx;
536 mNodes[idx]->setMatrixNodeIndex(1, matrixNodeIndexIdx);
537 SPDLOG_LOGGER_INFO(
mSLog,
"Assigned index {} to phase B of node {}",
538 matrixNodeIndexIdx, idx);
539 ++matrixNodeIndexIdx;
540 mNodes[idx]->setMatrixNodeIndex(2, matrixNodeIndexIdx);
541 SPDLOG_LOGGER_INFO(
mSLog,
"Assigned index {} to phase C of node {}",
542 matrixNodeIndexIdx, idx);
543 ++matrixNodeIndexIdx;
554 static_cast<UInt>(
mSystem.mFrequencies.size() - 1) *
559 SPDLOG_LOGGER_INFO(
mSLog,
"Assigned simulation nodes to topology nodes:");
560 SPDLOG_LOGGER_INFO(
mSLog,
"Number of network simulation nodes: {:d}",
562 SPDLOG_LOGGER_INFO(
mSLog,
"Number of simulation nodes: {:d}",
564 SPDLOG_LOGGER_INFO(
mSLog,
"Number of harmonic simulation nodes: {:d}",
575 for (
Int freq = 0; freq <
mSystem.mFrequencies.size(); ++freq) {
596 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
601 if (pComp->hasVirtualNodes()) {
602 for (
UInt node = 0; node < pComp->virtualNodesNumber(); ++node) {
603 mNodes.push_back(pComp->virtualNode(node));
604 SPDLOG_LOGGER_INFO(
mSLog,
"Collected virtual node {} of {}",
605 virtualNode, node, pComp->name());
611 if (pComp->hasSubComponents()) {
612 for (
auto pSubComp : pComp->subComponents()) {
613 for (
UInt node = 0; node < pSubComp->virtualNodesNumber(); ++node) {
614 auto vnode = pSubComp->virtualNode(node);
617 bool alreadyRegistered =
false;
618 for (
auto registeredNode :
mNodes) {
619 if (registeredNode == vnode) {
620 alreadyRegistered =
true;
624 if (alreadyRegistered)
627 SPDLOG_LOGGER_INFO(
mSLog,
"Collected virtual node {} of {}", node,
636 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
641 if (pComp->hasVirtualNodes()) {
642 for (
UInt node = 0; node < pComp->virtualNodesNumber(); ++node) {
643 mNodes.push_back(pComp->virtualNode(node));
644 SPDLOG_LOGGER_INFO(
mSLog,
645 "Collected virtual node {} of Varible Comp {}", node,
654 SPDLOG_LOGGER_INFO(
mSLog,
"Created virtual nodes:");
656 SPDLOG_LOGGER_INFO(
mSLog,
"Number of network and virtual nodes: {:d}",
660template <
typename VarType>
662 SPDLOG_LOGGER_INFO(
mSLog,
"--- Run steady-state initialization ---");
666 initLeftVectorLog.
start();
669 initRightVectorLog.
start();
679 Int timeStepCount = 0;
686 SPDLOG_LOGGER_INFO(
mSLog,
687 "Time step is {:f}s for steady-state initialization",
690 for (
auto comp :
mSystem.mComponents) {
691 auto powerComp = std::dynamic_pointer_cast<CPS::TopologicalPowerComp>(comp);
693 powerComp->setBehaviour(initBehaviourPowerComps);
695 auto sigComp = std::dynamic_pointer_cast<CPS::SimSignalComp>(comp);
697 sigComp->setBehaviour(initBehaviourSignalComps);
708 for (
auto node :
mNodes) {
709 for (
auto task : node->mnaTasks())
710 tasks.push_back(task);
713 for (
auto task : comp->mnaTasks()) {
714 tasks.push_back(task);
719 for (
auto task : comp->getTasks()) {
720 tasks.push_back(task);
732 sched.
step(time, timeStepCount);
743 time = time + initTimeStep;
749 maxDiff = diff.lpNorm<Eigen::Infinity>();
750 max = (**mLeftSideVector).lpNorm<Eigen::Infinity>();
756 SPDLOG_LOGGER_INFO(
mSLog,
"Max difference: {:f} or {:f}% at time {:f}",
757 maxDiff, maxDiff / max, time);
762 SPDLOG_LOGGER_INFO(
mSLog,
"--- Finished steady-state initialization ---");
769 for (
auto task : comp->mnaTasks()) {
774 for (
auto task : comp->mnaTasks()) {
778 for (
auto node :
mNodes) {
779 for (
auto task : node->mnaTasks())
784 for (
auto task : comp->getTasks()) {
789 for (
UInt i = 0; i <
mSystem.mFrequencies.size(); ++i)
793 for (
auto task : comp->mnaTasks())
810template <
typename VarType>
spdlog::level::level_enum Level
static String matrixToString(const Matrix &mat)
std::shared_ptr< MNAInterface > Ptr
void logEMTNodeValues(Real time, const Matrix &data)
void logPhasorNodeValues(Real time, const Matrix &data, Int freqNum=1)
virtual void start() override
Solver class using Modified Nodal Analysis (MNA).
std::bitset< SWITCH_NUM > mCurrentSwitchStatus
Current status of all switches encoded as bitset.
virtual void setSystem(const CPS::SystemTopology &system) override
CPS::Domain mDomain
Simulation domain, which can be dynamic phasor (DP) or EMT.
void resolveSystemMatrixRecomputationMode()
Resolve the requested system-matrix recomputation mode.
Matrix & rightSideVector()
void identifyTopologyObjects()
Identify Nodes and SimPowerComps and SimSignalComps.
std::vector< Matrix > mRightSideVectorHarm
Source vector of known quantities.
void steadyStateInitialization()
Matrix mRightSideVector
Source vector of known quantities.
Bool mStateSpaceExtraction
Enables extraction of the MNA-coupled discrete-time state matrix.
CPS::SystemTopology mSystem
System topology.
virtual std::shared_ptr< CPS::Task > createStateSpaceExtractionTask()=0
Create state-space extraction task for this solver implementation.
Matrix & leftSideVector()
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.
MNAStateSpaceExtractor::Ptr mStateSpaceExtractor
Extractor for the MNA-coupled state-space model.
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.
std::vector< const Matrix * > mRightVectorStamps
List of all right side vector contributions.
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.
const MNAStateSpaceExtractor & getStateSpaceExtractor() const
Read-only access to the MNA state-space extractor.
void doStateSpaceExtraction(Bool value=true)
Enable or disable MNA state-space extraction.
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.
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)
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.
String mName
Name for logging.
Real mSteadStIniAccLimit
steady state initialization accuracy limit
Bool mSystemMatrixRecomputationEnabled
Effective system-matrix recomputation setting used by the solver.
Real mTimeStep
Time step for fixed step solvers.
CPS::Logger::Log mSLog
Logger.
CPS::Logger::Level mLogLevel
Logging level.
Bool mIsInInitialization
Determines if solver is in initialization phase, which requires different behavior.
Solver(String name, CPS::Logger::Level logLevel)
Real mSteadStIniTimeLimit
steady state initialization time limit
Bool mInitFromNodesAndTerminals
Bool mFrequencyParallel
Activates parallelized computation of frequencies.
Bool mSteadyStateInit
Activates steady state initialization.
SystemMatrixRecomputationMode mSystemMatrixRecomputationMode
Requested system-matrix recomputation mode.
SystemMatrixRecomputationMode
System-matrix recomputation mode for MNA solvers.