DPsim
Loading...
Searching...
No Matches
PFSolverPowerPolar.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/PFSolverPowerPolar.h>
10
11using namespace DPsim;
12using namespace CPS;
13
15 const CPS::SystemTopology &system,
16 CPS::Real timeStep,
17 CPS::Logger::Level logLevel)
18 : PFSolver(name, system, timeStep, logLevel) {}
19
21 bool keep_last_solution) {
22 resize_sol(mSystem.mNodes.size());
23 resize_complex_sol(mSystem.mNodes.size());
24
25 // update all components for the new time
26 for (auto comp : mSystem.mComponents) {
27 if (std::shared_ptr<CPS::SP::Ph1::Load> load =
28 std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
29 if (load->use_profile) {
30 load->updatePQ(time);
31 }
32 load->calculatePerUnitParameters(mBaseApparentPower,
33 mSystem.mSystemOmega);
34 }
35 }
36
37 // set initial solution for the new time
38 for (auto pq : mPQBuses) {
39 if (!keep_last_solution) {
40 sol_V(pq->matrixNodeIndex()) = 1.0;
41 sol_D(pq->matrixNodeIndex()) = 0.0;
42 sol_V_complex(pq->matrixNodeIndex()) = CPS::Complex(
43 sol_V[pq->matrixNodeIndex()], sol_D[pq->matrixNodeIndex()]);
44 }
45 for (auto comp : mSystem.mComponentsAtNode[pq]) {
46 if (std::shared_ptr<CPS::SP::Ph1::Load> load =
47 std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
48 sol_P(pq->matrixNodeIndex()) -=
49 load->attributeTyped<CPS::Real>("P_pu")->get();
50 sol_Q(pq->matrixNodeIndex()) -=
51 load->attributeTyped<CPS::Real>("Q_pu")->get();
52 } else if (std::shared_ptr<CPS::SP::Ph1::SolidStateTransformer> sst =
53 std::dynamic_pointer_cast<
55 sol_P(pq->matrixNodeIndex()) -= sst->getNodalInjection(pq).real();
56 sol_Q(pq->matrixNodeIndex()) -= sst->getNodalInjection(pq).imag();
57 } else if (std::shared_ptr<CPS::SP::Ph1::AvVoltageSourceInverterDQ> vsi =
58 std::dynamic_pointer_cast<
60 // TODO: add per-unit attributes to VSI and use here
61 sol_P(pq->matrixNodeIndex()) +=
62 vsi->attributeTyped<CPS::Real>("P_ref")->get() / mBaseApparentPower;
63 sol_Q(pq->matrixNodeIndex()) +=
64 vsi->attributeTyped<CPS::Real>("Q_ref")->get() / mBaseApparentPower;
65 } else if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
66 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
67 comp)) {
68 sol_P(pq->matrixNodeIndex()) +=
69 gen->attributeTyped<CPS::Real>("P_set_pu")->get();
70 sol_Q(pq->matrixNodeIndex()) +=
71 gen->attributeTyped<CPS::Real>("Q_set_pu")->get();
72 }
73 sol_S_complex(pq->matrixNodeIndex()) = CPS::Complex(
74 sol_P[pq->matrixNodeIndex()], sol_Q[pq->matrixNodeIndex()]);
75 }
76 }
77
78 for (auto pv : mPVBuses) {
79 if (!keep_last_solution) {
80 sol_Q(pv->matrixNodeIndex()) = 0;
81 sol_D(pv->matrixNodeIndex()) = 0;
82 }
83 for (auto comp : mSystem.mComponentsAtNode[pv]) {
84 if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
85 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
86 comp)) {
87 sol_P(pv->matrixNodeIndex()) +=
88 gen->attributeTyped<CPS::Real>("P_set_pu")->get();
89 sol_V(pv->matrixNodeIndex()) =
90 gen->attributeTyped<CPS::Real>("V_set_pu")->get();
91 sol_Q(pv->matrixNodeIndex()) +=
92 gen->attributeTyped<CPS::Real>("Q_set_pu")->get();
93 } else if (std::shared_ptr<CPS::SP::Ph1::Load> load =
94 std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
95 sol_P(pv->matrixNodeIndex()) -=
96 load->attributeTyped<CPS::Real>("P_pu")->get();
97 sol_Q(pv->matrixNodeIndex()) -=
98 load->attributeTyped<CPS::Real>("Q_pu")->get();
99 } else if (std::shared_ptr<CPS::SP::Ph1::AvVoltageSourceInverterDQ> vsi =
100 std::dynamic_pointer_cast<
102 sol_P(pv->matrixNodeIndex()) +=
103 vsi->attributeTyped<CPS::Real>("P_ref")->get() / mBaseApparentPower;
104 } else if (std::shared_ptr<CPS::SP::Ph1::NetworkInjection> extnet =
105 std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(
106 comp)) {
107 sol_P(pv->matrixNodeIndex()) +=
108 extnet->attributeTyped<CPS::Real>("p_inj")->get() /
110 sol_Q(pv->matrixNodeIndex()) +=
111 extnet->attributeTyped<CPS::Real>("q_inj")->get() /
113 sol_V(pv->matrixNodeIndex()) =
114 extnet->attributeTyped<CPS::Real>("V_set_pu")->get();
115 }
116 sol_S_complex(pv->matrixNodeIndex()) = CPS::Complex(
117 sol_P[pv->matrixNodeIndex()], sol_Q[pv->matrixNodeIndex()]);
118 sol_V_complex(pv->matrixNodeIndex()) = CPS::Complex(
119 sol_V[pv->matrixNodeIndex()], sol_D[pv->matrixNodeIndex()]);
120 }
121 }
122
123 for (auto vd : mVDBuses) {
124 sol_P(vd->matrixNodeIndex()) = 0.0;
125 sol_Q(vd->matrixNodeIndex()) = 0.0;
126 sol_V(vd->matrixNodeIndex()) = 1.0;
127 sol_D(vd->matrixNodeIndex()) = 0.0;
128
129 // if external injection at VD bus, reset the voltage to injection's voltage set-point
130 for (auto comp : mSystem.mComponentsAtNode[vd]) {
131 if (std::shared_ptr<CPS::SP::Ph1::NetworkInjection> extnet =
132 std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(comp)) {
133 sol_V(vd->matrixNodeIndex()) =
134 extnet->attributeTyped<CPS::Real>("V_set_pu")->get();
135 sol_P(vd->matrixNodeIndex()) +=
136 extnet->attributeTyped<CPS::Real>("p_inj")->get() /
137 mBaseApparentPower; // Todo add p_set q_set to extnet
138 sol_Q(vd->matrixNodeIndex()) +=
139 extnet->attributeTyped<CPS::Real>("q_inj")->get() /
141 }
142
143 // if load at VD bus, substract P and Q
144 else if (std::shared_ptr<CPS::SP::Ph1::Load> load =
145 std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
146 sol_P(vd->matrixNodeIndex()) -=
147 load->attributeTyped<CPS::Real>("P_pu")->get();
148 sol_Q(vd->matrixNodeIndex()) -=
149 load->attributeTyped<CPS::Real>("Q_pu")->get();
150 }
151
152 // if generator at VD, add P_set Q_Set
153 else if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
154 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
155 comp)) {
156 sol_P(vd->matrixNodeIndex()) +=
157 gen->attributeTyped<CPS::Real>("P_set_pu")->get();
158 sol_Q(vd->matrixNodeIndex()) +=
159 gen->attributeTyped<CPS::Real>("Q_set_pu")->get();
160 }
161 }
162
163 // if generator at VD bus, reset the voltage to generator's set-point
164 if (!mSynchronGenerators.empty()) {
165 for (auto gen : mSynchronGenerators) {
166 if (gen->node(0)->matrixNodeIndex() == vd->matrixNodeIndex())
167 sol_V(vd->matrixNodeIndex()) =
168 gen->attributeTyped<CPS::Real>("V_set_pu")->get();
169 }
170 }
171
172 sol_S_complex(vd->matrixNodeIndex()) = CPS::Complex(
173 sol_P[vd->matrixNodeIndex()], sol_Q[vd->matrixNodeIndex()]);
174 sol_V_complex(vd->matrixNodeIndex()) = CPS::Complex(
175 sol_V[vd->matrixNodeIndex()], sol_D[vd->matrixNodeIndex()]);
176 }
177
178 solutionInitialized = true;
180
181 Pesp = sol_P;
182 Qesp = sol_Q;
183
184 SPDLOG_LOGGER_INFO(mSLog, "#### Initial solution: ");
185 SPDLOG_LOGGER_INFO(mSLog, "P\t\tQ\t\tV\t\tD");
186 for (UInt i = 0; i < mSystem.mNodes.size(); ++i) {
187 SPDLOG_LOGGER_INFO(mSLog, "{}\t{}\t{}\t{}", sol_P[i], sol_Q[i], sol_V[i],
188 sol_D[i]);
189 }
190 mSLog->flush();
191}
192
194 UInt npqpv = mNumPQBuses + mNumPVBuses;
195 UInt k;
196 mF.setZero();
197
198 for (UInt a = 0; a < npqpv; ++a) {
199 // For PQ and PV buses calculate active power mismatch
200 k = mPQPVBusIndices[a];
201 mF(a) = Pesp.coeff(k) - P(k);
202
203 //only for PQ buses calculate reactive power mismatch
204 if (a < mNumPQBuses)
205 mF(a + npqpv) = Qesp.coeff(k) - Q(k);
206 }
207}
208
210 UInt npqpv = mNumPQBuses + mNumPVBuses;
211 double val;
212 UInt k, j;
213 UInt da, db;
214
215 mJ.setZero();
216
217 //J1
218 for (UInt a = 0; a < npqpv; ++a) { //rows
219 k = mPQPVBusIndices[a];
220 //diagonal
221 mJ.coeffRef(a, a) = -Q(k) - B(k, k) * sol_V.coeff(k) * sol_V.coeff(k);
222
223 //non diagonal elements
224 for (UInt b = 0; b < npqpv; ++b) {
225 if (b != a) {
226 j = mPQPVBusIndices[b];
227 val = sol_V.coeff(k) * sol_V.coeff(j) *
228 (G(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)) -
229 B(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)));
230 //if (val != 0.0)
231 mJ.coeffRef(a, b) = val;
232 }
233 }
234 }
235
236 //J2
237 da = 0;
238 db = npqpv;
239 for (UInt a = 0; a < npqpv; ++a) { //rows
240 k = mPQPVBusIndices[a];
241 //diagonal
242 //std::cout << "J2D:" << (a + da) << "," << (a + db) << std::endl;
243 if (a < mNumPQBuses)
244 mJ.coeffRef(a + da, a + db) =
245 P(k) + G(k, k) * sol_V.coeff(k) * sol_V.coeff(k);
246
247 //non diagonal elements
248 for (UInt b = 0; b < mNumPQBuses; ++b) {
249 if (b != a) {
250 j = mPQPVBusIndices[b];
251 val = sol_V.coeff(k) * sol_V.coeff(j) *
252 (G(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)) +
253 B(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)));
254 //if (val != 0.0)
255 //std::cout << "J2ij:" << (a + da) << "," << (b + db) << std::endl;
256 mJ.coeffRef(a + da, b + db) = val;
257 }
258 }
259 }
260
261 //J3
262 da = npqpv;
263 db = 0;
264 for (UInt a = 0; a < mNumPQBuses; ++a) { //rows
265 k = mPQPVBusIndices[a];
266 //diagonal
267 //std::cout << "J3:" << (a + da) << "," << (a + db) << std::endl;
268 mJ.coeffRef(a + da, a + db) =
269 P(k) - G(k, k) * sol_V.coeff(k) * sol_V.coeff(k);
270
271 //non diagonal elements
272 for (UInt b = 0; b < npqpv; ++b) {
273 if (b != a) {
274 j = mPQPVBusIndices[b];
275 val = sol_V.coeff(k) * sol_V.coeff(j) *
276 (G(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)) +
277 B(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)));
278 //if (val != 0.0)
279 //std::cout << "J3:" << (a + da) << "," << (b + db) << std::endl;
280 mJ.coeffRef(a + da, b + db) = -val;
281 }
282 }
283 }
284
285 //J4
286 da = npqpv;
287 db = npqpv;
288 for (UInt a = 0; a < mNumPQBuses; ++a) { //rows
289 k = mPQPVBusIndices[a];
290 //diagonal
291 //std::cout << "J4:" << (a + da) << "," << (a + db) << std::endl;
292 mJ.coeffRef(a + da, a + db) =
293 Q(k) - B(k, k) * sol_V.coeff(k) * sol_V.coeff(k);
294
295 //non diagonal elements
296 for (UInt b = 0; b < mNumPQBuses; ++b) {
297 if (b != a) {
298 j = mPQPVBusIndices[b];
299 val = sol_V.coeff(k) * sol_V.coeff(j) *
300 (G(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)) -
301 B(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)));
302 if (val != 0.0) {
303 //std::cout << "J4:" << (a + da) << "," << (b + db) << std::endl;
304 mJ.coeffRef(a + da, b + db) = val;
305 }
306 }
307 }
308 }
309}
310
312 UInt npqpv = mNumPQBuses + mNumPVBuses;
313 UInt k;
314
315 for (UInt a = 0; a < npqpv; ++a) {
316 k = mPQPVBusIndices[a];
317 sol_D(k) += mX.coeff(a);
318
319 if (a < mNumPQBuses)
320 sol_V(k) = sol_V.coeff(k) * (1.0 + mX.coeff(a + npqpv));
321 }
322
323 //Correct for PV buses
324 for (UInt i = mNumPQBuses; i < npqpv; ++i) {
325 k = mPQPVBusIndices[i];
326 Complex v = sol_Vcx(k);
327 // v *= Model.buses[k].v_set_point / abs(v);
328 sol_V(k) = abs(v);
329 sol_D(k) = arg(v);
330 }
331}
332
334 if (!isConverged) {
335 SPDLOG_LOGGER_INFO(mSLog, "Not converged within {} iterations",
337 } else {
341 SPDLOG_LOGGER_INFO(mSLog, "converged in {} iterations", mIterations);
342 SPDLOG_LOGGER_INFO(mSLog, "Solution: ");
343 SPDLOG_LOGGER_INFO(mSLog, "P\t\tQ\t\tV\t\tD");
344 for (UInt i = 0; i < mSystem.mNodes.size(); ++i) {
345 SPDLOG_LOGGER_INFO(mSLog, "{}\t{}\t{}\t{}", sol_P[i], sol_Q[i], sol_V[i],
346 sol_D[i]);
347 }
348 }
349 for (UInt i = 0; i < mSystem.mNodes.size(); ++i) {
350 sol_S_complex(i) = CPS::Complex(sol_P.coeff(i), sol_Q.coeff(i));
351 sol_V_complex(i) = CPS::Complex(sol_V.coeff(i) * cos(sol_D.coeff(i)),
352 sol_V.coeff(i) * sin(sol_D.coeff(i)));
353 }
354
355 // update voltage and power at each node
356 for (auto node : mSystem.mNodes) {
357 std::dynamic_pointer_cast<CPS::SimNode<CPS::Complex>>(node)->setVoltage(
358 sol_V_complex(node->matrixNodeIndex()) * mBaseVoltageAtNode[node]);
359 std::dynamic_pointer_cast<CPS::SimNode<CPS::Complex>>(node)->setPower(
360 sol_S_complex(node->matrixNodeIndex()) * mBaseApparentPower);
361 }
364}
365
367 for (auto line : mLines) {
368 VectorComp v(2);
369 v(0) = sol_V_complex.coeff(line->node(0)->matrixNodeIndex());
370 v(1) = sol_V_complex.coeff(line->node(1)->matrixNodeIndex());
372 VectorComp current = line->Y_element() * v;
374 VectorComp flow_on_branch = v.array() * current.conjugate().array();
375 line->updateBranchFlow(current, flow_on_branch);
376 }
377 for (auto trafo : mTransformers) {
378 VectorComp v(2);
379 v(0) = sol_V_complex.coeff(trafo->node(0)->matrixNodeIndex());
380 v(1) = sol_V_complex.coeff(trafo->node(1)->matrixNodeIndex());
382 VectorComp current = trafo->Y_element() * v;
384 VectorComp flow_on_branch = v.array() * current.conjugate().array();
385 trafo->updateBranchFlow(current, flow_on_branch);
386 }
387}
388
390 for (auto node : mSystem.mNodes) {
391 std::list<std::shared_ptr<CPS::SP::Ph1::PiLine>> lines;
392 for (auto comp : mSystem.mComponentsAtNode[node]) {
393 if (std::shared_ptr<CPS::SP::Ph1::PiLine> line =
394 std::dynamic_pointer_cast<CPS::SP::Ph1::PiLine>(comp)) {
395 line->storeNodalInjection(sol_S_complex.coeff(node->matrixNodeIndex()));
396 lines.push_back(line);
397 break;
398 }
399 }
400 if (lines.empty()) {
401 for (auto comp : mSystem.mComponentsAtNode[node]) {
402 if (std::shared_ptr<CPS::SP::Ph1::Transformer> trafo =
403 std::dynamic_pointer_cast<CPS::SP::Ph1::Transformer>(comp)) {
404 trafo->storeNodalInjection(
405 sol_S_complex.coeff(node->matrixNodeIndex()));
406 break;
407 }
408 }
409 }
410 }
411}
412
414 Real val = 0.0;
415 for (UInt j = 0; j < mSystem.mNodes.size(); ++j) {
416 val += sol_V.coeff(j) * (G(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)) +
417 B(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)));
418 }
419 return sol_V.coeff(k) * val;
420}
421
423 Real val = 0.0;
424 for (UInt j = 0; j < mSystem.mNodes.size(); ++j) {
425 val += sol_V.coeff(j) * (G(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)) -
426 B(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)));
427 }
428 return sol_V.coeff(k) * val;
429}
430
432 // calculates apparent power injection at slack buses flowing to other nodes (i.e. S_inj_to_other = S_inj - S_shunt, with S_inj = S_gen - S_load)
433 for (auto topoNode : mVDBuses) {
434 auto node_idx = topoNode->matrixNodeIndex();
435
436 // calculate power flowing out of the node into the admittance matrix (i.e. S_inj)
437 CPS::Complex I(0.0, 0.0);
438 for (UInt j = 0; j < mSystem.mNodes.size(); ++j)
439 I += mY.coeff(node_idx, j) * sol_Vcx(j);
440 CPS::Complex S = sol_Vcx(node_idx) * conj(I);
441
442 // add load power to obtain generator power (S_gen = S_inj + S_load)
443 for (auto comp : mSystem.mComponentsAtNode[topoNode])
444 if (auto loadPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp))
445 S += Complex(**(loadPtr->mActivePowerPerUnit),
446 **(loadPtr->mReactivePowerPerUnit));
447
448 // Set power of either VD-type external network injection or VD-type synchronous generator depending on what is connected
449 for (auto comp : mSystem.mComponentsAtNode[topoNode]) {
450 if (auto extnetPtr =
451 std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(comp)) {
452 extnetPtr->updatePowerInjection(S * mBaseApparentPower);
453 break;
454 }
455 if (auto sgPtr =
456 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
457 comp)) {
458 sgPtr->updatePowerInjection(S * mBaseApparentPower);
459 break;
460 }
461 }
462
463 // Subtracting shunt power to obtain power injection flowing from this node to the other nodes
464 // FIXME: this calculates here S_gen-S_shunt, which is equal to S_inj_to_other+S_load, but generally not equal to S_inj_to_other
465 CPS::Real V = sol_V.coeff(node_idx);
466 for (auto comp : mSystem.mComponentsAtNode[topoNode])
467 if (auto shuntPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Shunt>(comp))
468 // capacitive susceptance is positive --> q is injected into the node
469 S += std::pow(V, 2) * Complex(-**(shuntPtr->mConductancePerUnit),
470 **(shuntPtr->mSusceptancePerUnit));
471
472 // TODO: check whether S_inj_to_other+S_load should be stored here in sol_P and sol_Q or rather S_inj
473 sol_P(node_idx) = S.real();
474 sol_Q(node_idx) = S.imag();
475 }
476}
477
479 // calculates apparent power injection at PV buses flowing to other nodes (i.e. S_inj_to_other = S_inj - S_shunt, with S_inj = S_gen - S_load)
480 for (auto topoNode : mPVBuses) {
481 auto node_idx = topoNode->matrixNodeIndex();
482
483 // calculate power flowing out of the node into the admittance matrix (i.e. S_inj)
484 CPS::Complex I(0.0, 0.0);
485 for (UInt j = 0; j < mSystem.mNodes.size(); ++j)
486 I += mY.coeff(node_idx, j) * sol_Vcx(j);
487 Complex S = sol_Vcx(node_idx) * conj(I);
488
489 // add load power to obtain generator power (S_gen = S_inj + S_load)
490 auto Sgen = S;
491 for (auto comp : mSystem.mComponentsAtNode[topoNode])
492 if (auto loadPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp))
493 Sgen += Complex(**(loadPtr->mActivePowerPerUnit),
494 **(loadPtr->mReactivePowerPerUnit));
495
496 // Set power of generator
497 for (auto comp : mSystem.mComponentsAtNode[topoNode])
498 if (auto sgPtr =
499 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(comp))
500 sgPtr->updatePowerInjection(Sgen * mBaseApparentPower);
501
502 // Subtracting shunt power to obtain power injection flowing from this node to the other nodes (i.e. S_inj_to_other = S_inj - S_shunt)
503 CPS::Real V = sol_V.coeff(node_idx);
504 for (auto comp : mSystem.mComponentsAtNode[topoNode])
505 if (auto shuntPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Shunt>(comp))
506 // capacitive susceptance is positive --> q is injected into the node
507 S += std::pow(V, 2) * Complex(-**(shuntPtr->mConductancePerUnit),
508 **(shuntPtr->mSusceptancePerUnit));
509
510 // TODO: check whether Q_inj_to_other should be stored in sol_Q or rather Q_inj
511 sol_Q(node_idx) = S.imag();
512 }
513}
514
516 // calculates apparent power injection at PQ buses flowing to other nodes (i.e. S_inj_to_other = S_inj - S_shunt, with S_inj = S_gen - S_load)
517 for (auto topoNode : mPQBuses) {
518 auto node_idx = topoNode->matrixNodeIndex();
519
520 // calculate power flowing out of the node into the admittance matrix (i.e. S_inj)
521 CPS::Complex I(0.0, 0.0);
522 for (UInt j = 0; j < mSystem.mNodes.size(); ++j)
523 I += mY.coeff(node_idx, j) * sol_Vcx(j);
524 CPS::Complex S = sol_Vcx(node_idx) * conj(I);
525
526 // Subtracting shunt power to obtain power injection flowing from this node to the other nodes (i.e. S_inj_to_other)
527 CPS::Real V = sol_V.coeff(node_idx);
528 for (auto comp : mSystem.mComponentsAtNode[topoNode])
529 if (auto shuntPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Shunt>(comp))
530 // capacitive susceptance is positive --> q is injected into the node
531 S += std::pow(V, 2) * Complex(-**(shuntPtr->mConductancePerUnit),
532 **(shuntPtr->mSusceptancePerUnit));
533
534 // TODO: check whether S_inj_to_other should be stored in sol_P and sol_Q or rather S_inj
535 sol_P(node_idx) = S.real();
536 sol_Q(node_idx) = S.imag();
537 }
538}
539
541 sol_P = CPS::Vector(n);
542 sol_Q = CPS::Vector(n);
543 sol_V = CPS::Vector(n);
544 sol_D = CPS::Vector(n);
545 sol_P.setZero(n);
546 sol_Q.setZero(n);
547 sol_V.setZero(n);
548 sol_D.setZero(n);
549}
550
552 sol_S_complex = CPS::VectorComp(n);
553 sol_V_complex = CPS::VectorComp(n);
554 sol_S_complex.setZero(n);
555 sol_V_complex.setZero(n);
556}
557
558CPS::Real PFSolverPowerPolar::sol_Vr(UInt k) {
559 return sol_V.coeff(k) * cos(sol_D.coeff(k));
560}
561
562CPS::Real PFSolverPowerPolar::sol_Vi(UInt k) {
563 return sol_V.coeff(k) * sin(sol_D.coeff(k));
564}
565
566CPS::Complex PFSolverPowerPolar::sol_Vcx(UInt k) {
567 return CPS::Complex(sol_Vr(k), sol_Vi(k));
568}
CPS::TopologicalNode::List mPQBuses
Vector of nodes characterized as PQ buses.
Definition PFSolver.h:32
UInt mNumPQBuses
Number of PQ nodes.
Definition PFSolver.h:24
std::vector< std::shared_ptr< CPS::SP::Ph1::PiLine > > mLines
Vector of line components.
Definition PFSolver.h:69
std::vector< std::shared_ptr< CPS::SP::Ph1::SynchronGenerator > > mSynchronGenerators
Vector of synchronous generator components.
Definition PFSolver.h:65
std::vector< std::shared_ptr< CPS::SP::Ph1::Transformer > > mTransformers
Vector of transformer components.
Definition PFSolver.h:59
CPS::Matrix mJ
Jacobian matrix.
Definition PFSolver.h:50
CPS::Vector mX
Solution vector.
Definition PFSolver.h:52
CPS::Bool solutionInitialized
Flag whether solution vectors are initialized.
Definition PFSolver.h:91
CPS::Real mBaseApparentPower
Base power of per-unit system.
Definition PFSolver.h:87
CPS::SparseMatrixCompRow mY
Admittance matrix.
Definition PFSolver.h:47
CPS::Bool solutionComplexInitialized
Flag whether complex solution vectors are initialized.
Definition PFSolver.h:93
UInt mNumPVBuses
Number of PV nodes.
Definition PFSolver.h:26
CPS::Real B(int i, int j)
Gets the imaginary part of admittance matrix element.
Definition PFSolver.cpp:432
CPS::Bool isConverged
Convergence flag.
Definition PFSolver.h:89
CPS::Vector mF
Vector of mismatch values.
Definition PFSolver.h:54
CPS::UInt mIterations
Actual number of iterations.
Definition PFSolver.h:85
PFSolver(CPS::String name, CPS::SystemTopology system, Real timeStep, CPS::Logger::Level logLevel)
Constructor to be used in simulation examples.
Definition PFSolver.cpp:16
CPS::SystemTopology mSystem
System list.
Definition PFSolver.h:57
std::map< CPS::TopologicalNode::Ptr, CPS::Real > mBaseVoltageAtNode
Map providing determined base voltages for each node.
Definition PFSolver.h:78
CPS::TopologicalNode::List mVDBuses
Vector of nodes characterized as VD buses.
Definition PFSolver.h:36
CPS::TopologicalNode::List mPVBuses
Vector of nodes characterized as PV buses.
Definition PFSolver.h:34
CPS::Real G(int i, int j)
Gets the real part of admittance matrix element.
Definition PFSolver.cpp:430
std::vector< CPS::UInt > mPQPVBusIndices
Vector with indices of both PQ and PV buses.
Definition PFSolver.h:44
CPS::Vector sol_P
Solution vector of active power.
void resize_complex_sol(CPS::Int n)
Resize complex solution vector.
void calculateBranchFlow()
Calculate branch flows from current solution and store them in line and transformer components.
void setSolution()
Set final solution.
void calculateQAtPVBuses()
Calculate the reactive power at all PV buses from current solution.
void generateInitialSolution(Real time, bool keep_last_solution=false)
Generate initial solution for current time step.
CPS::VectorComp sol_S_complex
Solution vector of representing sol_P and sol_Q as complex quantity.
PFSolverPowerPolar(CPS::String name, const CPS::SystemTopology &system, CPS::Real timeStep, CPS::Logger::Level logLevel)
Constructor to be used in simulation examples.
void updateSolution()
Update solution in each iteration.
CPS::Vector sol_D
Solution vector of voltage angle.
CPS::Real sol_Vi(CPS::UInt k)
Calculate imaginary part of voltage from sol_V and sol_D.
void calculateJacobian()
Calculate the Jacobian.
void calculatePAndQAtSlackBus()
Calculate P and Q at slack bus from current solution.
CPS::Vector sol_Q
Solution vector of reactive power.
CPS::Real Q(CPS::UInt k)
Calculate the reactive power at a bus from current solution.
CPS::Complex sol_Vcx(CPS::UInt k)
Calculate complex voltage from sol_V and sol_D.
void calculateMismatch()
Calculate mismatch.
void resize_sol(CPS::Int n)
Resize solution vector.
CPS::Real sol_Vr(CPS::UInt k)
Calculate real part of voltage from sol_V and sol_D.
CPS::Real P(CPS::UInt k)
Calculate active power at a bus from current solution.
void calculateNodalInjection()
Calculate nodal power injections and store them in first line or transformer (in case no line is conn...
CPS::Vector sol_V
Solution vector of voltage magnitude.
void calculatePAndQInjectionPQBuses()
Calculate complex power flowing from this node to the other nodes.
CPS::VectorComp sol_V_complex
Solution vector of representing sol_V and sol_D as complex quantity.
CPS::Logger::Log mSLog
Logger.
Definition Solver.h:45