DPsim
Loading...
Searching...
No Matches
DiakopticsSolver.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/DiakopticsSolver.h>
10
11#include <iomanip>
12
13#include <dpsim-models/MathUtils.h>
14#include <dpsim-models/Solver/MNATearInterface.h>
15#include <dpsim/Definitions.h>
16
17using namespace CPS;
18using namespace DPsim;
19
20namespace DPsim {
21
22template <typename VarType>
23DiakopticsSolver<VarType>::DiakopticsSolver(
24 String name, SystemTopology system, IdentifiedObject::List tearComponents,
25 Real timeStep, Logger::Level logLevel)
26 : Solver(name, logLevel),
27 mMappedTearCurrents(AttributeStatic<Matrix>::make()),
28 mOrigLeftSideVector(AttributeStatic<Matrix>::make()) {
29 mTimeStep = timeStep;
30
31 // Raw source and solution vector logging
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);
36
37 for (auto comp : tearComponents) {
38 auto pcomp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
39 if (pcomp)
40 mTearComponents.push_back(pcomp);
41 }
42 init(system);
43}
44
45template <typename VarType>
46void DiakopticsSolver<VarType>::init(SystemTopology &system) {
47 std::vector<SystemTopology> subnets;
48 mSystem = system;
49 if (mSystem.mNodes.size() > 0)
50 mPhaseType = mSystem.mNodes.at(0)->phaseType();
51 mSystemFrequency = system.mSystemFrequency;
52
53 system.splitSubnets<VarType>(subnets);
54 initSubnets(subnets);
55 setLogColumns();
56 createMatrices();
57 initComponents();
58 initMatrices();
59}
60
61template <typename VarType>
62void DiakopticsSolver<VarType>::initSubnets(
63 const std::vector<SystemTopology> &subnets) {
64 mSubnets.resize(subnets.size());
65 for (UInt i = 0; i < subnets.size(); ++i) {
66 // Add nodes to the list and ignore ground nodes.
67 for (auto baseNode : subnets[i].mNodes) {
68 if (!baseNode->isGround()) {
69 auto node = std::dynamic_pointer_cast<CPS::SimNode<VarType>>(baseNode);
70 mSubnets[i].nodes.push_back(node);
71 }
72 }
73
74 for (auto comp : subnets[i].mComponents) {
75 // TODO switches
76 auto mnaComp = std::dynamic_pointer_cast<CPS::MNAInterface>(comp);
77 if (mnaComp)
78 mSubnets[i].components.push_back(mnaComp);
79
80 auto sigComp = std::dynamic_pointer_cast<CPS::SimSignalComp>(comp);
81 if (sigComp)
82 mSimSignalComps.push_back(sigComp);
83 }
84 }
85
86 // Create map that relates nodes to subnetworks
87 for (auto &net : mSubnets) {
88 for (auto &node : net.nodes) {
89 mNodeSubnetMap[node] = &net;
90 }
91 }
92
93 for (UInt idx = 0; idx < mTearComponents.size(); ++idx) {
94 auto comp = mTearComponents[idx];
95 auto tComp = std::dynamic_pointer_cast<MNATearInterface>(comp);
96 if (!tComp)
97 throw SystemError("Unsupported component type for diakoptics");
98
99 if (comp->hasVirtualNodes()) {
100 for (UInt node = 0; node < comp->virtualNodesNumber(); ++node) {
101 // sim node number doesn't matter here because it shouldn't be used anyway
102 // TODO adapt this to new concept
103 comp->setVirtualNodeAt(std::make_shared<CPS::SimNode<VarType>>(node),
104 node);
105 }
106 }
107 tComp->mnaTearSetIdx(idx);
108 comp->initializeFromNodesAndTerminals(mSystemFrequency);
109 tComp->mnaTearInitialize(2 * PI * mSystemFrequency, mTimeStep);
110
111 for (auto gndComp : tComp->mnaTearGroundComponents()) {
112 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(gndComp);
113 Subnet *net = nullptr;
114 if (pComp->node(0)->isGround()) {
115 net = mNodeSubnetMap[pComp->node(1)];
116 } else if (pComp->node(1)->isGround()) {
117 net = mNodeSubnetMap[pComp->node(0)];
118 } else {
119 throw SystemError(
120 "Invalid ground component passed from torn component");
121 }
122 net->components.push_back(gndComp);
123 }
124 }
125
126 for (UInt i = 0; i < subnets.size(); ++i) {
127 collectVirtualNodes(i);
128 assignMatrixNodeIndices(i);
129 }
130}
131
132template <typename VarType>
133void DiakopticsSolver<VarType>::collectVirtualNodes(int net) {
134 mSubnets[net].mVirtualNodeNum = 0;
135 mSubnets[net].mRealNetNodeNum = static_cast<UInt>(mSubnets[net].nodes.size());
136
137 for (auto comp : mSubnets[net].components) {
138 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
139 if (!pComp)
140 continue;
141
142 if (pComp->hasVirtualNodes()) {
143 for (UInt node = 0; node < pComp->virtualNodesNumber(); ++node) {
144 ++(mSubnets[net].mVirtualNodeNum);
145 mSubnets[net].nodes.push_back(pComp->virtualNode(node));
146 }
147 }
148 }
149 SPDLOG_LOGGER_INFO(mSLog, "Subnet {} has {} real network nodes.", net,
150 mSubnets[net].mRealNetNodeNum);
151 SPDLOG_LOGGER_INFO(mSLog, "Subnet {} has {} virtual nodes.", net,
152 mSubnets[net].mVirtualNodeNum);
153}
154
155template <typename VarType>
156void DiakopticsSolver<VarType>::assignMatrixNodeIndices(int net) {
157 UInt matrixNodeIndexIdx = 0;
158 for (UInt idx = 0; idx < mSubnets[net].nodes.size(); ++idx) {
159 auto &node = mSubnets[net].nodes[idx];
160
161 node->setMatrixNodeIndex(0, matrixNodeIndexIdx);
162 SPDLOG_LOGGER_INFO(mSLog, "Assigned index {} to node {}",
163 matrixNodeIndexIdx, node->name());
164 ++matrixNodeIndexIdx;
165
166 if (node->phaseType() == CPS::PhaseType::ABC) {
167 node->setMatrixNodeIndex(1, matrixNodeIndexIdx);
168 SPDLOG_LOGGER_INFO(mSLog, "Assigned index {} to node {} phase B",
169 matrixNodeIndexIdx, node->name());
170 ++matrixNodeIndexIdx;
171 node->setMatrixNodeIndex(2, matrixNodeIndexIdx);
172 SPDLOG_LOGGER_INFO(mSLog, "Assigned index {} to node {} phase C",
173 matrixNodeIndexIdx, node->name());
174 ++matrixNodeIndexIdx;
175 }
176 }
177 setSubnetSize(net, matrixNodeIndexIdx);
178
179 if (net == 0)
180 mSubnets[net].sysOff = 0;
181 else
182 mSubnets[net].sysOff = mSubnets[net - 1].sysOff + mSubnets[net - 1].sysSize;
183}
184
185template <> void DiakopticsSolver<Real>::setSubnetSize(int net, UInt nodes) {
186 mSubnets[net].sysSize = nodes;
187 mSubnets[net].mCmplOff = 0;
188}
189
190template <> void DiakopticsSolver<Complex>::setSubnetSize(int net, UInt nodes) {
191 mSubnets[net].sysSize = 2 * nodes;
192 mSubnets[net].mCmplOff = nodes;
193}
194
195template <> void DiakopticsSolver<Real>::setLogColumns() {
196 // nothing to do, column names generated by DataLogger are correct
197}
198
199template <> void DiakopticsSolver<Complex>::setLogColumns() {
200 std::vector<String> names;
201 for (auto &subnet : mSubnets) {
202 for (UInt i = subnet.sysOff; i < subnet.sysOff + subnet.sysSize; ++i) {
203 std::stringstream name;
204 if (i < subnet.sysOff + subnet.mCmplOff)
205 name << "node" << std::setfill('0') << std::setw(5)
206 << i - subnet.sysOff / 2 << ".real";
207 else
208 name << "node" << std::setfill('0') << std::setw(5)
209 << i - (subnet.sysOff + subnet.sysSize) / 2 << ".imag";
210 names.push_back(name.str());
211 }
212 }
213 mLeftVectorLog->setColumnNames(names);
214 mRightVectorLog->setColumnNames(names);
215}
216
217template <typename VarType> void DiakopticsSolver<VarType>::createMatrices() {
218 UInt totalSize = mSubnets.back().sysOff + mSubnets.back().sysSize;
219 mSystemMatrix = Matrix::Zero(totalSize, totalSize);
220 mSystemInverse = Matrix::Zero(totalSize, totalSize);
221
222 mRightSideVector = Matrix::Zero(totalSize, 1);
223 mLeftSideVector = Matrix::Zero(totalSize, 1);
224 **mOrigLeftSideVector = Matrix::Zero(totalSize, 1);
225 **mMappedTearCurrents = Matrix::Zero(totalSize, 1);
226
227 for (auto &net : mSubnets) {
228 // The subnets' components expect to be passed a left-side vector matching
229 // the size of the subnet, so we have to create separate vectors here and
230 // copy the solution there
231 net.leftVector = AttributeStatic<Matrix>::make();
232 net.leftVector->set(Matrix::Zero(net.sysSize, 1));
233 }
234
235 createTearMatrices(totalSize);
236}
237
238template <> void DiakopticsSolver<Real>::createTearMatrices(UInt totalSize) {
239 int phaseMultiplier = 1;
240 if (mPhaseType == PhaseType::ABC) {
241 phaseMultiplier = 3;
242 }
243 mTearTopology =
244 Matrix::Zero(totalSize, mTearComponents.size() * phaseMultiplier);
245 mTearImpedance =
246 CPS::SparseMatrixRow(mTearComponents.size() * phaseMultiplier,
247 mTearComponents.size() * phaseMultiplier);
248 mTearCurrents = Matrix::Zero(mTearComponents.size() * phaseMultiplier, 1);
249 mTearVoltages = Matrix::Zero(mTearComponents.size() * phaseMultiplier, 1);
250}
251
252template <> void DiakopticsSolver<Complex>::createTearMatrices(UInt totalSize) {
253 int phaseMultiplier = 1;
254 if (mPhaseType == PhaseType::ABC) {
255 phaseMultiplier = 3;
256 }
257 mTearTopology =
258 Matrix::Zero(totalSize, 2 * mTearComponents.size() * phaseMultiplier);
259 mTearImpedance =
260 CPS::SparseMatrixRow(2 * mTearComponents.size() * phaseMultiplier,
261 2 * mTearComponents.size() * phaseMultiplier);
262 mTearCurrents = Matrix::Zero(2 * mTearComponents.size() * phaseMultiplier, 1);
263 mTearVoltages = Matrix::Zero(2 * mTearComponents.size() * phaseMultiplier, 1);
264}
265
266template <typename VarType> void DiakopticsSolver<VarType>::initComponents() {
267 for (UInt net = 0; net < mSubnets.size(); ++net) {
268 for (auto comp : mSubnets[net].components) {
269 auto pComp = std::dynamic_pointer_cast<SimPowerComp<VarType>>(comp);
270 if (!pComp)
271 continue;
272 pComp->initializeFromNodesAndTerminals(mSystem.mSystemFrequency);
273 }
274
275 // Initialize MNA specific parts of components.
276 for (auto comp : mSubnets[net].components) {
277 comp->mnaInitialize(mSystem.mSystemOmega, mTimeStep,
278 mSubnets[net].leftVector);
279 const Matrix &stamp = comp->getRightVector()->get();
280 if (stamp.size() != 0) {
281 mSubnets[net].rightVectorStamps.push_back(&stamp);
282 }
283 }
284 }
285 // Initialize signal components.
286 for (auto comp : mSimSignalComps)
287 comp->initialize(mSystem.mSystemOmega, mTimeStep);
288}
289
290template <typename VarType> void DiakopticsSolver<VarType>::initMatrices() {
291 for (auto &net : mSubnets) {
292 // We can't directly pass the block reference to mnaApplySystemMatrixStamp,
293 // because it expects a concrete Matrix. It can't be changed to accept some common
294 // base class like DenseBase because that would make it a template function (as
295 // Eigen uses CRTP for polymorphism), which is impossible for virtual functions.
296 CPS::SparseMatrixRow partSys =
297 CPS::SparseMatrixRow(net.sysSize, net.sysSize);
298 for (auto comp : net.components) {
299 comp->mnaApplySystemMatrixStamp(partSys);
300 }
301 auto block =
302 mSystemMatrix.block(net.sysOff, net.sysOff, net.sysSize, net.sysSize);
303 block = partSys;
304 SPDLOG_LOGGER_INFO(mSLog, "Block: \n{}", block);
305 net.luFactorization = Eigen::PartialPivLU<Matrix>(partSys);
306 SPDLOG_LOGGER_INFO(mSLog, "Factorization: \n{}",
307 net.luFactorization.matrixLU());
308 }
309 SPDLOG_LOGGER_INFO(mSLog, "Complete system matrix: \n{}", mSystemMatrix);
310
311 // initialize tear topology matrix and impedance matrix of removed network
312 for (UInt compIdx = 0; compIdx < mTearComponents.size(); ++compIdx) {
313 applyTearComponentStamp(compIdx);
314 }
315 SPDLOG_LOGGER_INFO(mSLog, "Topology matrix: \n{}", mTearTopology);
316 SPDLOG_LOGGER_INFO(mSLog, "Removed impedance matrix: \n{}", mTearImpedance);
317 // TODO this can be sped up as well by using the block diagonal form of Yinv
318 for (auto &net : mSubnets) {
319 mSystemInverse.block(net.sysOff, net.sysOff, net.sysSize, net.sysSize) =
320 net.luFactorization.inverse();
321 }
322 mTotalTearImpedance = Eigen::PartialPivLU<Matrix>(
323 mTearImpedance +
324 mTearTopology.transpose() * mSystemInverse * mTearTopology);
325 SPDLOG_LOGGER_INFO(mSLog,
326 "Total removed impedance matrix LU decomposition: \n{}",
327 mTotalTearImpedance.matrixLU());
328
329 // Compute subnet right side (source) vectors for debugging
330 for (auto &net : mSubnets) {
331 Matrix rInit = Matrix::Zero(net.sysSize, 1);
332
333 for (auto comp : net.components) {
334 comp->mnaApplyRightSideVectorStamp(rInit);
335 }
336 SPDLOG_LOGGER_INFO(mSLog, "Source block: \n{}", rInit);
337 }
338}
339
340template <> void DiakopticsSolver<Real>::applyTearComponentStamp(UInt compIdx) {
341 auto comp = mTearComponents[compIdx];
342
343 // Use triplets to populate the sparse matrix
344 std::vector<Eigen::Triplet<double>> triplets;
345
346 // Node 0 contributions
347 if (comp->node(0)->phaseType() == CPS::PhaseType::ABC) {
348 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
349 comp->node(0)->matrixNodeIndex(PhaseType::A),
350 compIdx * 3, 1);
351 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
352 comp->node(0)->matrixNodeIndex(PhaseType::B),
353 compIdx * 3 + 1, 1);
354 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
355 comp->node(0)->matrixNodeIndex(PhaseType::C),
356 compIdx * 3 + 2, 1);
357 } else {
358 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
359 comp->node(0)->matrixNodeIndex(),
360 compIdx, 1);
361 }
362
363 // Node 1 contributions
364 if (comp->node(0)->phaseType() == CPS::PhaseType::ABC) {
365 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
366 comp->node(1)->matrixNodeIndex(PhaseType::A),
367 compIdx * 3, -1);
368 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
369 comp->node(1)->matrixNodeIndex(PhaseType::B),
370 compIdx * 3 + 1, -1);
371 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
372 comp->node(1)->matrixNodeIndex(PhaseType::C),
373 compIdx * 3 + 2, -1);
374 } else {
375 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
376 comp->node(1)->matrixNodeIndex(),
377 compIdx, -1);
378 }
379
380 // Apply triplets to the sparse matrix
381 for (const auto &triplet : triplets) {
382 mTearTopology.coeffRef(triplet.row(), triplet.col()) += triplet.value();
383 }
384
385 // Call tear component stamp function
386 auto tearComp = std::dynamic_pointer_cast<MNATearInterface>(comp);
387 tearComp->mnaTearApplyMatrixStamp(mTearImpedance);
388}
389
390template <>
391void DiakopticsSolver<Complex>::applyTearComponentStamp(UInt compIdx) {
392 auto comp = mTearComponents[compIdx];
393
394 // Use triplets to populate the sparse matrix
395 std::vector<Eigen::Triplet<double>> triplets;
396
397 // Node 0 contributions
398 if (comp->node(0)->phaseType() == CPS::PhaseType::ABC) {
399 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
400 comp->node(0)->matrixNodeIndex(PhaseType::A),
401 compIdx * 3, 1);
402 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
403 mNodeSubnetMap[comp->node(0)]->mCmplOff +
404 comp->node(0)->matrixNodeIndex(PhaseType::A),
405 mTearComponents.size() * 3 + compIdx * 3,
406 double(1.0));
407 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
408 comp->node(0)->matrixNodeIndex(PhaseType::B),
409 compIdx * 3 + 1, 1);
410 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
411 mNodeSubnetMap[comp->node(0)]->mCmplOff +
412 comp->node(0)->matrixNodeIndex(PhaseType::B),
413 mTearComponents.size() * 3 + compIdx * 3 + 1,
414 double(1.0));
415 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
416 comp->node(0)->matrixNodeIndex(PhaseType::C),
417 compIdx * 3 + 2, 1);
418 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
419 mNodeSubnetMap[comp->node(0)]->mCmplOff +
420 comp->node(0)->matrixNodeIndex(PhaseType::C),
421 mTearComponents.size() * 3 + compIdx * 3 + 2,
422 double(1.0));
423 } else {
424 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
425 comp->node(0)->matrixNodeIndex(),
426 compIdx, 1);
427 triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff +
428 mNodeSubnetMap[comp->node(0)]->mCmplOff +
429 comp->node(0)->matrixNodeIndex(),
430 mTearComponents.size() + compIdx, double(1.0));
431 }
432
433 if (comp->node(0)->phaseType() == CPS::PhaseType::ABC) {
434 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
435 comp->node(1)->matrixNodeIndex(PhaseType::A),
436 compIdx * 3, -1);
437 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
438 mNodeSubnetMap[comp->node(1)]->mCmplOff +
439 comp->node(1)->matrixNodeIndex(PhaseType::A),
440 mTearComponents.size() * 3 + compIdx * 3,
441 double(-1.0));
442 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
443 comp->node(1)->matrixNodeIndex(PhaseType::B),
444 compIdx * 3 + 1, -1);
445 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
446 mNodeSubnetMap[comp->node(1)]->mCmplOff +
447 comp->node(1)->matrixNodeIndex(PhaseType::B),
448 mTearComponents.size() * 3 + compIdx * 3 + 1,
449 double(-1.0));
450 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
451 comp->node(1)->matrixNodeIndex(PhaseType::C),
452 compIdx * 3 + 2, -1);
453 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
454 mNodeSubnetMap[comp->node(1)]->mCmplOff +
455 comp->node(1)->matrixNodeIndex(PhaseType::C),
456 mTearComponents.size() * 3 + compIdx * 3 + 2,
457 double(-1.0));
458 } else {
459 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
460 comp->node(1)->matrixNodeIndex(),
461 compIdx, -1);
462 triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff +
463 mNodeSubnetMap[comp->node(1)]->mCmplOff +
464 comp->node(1)->matrixNodeIndex(),
465 mTearComponents.size() + compIdx, double(-1.0));
466 }
467 // Apply triplets to the sparse matrix
468 for (const auto &triplet : triplets) {
469 mTearTopology.coeffRef(triplet.row(), triplet.col()) += triplet.value();
470 }
471
472 // Call tear component stamp function
473 auto tearComp = std::dynamic_pointer_cast<MNATearInterface>(comp);
474 tearComp->mnaTearApplyMatrixStamp(mTearImpedance);
475}
476
477template <typename VarType> Task::List DiakopticsSolver<VarType>::getTasks() {
478 Task::List l;
479
480 for (UInt net = 0; net < mSubnets.size(); ++net) {
481 for (auto node : mSubnets[net].nodes) {
482 for (auto task : node->mnaTasks())
483 l.push_back(task);
484 }
485
486 for (auto comp : mSubnets[net].components) {
487 for (auto task : comp->mnaTasks()) {
488 l.push_back(task);
489 }
490 }
491 l.push_back(std::make_shared<SubnetSolveTask>(*this, net));
492 l.push_back(std::make_shared<SolveTask>(*this, net));
493 }
494
495 for (auto comp : mSimSignalComps) {
496 for (auto task : comp->getTasks()) {
497 l.push_back(task);
498 }
499 }
500 l.push_back(std::make_shared<PreSolveTask>(*this));
501 l.push_back(std::make_shared<PostSolveTask>(*this));
502 l.push_back(std::make_shared<LogTask>(*this));
503
504 return l;
505}
506
507template <typename VarType>
508void DiakopticsSolver<VarType>::SubnetSolveTask::execute(Real time,
509 Int timeStepCount) {
510 auto rBlock =
511 mSolver.mRightSideVector.block(mSubnet.sysOff, 0, mSubnet.sysSize, 1);
512 rBlock.setZero();
513
514 for (auto stamp : mSubnet.rightVectorStamps)
515 rBlock += *stamp;
516
517 auto lBlock = (**mSolver.mOrigLeftSideVector)
518 .block(mSubnet.sysOff, 0, mSubnet.sysSize, 1);
519 // Solve Y' * v' = I
520 lBlock = mSubnet.luFactorization.solve(rBlock);
521}
522
523template <typename VarType>
524void DiakopticsSolver<VarType>::PreSolveTask::execute(Real time,
525 Int timeStepCount) {
526 mSolver.mTearVoltages.setZero();
527 for (auto comp : mSolver.mTearComponents) {
528 auto tComp = std::dynamic_pointer_cast<MNATearInterface>(comp);
529 tComp->mnaTearApplyVoltageStamp(mSolver.mTearVoltages);
530 }
531 // -C^T * v'
532 mSolver.mTearVoltages -=
533 mSolver.mTearTopology.transpose() * **mSolver.mOrigLeftSideVector;
534 // Solve Z' * i = E - C^T * v'
535 mSolver.mTearCurrents =
536 mSolver.mTotalTearImpedance.solve(mSolver.mTearVoltages);
537 // C * i
538 **mSolver.mMappedTearCurrents = mSolver.mTearTopology * mSolver.mTearCurrents;
539 mSolver.mLeftSideVector = **mSolver.mOrigLeftSideVector;
540}
541
542template <typename VarType>
543void DiakopticsSolver<VarType>::SolveTask::execute(Real time,
544 Int timeStepCount) {
545 auto lBlock =
546 mSolver.mLeftSideVector.block(mSubnet.sysOff, 0, mSubnet.sysSize, 1);
547 auto rBlock = (**mSolver.mMappedTearCurrents)
548 .block(mSubnet.sysOff, 0, mSubnet.sysSize, 1);
549 // Solve Y' * x = C * i
550 // v = v' + x
551 lBlock += mSubnet.luFactorization.solve(rBlock);
552 **mSubnet.leftVector = lBlock;
553}
554
555template <>
556void DiakopticsSolver<Real>::PostSolveTask::execute(Real time,
557 Int timeStepCount) {
558 // pass the voltages and current of the solution to the torn components
559 mSolver.mTearVoltages =
560 -mSolver.mTearTopology.transpose() * mSolver.mLeftSideVector;
561 for (UInt compIdx = 0; compIdx < mSolver.mTearComponents.size(); ++compIdx) {
562 auto comp = mSolver.mTearComponents[compIdx];
563 auto tComp = std::dynamic_pointer_cast<MNATearInterface>(comp);
564 if (mSolver.mPhaseType == CPS::PhaseType::ABC) {
565 Matrix voltage = Matrix::Zero(3, 1);
566 voltage << mSolver.mTearVoltages(compIdx * 3),
567 mSolver.mTearVoltages(compIdx * 3 + 1),
568 mSolver.mTearVoltages(compIdx * 3 + 2);
569
570 Matrix current = Matrix::Zero(3, 1);
571 current << mSolver.mTearCurrents(compIdx * 3),
572 mSolver.mTearCurrents(compIdx * 3 + 1),
573 mSolver.mTearCurrents(compIdx * 3 + 2);
574 tComp->mnaTearPostStep(voltage, current);
575 } else {
576 Complex voltage =
577 Math::complexFromVectorElement(mSolver.mTearVoltages, compIdx);
578 Complex current =
579 Math::complexFromVectorElement(mSolver.mTearCurrents, compIdx);
580 tComp->mnaTearPostStep(voltage, current);
581 }
582 }
583
584 // TODO split into separate task? (dependent on x, updating all v attributes)
585 for (UInt net = 0; net < mSolver.mSubnets.size(); ++net) {
586 for (UInt node = 0; node < mSolver.mSubnets[net].mRealNetNodeNum; ++node) {
587 mSolver.mSubnets[net].nodes[node]->mnaUpdateVoltage(
588 *(mSolver.mSubnets[net].leftVector));
589 }
590 }
591}
592
593template <>
594void DiakopticsSolver<Complex>::PostSolveTask::execute(Real time,
595 Int timeStepCount) {
596 // pass the voltages and current of the solution to the torn components
597 mSolver.mTearVoltages =
598 -mSolver.mTearTopology.transpose() * mSolver.mLeftSideVector;
599 for (UInt compIdx = 0; compIdx < mSolver.mTearComponents.size(); ++compIdx) {
600 auto comp = mSolver.mTearComponents[compIdx];
601 auto tComp = std::dynamic_pointer_cast<MNATearInterface>(comp);
602 if (mSolver.mPhaseType == CPS::PhaseType::ABC) {
603 MatrixComp voltage = MatrixComp::Zero(3, 1);
604 voltage << Math::complexFromVectorElement(mSolver.mTearVoltages,
605 compIdx * 3),
606 Math::complexFromVectorElement(mSolver.mTearVoltages,
607 compIdx * 3 + 1),
608 Math::complexFromVectorElement(mSolver.mTearVoltages,
609 compIdx * 3 + 2);
610 MatrixComp current = MatrixComp::Zero(3, 1);
611 current << Math::complexFromVectorElement(mSolver.mTearCurrents,
612 compIdx * 3),
613 Math::complexFromVectorElement(mSolver.mTearCurrents,
614 compIdx * 3 + 1),
615 Math::complexFromVectorElement(mSolver.mTearCurrents,
616 compIdx * 3 + 2);
617 tComp->mnaTearPostStep(voltage, current);
618 } else {
619 Complex voltage =
620 Math::complexFromVectorElement(mSolver.mTearVoltages, compIdx);
621 Complex current =
622 Math::complexFromVectorElement(mSolver.mTearCurrents, compIdx);
623 tComp->mnaTearPostStep(voltage, current);
624 }
625 }
626
627 // TODO split into separate task? (dependent on x, updating all v attributes)
628 for (UInt net = 0; net < mSolver.mSubnets.size(); ++net) {
629 for (UInt node = 0; node < mSolver.mSubnets[net].mRealNetNodeNum; ++node) {
630 mSolver.mSubnets[net].nodes[node]->mnaUpdateVoltage(
631 *(mSolver.mSubnets[net].leftVector));
632 }
633 }
634}
635
636template <> void DiakopticsSolver<Real>::log(Real time, Int timeStepCount) {
637 mLeftVectorLog->logEMTNodeValues(time, mLeftSideVector);
638 mRightVectorLog->logEMTNodeValues(time, mRightSideVector);
639}
640
641template <> void DiakopticsSolver<Complex>::log(Real time, Int timeStepCount) {
642 mLeftVectorLog->logPhasorNodeValues(time, mLeftSideVector);
643 mRightVectorLog->logPhasorNodeValues(time, mRightSideVector);
644}
645
646template <typename VarType>
647void DiakopticsSolver<VarType>::LogTask::execute(Real time, Int timeStepCount) {
648 mSolver.log(time, timeStepCount);
649}
650
651template class DiakopticsSolver<Real>;
652template class DiakopticsSolver<Complex>;
653
654} // namespace DPsim
Real mSystemFrequency
System frequency.
TopologicalNode::List mNodes
List of network nodes.
CPS::Task::List getTasks() override
Get tasks for scheduler.
Base class for more specific solvers such as MNA, ODE or IDA.
Definition Solver.h:30