9 #include <dpsim/DiakopticsSolver.h>
13 #include <dpsim-models/MathUtils.h>
14 #include <dpsim-models/Solver/MNATearInterface.h>
15 #include <dpsim/Definitions.h>
18 using namespace DPsim;
22 template <
typename VarType>
24 String name,
SystemTopology system, IdentifiedObject::List tearComponents,
25 Real timeStep, Logger::Level logLevel)
32 mLeftVectorLog = std::make_shared<DataLogger>(
33 name +
"_LeftVector", logLevel != CPS::Logger::Level::off);
34 mRightVectorLog = std::make_shared<DataLogger>(
35 name +
"_RightVector", logLevel != CPS::Logger::Level::off);
37 for (
auto comp : tearComponents) {
38 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
40 mTearComponents.push_back(pcomp);
45 template <
typename VarType>
47 std::vector<SystemTopology> subnets;
51 system.splitSubnets<VarType>(subnets);
59 template <
typename VarType>
61 const std::vector<SystemTopology> &subnets) {
62 mSubnets.resize(subnets.size());
63 for (UInt i = 0; i < subnets.size(); ++i) {
65 for (
auto baseNode : subnets[i].mNodes) {
66 if (!baseNode->isGround()) {
67 auto node = std::dynamic_pointer_cast<CPS::SimNode<VarType>>(baseNode);
68 mSubnets[i].nodes.push_back(node);
72 for (
auto comp : subnets[i].mComponents) {
74 auto mnaComp = std::dynamic_pointer_cast<CPS::MNAInterface>(comp);
76 mSubnets[i].components.push_back(mnaComp);
78 auto sigComp = std::dynamic_pointer_cast<CPS::SimSignalComp>(comp);
80 mSimSignalComps.push_back(sigComp);
85 for (
auto &net : mSubnets) {
86 for (
auto &node : net.nodes) {
87 mNodeSubnetMap[node] = &net;
91 for (UInt idx = 0; idx < mTearComponents.size(); ++idx) {
92 auto comp = mTearComponents[idx];
93 auto tComp = std::dynamic_pointer_cast<MNATearInterface>(comp);
95 throw SystemError(
"Unsupported component type for diakoptics");
97 if (comp->hasVirtualNodes()) {
98 for (UInt node = 0; node < comp->virtualNodesNumber(); ++node) {
105 tComp->mnaTearSetIdx(idx);
106 comp->initializeFromNodesAndTerminals(mSystemFrequency);
107 tComp->mnaTearInitialize(2 * PI * mSystemFrequency, mTimeStep);
109 for (
auto gndComp : tComp->mnaTearGroundComponents()) {
110 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(gndComp);
111 Subnet *net =
nullptr;
112 if (pComp->node(0)->isGround()) {
113 net = mNodeSubnetMap[pComp->node(1)];
114 }
else if (pComp->node(1)->isGround()) {
115 net = mNodeSubnetMap[pComp->node(0)];
118 "Invalid ground component passed from torn component");
120 net->components.push_back(gndComp);
124 for (UInt i = 0; i < subnets.size(); ++i) {
125 collectVirtualNodes(i);
126 assignMatrixNodeIndices(i);
130 template <
typename VarType>
132 mSubnets[net].mVirtualNodeNum = 0;
133 mSubnets[net].mRealNetNodeNum =
static_cast<UInt
>(mSubnets[net].nodes.size());
135 for (
auto comp : mSubnets[net].components) {
136 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
140 if (pComp->hasVirtualNodes()) {
141 for (UInt node = 0; node < pComp->virtualNodesNumber(); ++node) {
142 ++(mSubnets[net].mVirtualNodeNum);
143 mSubnets[net].nodes.push_back(pComp->virtualNode(node));
147 SPDLOG_LOGGER_INFO(mSLog,
"Subnet {} has {} real network nodes.", net,
148 mSubnets[net].mRealNetNodeNum);
149 SPDLOG_LOGGER_INFO(mSLog,
"Subnet {} has {} virtual nodes.", net,
150 mSubnets[net].mVirtualNodeNum);
153 template <
typename VarType>
155 UInt matrixNodeIndexIdx = 0;
156 for (UInt idx = 0; idx < mSubnets[net].nodes.size(); ++idx) {
157 auto &node = mSubnets[net].nodes[idx];
159 node->setMatrixNodeIndex(0, matrixNodeIndexIdx);
160 SPDLOG_LOGGER_INFO(mSLog,
"Assigned index {} to node {}",
161 matrixNodeIndexIdx, node->name());
162 ++matrixNodeIndexIdx;
164 if (node->phaseType() == CPS::PhaseType::ABC) {
165 node->setMatrixNodeIndex(1, matrixNodeIndexIdx);
166 SPDLOG_LOGGER_INFO(mSLog,
"Assigned index {} to node {} phase B",
167 matrixNodeIndexIdx, node->name());
168 ++matrixNodeIndexIdx;
169 node->setMatrixNodeIndex(2, matrixNodeIndexIdx);
170 SPDLOG_LOGGER_INFO(mSLog,
"Assigned index {} to node {} phase C",
171 matrixNodeIndexIdx, node->name());
172 ++matrixNodeIndexIdx;
175 setSubnetSize(net, matrixNodeIndexIdx);
178 mSubnets[net].sysOff = 0;
180 mSubnets[net].sysOff = mSubnets[net - 1].sysOff + mSubnets[net - 1].sysSize;
184 mSubnets[net].sysSize = nodes;
185 mSubnets[net].mCmplOff = 0;
189 mSubnets[net].sysSize = 2 * nodes;
190 mSubnets[net].mCmplOff = nodes;
198 std::vector<String> names;
199 for (
auto &subnet : mSubnets) {
200 for (UInt i = subnet.sysOff; i < subnet.sysOff + subnet.sysSize; ++i) {
201 std::stringstream name;
202 if (i < subnet.sysOff + subnet.mCmplOff)
203 name <<
"node" << std::setfill(
'0') << std::setw(5)
204 << i - subnet.sysOff / 2 <<
".real";
206 name <<
"node" << std::setfill(
'0') << std::setw(5)
207 << i - (subnet.sysOff + subnet.sysSize) / 2 <<
".imag";
208 names.push_back(name.str());
211 mLeftVectorLog->setColumnNames(names);
212 mRightVectorLog->setColumnNames(names);
216 UInt totalSize = mSubnets.back().sysOff + mSubnets.back().sysSize;
217 mSystemMatrix = Matrix::Zero(totalSize, totalSize);
218 mSystemInverse = Matrix::Zero(totalSize, totalSize);
220 mRightSideVector = Matrix::Zero(totalSize, 1);
221 mLeftSideVector = Matrix::Zero(totalSize, 1);
222 **mOrigLeftSideVector = Matrix::Zero(totalSize, 1);
223 **mMappedTearCurrents = Matrix::Zero(totalSize, 1);
225 for (
auto &net : mSubnets) {
230 net.leftVector->set(Matrix::Zero(net.sysSize, 1));
233 createTearMatrices(totalSize);
237 mTearTopology = Matrix::Zero(totalSize, mTearComponents.size());
239 CPS::SparseMatrixRow(mTearComponents.size(), mTearComponents.size());
240 mTearCurrents = Matrix::Zero(mTearComponents.size(), 1);
241 mTearVoltages = Matrix::Zero(mTearComponents.size(), 1);
245 mTearTopology = Matrix::Zero(totalSize, 2 * mTearComponents.size());
246 mTearImpedance = CPS::SparseMatrixRow(2 * mTearComponents.size(),
247 2 * mTearComponents.size());
248 mTearCurrents = Matrix::Zero(2 * mTearComponents.size(), 1);
249 mTearVoltages = Matrix::Zero(2 * mTearComponents.size(), 1);
253 for (UInt net = 0; net < mSubnets.size(); ++net) {
254 for (
auto comp : mSubnets[net].components) {
255 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
258 pComp->initializeFromNodesAndTerminals(mSystem.mSystemFrequency);
262 for (
auto comp : mSubnets[net].components) {
263 comp->mnaInitialize(mSystem.mSystemOmega, mTimeStep,
264 mSubnets[net].leftVector);
265 const Matrix &stamp = comp->getRightVector()->get();
266 if (stamp.size() != 0) {
267 mSubnets[net].rightVectorStamps.push_back(&stamp);
272 for (
auto comp : mSimSignalComps)
273 comp->initialize(mSystem.mSystemOmega, mTimeStep);
277 for (
auto &net : mSubnets) {
282 CPS::SparseMatrixRow partSys =
283 CPS::SparseMatrixRow(net.sysSize, net.sysSize);
284 for (
auto comp : net.components) {
285 comp->mnaApplySystemMatrixStamp(partSys);
288 mSystemMatrix.block(net.sysOff, net.sysOff, net.sysSize, net.sysSize);
290 SPDLOG_LOGGER_INFO(mSLog,
"Block: \n{}", block);
291 net.luFactorization = Eigen::PartialPivLU<Matrix>(partSys);
292 SPDLOG_LOGGER_INFO(mSLog,
"Factorization: \n{}",
293 net.luFactorization.matrixLU());
295 SPDLOG_LOGGER_INFO(mSLog,
"Complete system matrix: \n{}", mSystemMatrix);
298 for (UInt compIdx = 0; compIdx < mTearComponents.size(); ++compIdx) {
299 applyTearComponentStamp(compIdx);
301 SPDLOG_LOGGER_INFO(mSLog,
"Topology matrix: \n{}", mTearTopology);
302 SPDLOG_LOGGER_INFO(mSLog,
"Removed impedance matrix: \n{}", mTearImpedance);
304 for (
auto &net : mSubnets) {
305 mSystemInverse.block(net.sysOff, net.sysOff, net.sysSize, net.sysSize) =
306 net.luFactorization.inverse();
308 mTotalTearImpedance = Eigen::PartialPivLU<Matrix>(
310 mTearTopology.transpose() * mSystemInverse * mTearTopology);
311 SPDLOG_LOGGER_INFO(mSLog,
312 "Total removed impedance matrix LU decomposition: \n{}",
313 mTotalTearImpedance.matrixLU());
316 for (
auto &net : mSubnets) {
317 Matrix rInit = Matrix::Zero(net.sysSize, 1);
319 for (
auto comp : net.components) {
320 comp->mnaApplyRightSideVectorStamp(rInit);
322 SPDLOG_LOGGER_INFO(mSLog,
"Source block: \n{}", rInit);
327 auto comp = mTearComponents[compIdx];
328 mTearTopology(mNodeSubnetMap[comp->node(0)]->sysOff +
329 comp->node(0)->matrixNodeIndex(),
331 mTearTopology(mNodeSubnetMap[comp->node(1)]->sysOff +
332 comp->node(1)->matrixNodeIndex(),
335 auto tearComp = std::dynamic_pointer_cast<MNATearInterface>(comp);
336 tearComp->mnaTearApplyMatrixStamp(mTearImpedance);
341 auto comp = mTearComponents[compIdx];
343 auto net1 = mNodeSubnetMap[comp->node(0)];
344 auto net2 = mNodeSubnetMap[comp->node(1)];
346 mTearTopology(net1->sysOff + comp->node(0)->matrixNodeIndex(), compIdx) = 1;
347 mTearTopology(net1->sysOff + net1->mCmplOff +
348 comp->node(0)->matrixNodeIndex(),
349 mTearComponents.size() + compIdx) = 1;
350 mTearTopology(net2->sysOff + comp->node(1)->matrixNodeIndex(), compIdx) = -1;
351 mTearTopology(net2->sysOff + net2->mCmplOff +
352 comp->node(1)->matrixNodeIndex(),
353 mTearComponents.size() + compIdx) = -1;
355 auto tearComp = std::dynamic_pointer_cast<MNATearInterface>(comp);
356 tearComp->mnaTearApplyMatrixStamp(mTearImpedance);
362 for (UInt net = 0; net < mSubnets.size(); ++net) {
363 for (
auto node : mSubnets[net].nodes) {
364 for (
auto task : node->mnaTasks())
368 for (
auto comp : mSubnets[net].components) {
369 for (
auto task : comp->mnaTasks()) {
373 l.push_back(std::make_shared<SubnetSolveTask>(*
this, net));
374 l.push_back(std::make_shared<SolveTask>(*
this, net));
377 for (
auto comp : mSimSignalComps) {
378 for (
auto task : comp->getTasks()) {
382 l.push_back(std::make_shared<PreSolveTask>(*
this));
383 l.push_back(std::make_shared<PostSolveTask>(*
this));
384 l.push_back(std::make_shared<LogTask>(*
this));
389 template <
typename VarType>
393 mSolver.mRightSideVector.block(mSubnet.sysOff, 0, mSubnet.sysSize, 1);
396 for (
auto stamp : mSubnet.rightVectorStamps)
399 auto lBlock = (**mSolver.mOrigLeftSideVector)
400 .block(mSubnet.sysOff, 0, mSubnet.sysSize, 1);
402 lBlock = mSubnet.luFactorization.solve(rBlock);
405 template <
typename VarType>
408 mSolver.mTearVoltages.setZero();
409 for (
auto comp : mSolver.mTearComponents) {
410 auto tComp = std::dynamic_pointer_cast<MNATearInterface>(comp);
411 tComp->mnaTearApplyVoltageStamp(mSolver.mTearVoltages);
414 mSolver.mTearVoltages -=
415 mSolver.mTearTopology.transpose() * **mSolver.mOrigLeftSideVector;
417 mSolver.mTearCurrents =
418 mSolver.mTotalTearImpedance.solve(mSolver.mTearVoltages);
420 **mSolver.mMappedTearCurrents = mSolver.mTearTopology * mSolver.mTearCurrents;
421 mSolver.mLeftSideVector = **mSolver.mOrigLeftSideVector;
424 template <
typename VarType>
428 mSolver.mLeftSideVector.block(mSubnet.sysOff, 0, mSubnet.sysSize, 1);
429 auto rBlock = (**mSolver.mMappedTearCurrents)
430 .block(mSubnet.sysOff, 0, mSubnet.sysSize, 1);
433 lBlock += mSubnet.luFactorization.solve(rBlock);
434 **mSubnet.leftVector = lBlock;
437 template <
typename VarType>
441 mSolver.mTearVoltages =
442 -mSolver.mTearTopology.transpose() * mSolver.mLeftSideVector;
443 for (UInt compIdx = 0; compIdx < mSolver.mTearComponents.size(); ++compIdx) {
444 auto comp = mSolver.mTearComponents[compIdx];
445 auto tComp = std::dynamic_pointer_cast<MNATearInterface>(comp);
447 Math::complexFromVectorElement(mSolver.mTearVoltages, compIdx);
449 Math::complexFromVectorElement(mSolver.mTearCurrents, compIdx);
450 tComp->mnaTearPostStep(voltage, current);
454 for (UInt net = 0; net < mSolver.mSubnets.size(); ++net) {
455 for (UInt node = 0; node < mSolver.mSubnets[net].mRealNetNodeNum; ++node) {
456 mSolver.mSubnets[net].nodes[node]->mnaUpdateVoltage(
457 *(mSolver.mSubnets[net].leftVector));
463 mLeftVectorLog->logEMTNodeValues(time, mLeftSideVector);
464 mRightVectorLog->logEMTNodeValues(time, mRightSideVector);
468 mLeftVectorLog->logPhasorNodeValues(time, mLeftSideVector);
469 mRightVectorLog->logPhasorNodeValues(time, mRightSideVector);
472 template <
typename VarType>
474 mSolver.log(time, timeStepCount);
Real mSystemFrequency
System frequency.
Base class for more specific solvers such as MNA, ODE or IDA.