DPsim
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 
11 using namespace DPsim;
12 using 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());
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,
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  }
66  sol_S_complex(pq->matrixNodeIndex()) = CPS::Complex(
67  sol_P[pq->matrixNodeIndex()], sol_Q[pq->matrixNodeIndex()]);
68  }
69  }
70 
71  for (auto pv : mPVBuses) {
72  if (!keep_last_solution) {
73  sol_Q(pv->matrixNodeIndex()) = 0;
74  sol_D(pv->matrixNodeIndex()) = 0;
75  }
76  for (auto comp : mSystem.mComponentsAtNode[pv]) {
77  if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
78  std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
79  comp)) {
80  sol_P(pv->matrixNodeIndex()) +=
81  gen->attributeTyped<CPS::Real>("P_set_pu")->get();
82  sol_V(pv->matrixNodeIndex()) =
83  gen->attributeTyped<CPS::Real>("V_set_pu")->get();
84  } else if (std::shared_ptr<CPS::SP::Ph1::Load> load =
85  std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
86  sol_P(pv->matrixNodeIndex()) -=
87  load->attributeTyped<CPS::Real>("P_pu")->get();
88  } else if (std::shared_ptr<CPS::SP::Ph1::AvVoltageSourceInverterDQ> vsi =
89  std::dynamic_pointer_cast<
91  sol_P(pv->matrixNodeIndex()) +=
92  vsi->attributeTyped<CPS::Real>("P_ref")->get() / mBaseApparentPower;
93  } else if (std::shared_ptr<CPS::SP::Ph1::NetworkInjection> extnet =
94  std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(
95  comp)) {
96  sol_P(pv->matrixNodeIndex()) +=
97  extnet->attributeTyped<CPS::Real>("p_inj")->get() /
99  sol_V(pv->matrixNodeIndex()) =
100  extnet->attributeTyped<CPS::Real>("V_set_pu")->get();
101  }
102  sol_S_complex(pv->matrixNodeIndex()) = CPS::Complex(
103  sol_P[pv->matrixNodeIndex()], sol_Q[pv->matrixNodeIndex()]);
104  sol_V_complex(pv->matrixNodeIndex()) = CPS::Complex(
105  sol_V[pv->matrixNodeIndex()], sol_D[pv->matrixNodeIndex()]);
106  }
107  }
108 
109  for (auto vd : mVDBuses) {
110  sol_P(vd->matrixNodeIndex()) = 0.0;
111  sol_Q(vd->matrixNodeIndex()) = 0.0;
112  sol_V(vd->matrixNodeIndex()) = 1.0;
113  sol_D(vd->matrixNodeIndex()) = 0.0;
114 
115  // if external injection at VD bus, reset the voltage to injection's voltage set-point
116  for (auto comp : mSystem.mComponentsAtNode[vd]) {
117  if (std::shared_ptr<CPS::SP::Ph1::NetworkInjection> extnet =
118  std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(comp)) {
119  sol_V(vd->matrixNodeIndex()) =
120  extnet->attributeTyped<CPS::Real>("V_set_pu")->get();
121  sol_P(vd->matrixNodeIndex()) +=
122  extnet->attributeTyped<CPS::Real>("p_inj")->get() /
123  mBaseApparentPower; // Todo add p_set q_set to extnet
124  sol_Q(vd->matrixNodeIndex()) +=
125  extnet->attributeTyped<CPS::Real>("q_inj")->get() /
127  }
128 
129  // if load at VD bus, substract P and Q
130  else if (std::shared_ptr<CPS::SP::Ph1::Load> load =
131  std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
132  sol_P(vd->matrixNodeIndex()) -=
133  load->attributeTyped<CPS::Real>("P_pu")->get();
134  sol_Q(vd->matrixNodeIndex()) -=
135  load->attributeTyped<CPS::Real>("Q_pu")->get();
136  }
137 
138  // if generator at VD, add P_set Q_Set
139  else if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
140  std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
141  comp)) {
142  sol_P(vd->matrixNodeIndex()) +=
143  gen->attributeTyped<CPS::Real>("P_set_pu")->get();
144  sol_Q(vd->matrixNodeIndex()) +=
145  gen->attributeTyped<CPS::Real>("Q_set_pu")->get();
146  }
147  }
148 
149  // if generator at VD bus, reset the voltage to generator's set-point
150  if (!mSynchronGenerators.empty()) {
151  for (auto gen : mSynchronGenerators) {
152  if (gen->node(0)->matrixNodeIndex() == vd->matrixNodeIndex())
153  sol_V(vd->matrixNodeIndex()) =
154  gen->attributeTyped<CPS::Real>("V_set_pu")->get();
155  }
156  }
157 
158  sol_S_complex(vd->matrixNodeIndex()) = CPS::Complex(
159  sol_P[vd->matrixNodeIndex()], sol_Q[vd->matrixNodeIndex()]);
160  sol_V_complex(vd->matrixNodeIndex()) = CPS::Complex(
161  sol_V[vd->matrixNodeIndex()], sol_D[vd->matrixNodeIndex()]);
162  }
163 
164  solutionInitialized = true;
166 
167  Pesp = sol_P;
168  Qesp = sol_Q;
169 
170  SPDLOG_LOGGER_INFO(mSLog, "#### Initial solution: ");
171  SPDLOG_LOGGER_INFO(mSLog, "P\t\tQ\t\tV\t\tD");
172  for (UInt i = 0; i < mSystem.mNodes.size(); ++i) {
173  SPDLOG_LOGGER_INFO(mSLog, "{}\t{}\t{}\t{}", sol_P[i], sol_Q[i], sol_V[i],
174  sol_D[i]);
175  }
176  mSLog->flush();
177 }
178 
180  UInt npqpv = mNumPQBuses + mNumPVBuses;
181  UInt k;
182  mF.setZero();
183 
184  for (UInt a = 0; a < npqpv; ++a) {
185  // For PQ and PV buses calculate active power mismatch
186  k = mPQPVBusIndices[a];
187  mF(a) = Pesp.coeff(k) - P(k);
188 
189  //only for PQ buses calculate reactive power mismatch
190  if (a < mNumPQBuses)
191  mF(a + npqpv) = Qesp.coeff(k) - Q(k);
192  }
193 }
194 
196  UInt npqpv = mNumPQBuses + mNumPVBuses;
197  double val;
198  UInt k, j;
199  UInt da, db;
200 
201  mJ.setZero();
202 
203  //J1
204  for (UInt a = 0; a < npqpv; ++a) { //rows
205  k = mPQPVBusIndices[a];
206  //diagonal
207  mJ.coeffRef(a, a) = -Q(k) - B(k, k) * sol_V.coeff(k) * sol_V.coeff(k);
208 
209  //non diagonal elements
210  for (UInt b = 0; b < npqpv; ++b) {
211  if (b != a) {
212  j = mPQPVBusIndices[b];
213  val = sol_V.coeff(k) * sol_V.coeff(j) *
214  (G(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)) -
215  B(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)));
216  //if (val != 0.0)
217  mJ.coeffRef(a, b) = val;
218  }
219  }
220  }
221 
222  //J2
223  da = 0;
224  db = npqpv;
225  for (UInt a = 0; a < npqpv; ++a) { //rows
226  k = mPQPVBusIndices[a];
227  //diagonal
228  //std::cout << "J2D:" << (a + da) << "," << (a + db) << std::endl;
229  if (a < mNumPQBuses)
230  mJ.coeffRef(a + da, a + db) =
231  P(k) + G(k, k) * sol_V.coeff(k) * sol_V.coeff(k);
232 
233  //non diagonal elements
234  for (UInt b = 0; b < mNumPQBuses; ++b) {
235  if (b != a) {
236  j = mPQPVBusIndices[b];
237  val = sol_V.coeff(k) * sol_V.coeff(j) *
238  (G(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)) +
239  B(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)));
240  //if (val != 0.0)
241  //std::cout << "J2ij:" << (a + da) << "," << (b + db) << std::endl;
242  mJ.coeffRef(a + da, b + db) = val;
243  }
244  }
245  }
246 
247  //J3
248  da = npqpv;
249  db = 0;
250  for (UInt a = 0; a < mNumPQBuses; ++a) { //rows
251  k = mPQPVBusIndices[a];
252  //diagonal
253  //std::cout << "J3:" << (a + da) << "," << (a + db) << std::endl;
254  mJ.coeffRef(a + da, a + db) =
255  P(k) - G(k, k) * sol_V.coeff(k) * sol_V.coeff(k);
256 
257  //non diagonal elements
258  for (UInt b = 0; b < npqpv; ++b) {
259  if (b != a) {
260  j = mPQPVBusIndices[b];
261  val = sol_V.coeff(k) * sol_V.coeff(j) *
262  (G(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)) +
263  B(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)));
264  //if (val != 0.0)
265  //std::cout << "J3:" << (a + da) << "," << (b + db) << std::endl;
266  mJ.coeffRef(a + da, b + db) = -val;
267  }
268  }
269  }
270 
271  //J4
272  da = npqpv;
273  db = npqpv;
274  for (UInt a = 0; a < mNumPQBuses; ++a) { //rows
275  k = mPQPVBusIndices[a];
276  //diagonal
277  //std::cout << "J4:" << (a + da) << "," << (a + db) << std::endl;
278  mJ.coeffRef(a + da, a + db) =
279  Q(k) - B(k, k) * sol_V.coeff(k) * sol_V.coeff(k);
280 
281  //non diagonal elements
282  for (UInt b = 0; b < mNumPQBuses; ++b) {
283  if (b != a) {
284  j = mPQPVBusIndices[b];
285  val = sol_V.coeff(k) * sol_V.coeff(j) *
286  (G(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)) -
287  B(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)));
288  if (val != 0.0) {
289  //std::cout << "J4:" << (a + da) << "," << (b + db) << std::endl;
290  mJ.coeffRef(a + da, b + db) = val;
291  }
292  }
293  }
294  }
295 }
296 
298  UInt npqpv = mNumPQBuses + mNumPVBuses;
299  UInt k;
300 
301  for (UInt a = 0; a < npqpv; ++a) {
302  k = mPQPVBusIndices[a];
303  sol_D(k) += mX.coeff(a);
304 
305  if (a < mNumPQBuses)
306  sol_V(k) = sol_V.coeff(k) * (1.0 + mX.coeff(a + npqpv));
307  }
308 
309  //Correct for PV buses
310  for (UInt i = mNumPQBuses; i < npqpv; ++i) {
311  k = mPQPVBusIndices[i];
312  Complex v = sol_Vcx(k);
313  // v *= Model.buses[k].v_set_point / abs(v);
314  sol_V(k) = abs(v);
315  sol_D(k) = arg(v);
316  }
317 }
318 
320  if (!isConverged) {
321  SPDLOG_LOGGER_INFO(mSLog, "Not converged within {} iterations",
322  mIterations);
323  } else {
327  SPDLOG_LOGGER_INFO(mSLog, "converged in {} iterations", mIterations);
328  SPDLOG_LOGGER_INFO(mSLog, "Solution: ");
329  SPDLOG_LOGGER_INFO(mSLog, "P\t\tQ\t\tV\t\tD");
330  for (UInt i = 0; i < mSystem.mNodes.size(); ++i) {
331  SPDLOG_LOGGER_INFO(mSLog, "{}\t{}\t{}\t{}", sol_P[i], sol_Q[i], sol_V[i],
332  sol_D[i]);
333  }
334  }
335  for (UInt i = 0; i < mSystem.mNodes.size(); ++i) {
336  sol_S_complex(i) = CPS::Complex(sol_P.coeff(i), sol_Q.coeff(i));
337  sol_V_complex(i) = CPS::Complex(sol_V.coeff(i) * cos(sol_D.coeff(i)),
338  sol_V.coeff(i) * sin(sol_D.coeff(i)));
339  }
340 
341  // update voltage and power at each node
342  for (auto node : mSystem.mNodes) {
343  std::dynamic_pointer_cast<CPS::SimNode<CPS::Complex>>(node)->setVoltage(
344  sol_V_complex(node->matrixNodeIndex()) * mBaseVoltageAtNode[node]);
345  std::dynamic_pointer_cast<CPS::SimNode<CPS::Complex>>(node)->setPower(
346  sol_S_complex(node->matrixNodeIndex()) * mBaseApparentPower);
347  }
350 }
351 
353  for (auto line : mLines) {
354  VectorComp v(2);
355  v(0) = sol_V_complex.coeff(line->node(0)->matrixNodeIndex());
356  v(1) = sol_V_complex.coeff(line->node(1)->matrixNodeIndex());
358  VectorComp current = line->Y_element() * v;
360  VectorComp flow_on_branch = v.array() * current.conjugate().array();
361  line->updateBranchFlow(current, flow_on_branch);
362  }
363  for (auto trafo : mTransformers) {
364  VectorComp v(2);
365  v(0) = sol_V_complex.coeff(trafo->node(0)->matrixNodeIndex());
366  v(1) = sol_V_complex.coeff(trafo->node(1)->matrixNodeIndex());
368  VectorComp current = trafo->Y_element() * v;
370  VectorComp flow_on_branch = v.array() * current.conjugate().array();
371  trafo->updateBranchFlow(current, flow_on_branch);
372  }
373 }
374 
376  for (auto node : mSystem.mNodes) {
377  std::list<std::shared_ptr<CPS::SP::Ph1::PiLine>> lines;
378  for (auto comp : mSystem.mComponentsAtNode[node]) {
379  if (std::shared_ptr<CPS::SP::Ph1::PiLine> line =
380  std::dynamic_pointer_cast<CPS::SP::Ph1::PiLine>(comp)) {
381  line->storeNodalInjection(sol_S_complex.coeff(node->matrixNodeIndex()));
382  lines.push_back(line);
383  break;
384  }
385  }
386  if (lines.empty()) {
387  for (auto comp : mSystem.mComponentsAtNode[node]) {
388  if (std::shared_ptr<CPS::SP::Ph1::Transformer> trafo =
389  std::dynamic_pointer_cast<CPS::SP::Ph1::Transformer>(comp)) {
390  trafo->storeNodalInjection(
391  sol_S_complex.coeff(node->matrixNodeIndex()));
392  break;
393  }
394  }
395  }
396  }
397 }
398 
399 Real PFSolverPowerPolar::P(UInt k) {
400  Real val = 0.0;
401  for (UInt j = 0; j < mSystem.mNodes.size(); ++j) {
402  val += sol_V.coeff(j) * (G(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)) +
403  B(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)));
404  }
405  return sol_V.coeff(k) * val;
406 }
407 
408 Real PFSolverPowerPolar::Q(UInt k) {
409  Real val = 0.0;
410  for (UInt j = 0; j < mSystem.mNodes.size(); ++j) {
411  val += sol_V.coeff(j) * (G(k, j) * sin(sol_D.coeff(k) - sol_D.coeff(j)) -
412  B(k, j) * cos(sol_D.coeff(k) - sol_D.coeff(j)));
413  }
414  return sol_V.coeff(k) * val;
415 }
416 
418  // 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)
419  for (auto topoNode : mVDBuses) {
420  auto node_idx = topoNode->matrixNodeIndex();
421 
422  // calculate power flowing out of the node into the admittance matrix (i.e. S_inj)
423  CPS::Complex I(0.0, 0.0);
424  for (UInt j = 0; j < mSystem.mNodes.size(); ++j)
425  I += mY.coeff(node_idx, j) * sol_Vcx(j);
426  CPS::Complex S = sol_Vcx(node_idx) * conj(I);
427 
428  // add load power to obtain generator power (S_gen = S_inj + S_load)
429  for (auto comp : mSystem.mComponentsAtNode[topoNode])
430  if (auto loadPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp))
431  S += Complex(**(loadPtr->mActivePowerPerUnit),
432  **(loadPtr->mReactivePowerPerUnit));
433 
434  // Set power of either VD-type external network injection or VD-type synchronous generator depending on what is connected
435  for (auto comp : mSystem.mComponentsAtNode[topoNode]) {
436  if (auto extnetPtr =
437  std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(comp)) {
438  extnetPtr->updatePowerInjection(S * mBaseApparentPower);
439  break;
440  }
441  if (auto sgPtr =
442  std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
443  comp)) {
444  sgPtr->updatePowerInjection(S * mBaseApparentPower);
445  break;
446  }
447  }
448 
449  // Subtracting shunt power to obtain power injection flowing from this node to the other nodes
450  // 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
451  CPS::Real V = sol_V.coeff(node_idx);
452  for (auto comp : mSystem.mComponentsAtNode[topoNode])
453  if (auto shuntPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Shunt>(comp))
454  // capacitive susceptance is positive --> q is injected into the node
455  S += std::pow(V, 2) * Complex(-**(shuntPtr->mConductancePerUnit),
456  **(shuntPtr->mSusceptancePerUnit));
457 
458  // TODO: check whether S_inj_to_other+S_load should be stored here in sol_P and sol_Q or rather S_inj
459  sol_P(node_idx) = S.real();
460  sol_Q(node_idx) = S.imag();
461  }
462 }
463 
465  // 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)
466  for (auto topoNode : mPVBuses) {
467  auto node_idx = topoNode->matrixNodeIndex();
468 
469  // calculate power flowing out of the node into the admittance matrix (i.e. S_inj)
470  CPS::Complex I(0.0, 0.0);
471  for (UInt j = 0; j < mSystem.mNodes.size(); ++j)
472  I += mY.coeff(node_idx, j) * sol_Vcx(j);
473  Complex S = sol_Vcx(node_idx) * conj(I);
474 
475  // add load power to obtain generator power (S_gen = S_inj + S_load)
476  auto Sgen = S;
477  for (auto comp : mSystem.mComponentsAtNode[topoNode])
478  if (auto loadPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp))
479  Sgen += Complex(**(loadPtr->mActivePowerPerUnit),
480  **(loadPtr->mReactivePowerPerUnit));
481 
482  // Set power of generator
483  for (auto comp : mSystem.mComponentsAtNode[topoNode])
484  if (auto sgPtr =
485  std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(comp))
486  sgPtr->updatePowerInjection(Sgen * mBaseApparentPower);
487 
488  // 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)
489  CPS::Real V = sol_V.coeff(node_idx);
490  for (auto comp : mSystem.mComponentsAtNode[topoNode])
491  if (auto shuntPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Shunt>(comp))
492  // capacitive susceptance is positive --> q is injected into the node
493  S += std::pow(V, 2) * Complex(-**(shuntPtr->mConductancePerUnit),
494  **(shuntPtr->mSusceptancePerUnit));
495 
496  // TODO: check whether Q_inj_to_other should be stored in sol_Q or rather Q_inj
497  sol_Q(node_idx) = S.imag();
498  }
499 }
500 
502  // 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)
503  for (auto topoNode : mPQBuses) {
504  auto node_idx = topoNode->matrixNodeIndex();
505 
506  // calculate power flowing out of the node into the admittance matrix (i.e. S_inj)
507  CPS::Complex I(0.0, 0.0);
508  for (UInt j = 0; j < mSystem.mNodes.size(); ++j)
509  I += mY.coeff(node_idx, j) * sol_Vcx(j);
510  CPS::Complex S = sol_Vcx(node_idx) * conj(I);
511 
512  // Subtracting shunt power to obtain power injection flowing from this node to the other nodes (i.e. S_inj_to_other)
513  CPS::Real V = sol_V.coeff(node_idx);
514  for (auto comp : mSystem.mComponentsAtNode[topoNode])
515  if (auto shuntPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Shunt>(comp))
516  // capacitive susceptance is positive --> q is injected into the node
517  S += std::pow(V, 2) * Complex(-**(shuntPtr->mConductancePerUnit),
518  **(shuntPtr->mSusceptancePerUnit));
519 
520  // TODO: check whether S_inj_to_other should be stored in sol_P and sol_Q or rather S_inj
521  sol_P(node_idx) = S.real();
522  sol_Q(node_idx) = S.imag();
523  }
524 }
525 
527  sol_P = CPS::Vector(n);
528  sol_Q = CPS::Vector(n);
529  sol_V = CPS::Vector(n);
530  sol_D = CPS::Vector(n);
531  sol_P.setZero(n);
532  sol_Q.setZero(n);
533  sol_V.setZero(n);
534  sol_D.setZero(n);
535 }
536 
538  sol_S_complex = CPS::VectorComp(n);
539  sol_V_complex = CPS::VectorComp(n);
540  sol_S_complex.setZero(n);
541  sol_V_complex.setZero(n);
542 }
543 
544 CPS::Real PFSolverPowerPolar::sol_Vr(UInt k) {
545  return sol_V.coeff(k) * cos(sol_D.coeff(k));
546 }
547 
548 CPS::Real PFSolverPowerPolar::sol_Vi(UInt k) {
549  return sol_V.coeff(k) * sin(sol_D.coeff(k));
550 }
551 
552 CPS::Complex PFSolverPowerPolar::sol_Vcx(UInt k) {
553  return CPS::Complex(sol_Vr(k), sol_Vi(k));
554 }
Real mSystemOmega
System angular frequency - omega.
IdentifiedObject::List mComponents
List of network components.
TopologicalNode::List mNodes
List of network nodes.
std::map< TopologicalNode::Ptr, TopologicalPowerComp::List > mComponentsAtNode
Map of network components connected to network nodes.
Solver class using the nonlinear powerflow (PF) formulation.
Definition: PFSolver.h:21
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:420
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
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:418
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:43