9 #include <dpsim/PFSolverPowerPolar.h>
11 using namespace DPsim;
17 CPS::Logger::Level logLevel)
18 :
PFSolver(name, system, timeStep, logLevel) {}
21 bool keep_last_solution) {
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) {
39 if (!keep_last_solution) {
40 sol_V(pq->matrixNodeIndex()) = 1.0;
41 sol_D(pq->matrixNodeIndex()) = 0.0;
43 sol_V[pq->matrixNodeIndex()],
sol_D[pq->matrixNodeIndex()]);
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<
61 sol_P(pq->matrixNodeIndex()) +=
63 sol_Q(pq->matrixNodeIndex()) +=
67 sol_P[pq->matrixNodeIndex()],
sol_Q[pq->matrixNodeIndex()]);
72 if (!keep_last_solution) {
73 sol_Q(pv->matrixNodeIndex()) = 0;
74 sol_D(pv->matrixNodeIndex()) = 0;
77 if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
78 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
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()) +=
93 }
else if (std::shared_ptr<CPS::SP::Ph1::NetworkInjection> extnet =
94 std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(
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();
103 sol_P[pv->matrixNodeIndex()],
sol_Q[pv->matrixNodeIndex()]);
105 sol_V[pv->matrixNodeIndex()],
sol_D[pv->matrixNodeIndex()]);
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;
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() /
124 sol_Q(vd->matrixNodeIndex()) +=
125 extnet->attributeTyped<CPS::Real>(
"q_inj")->get() /
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();
139 else if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
140 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
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();
152 if (gen->node(0)->matrixNodeIndex() == vd->matrixNodeIndex())
153 sol_V(vd->matrixNodeIndex()) =
154 gen->attributeTyped<CPS::Real>(
"V_set_pu")->get();
159 sol_P[vd->matrixNodeIndex()],
sol_Q[vd->matrixNodeIndex()]);
161 sol_V[vd->matrixNodeIndex()],
sol_D[vd->matrixNodeIndex()]);
170 SPDLOG_LOGGER_INFO(
mSLog,
"#### Initial solution: ");
171 SPDLOG_LOGGER_INFO(
mSLog,
"P\t\tQ\t\tV\t\tD");
184 for (UInt a = 0; a < npqpv; ++a) {
187 mF(a) = Pesp.coeff(k) -
P(k);
191 mF(a + npqpv) = Qesp.coeff(k) -
Q(k);
204 for (UInt a = 0; a < npqpv; ++a) {
207 mJ.coeffRef(a, a) = -
Q(k) -
B(k, k) *
sol_V.coeff(k) *
sol_V.coeff(k);
210 for (UInt b = 0; b < npqpv; ++b) {
217 mJ.coeffRef(a, b) = val;
225 for (UInt a = 0; a < npqpv; ++a) {
230 mJ.coeffRef(a + da, a + db) =
242 mJ.coeffRef(a + da, b + db) = val;
254 mJ.coeffRef(a + da, a + db) =
258 for (UInt b = 0; b < npqpv; ++b) {
266 mJ.coeffRef(a + da, b + db) = -val;
278 mJ.coeffRef(a + da, a + db) =
290 mJ.coeffRef(a + da, b + db) = val;
301 for (UInt a = 0; a < npqpv; ++a) {
306 sol_V(k) =
sol_V.coeff(k) * (1.0 +
mX.coeff(a + npqpv));
321 SPDLOG_LOGGER_INFO(
mSLog,
"Not converged within {} iterations",
328 SPDLOG_LOGGER_INFO(
mSLog,
"Solution: ");
329 SPDLOG_LOGGER_INFO(
mSLog,
"P\t\tQ\t\tV\t\tD");
343 std::dynamic_pointer_cast<CPS::SimNode<CPS::Complex>>(node)->setVoltage(
345 std::dynamic_pointer_cast<CPS::SimNode<CPS::Complex>>(node)->setPower(
353 for (
auto line :
mLines) {
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);
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);
377 std::list<std::shared_ptr<CPS::SP::Ph1::PiLine>> lines;
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);
388 if (std::shared_ptr<CPS::SP::Ph1::Transformer> trafo =
389 std::dynamic_pointer_cast<CPS::SP::Ph1::Transformer>(comp)) {
390 trafo->storeNodalInjection(
405 return sol_V.coeff(k) * val;
414 return sol_V.coeff(k) * val;
420 auto node_idx = topoNode->matrixNodeIndex();
423 CPS::Complex I(0.0, 0.0);
426 CPS::Complex S =
sol_Vcx(node_idx) * conj(I);
430 if (
auto loadPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp))
431 S += Complex(**(loadPtr->mActivePowerPerUnit),
432 **(loadPtr->mReactivePowerPerUnit));
437 std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(comp)) {
442 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
451 CPS::Real V =
sol_V.coeff(node_idx);
453 if (
auto shuntPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Shunt>(comp))
455 S += std::pow(V, 2) * Complex(-**(shuntPtr->mConductancePerUnit),
456 **(shuntPtr->mSusceptancePerUnit));
459 sol_P(node_idx) = S.real();
460 sol_Q(node_idx) = S.imag();
467 auto node_idx = topoNode->matrixNodeIndex();
470 CPS::Complex I(0.0, 0.0);
473 Complex S =
sol_Vcx(node_idx) * conj(I);
478 if (
auto loadPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp))
479 Sgen += Complex(**(loadPtr->mActivePowerPerUnit),
480 **(loadPtr->mReactivePowerPerUnit));
485 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(comp))
489 CPS::Real V =
sol_V.coeff(node_idx);
491 if (
auto shuntPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Shunt>(comp))
493 S += std::pow(V, 2) * Complex(-**(shuntPtr->mConductancePerUnit),
494 **(shuntPtr->mSusceptancePerUnit));
497 sol_Q(node_idx) = S.imag();
504 auto node_idx = topoNode->matrixNodeIndex();
507 CPS::Complex I(0.0, 0.0);
510 CPS::Complex S =
sol_Vcx(node_idx) * conj(I);
513 CPS::Real V =
sol_V.coeff(node_idx);
515 if (
auto shuntPtr = std::dynamic_pointer_cast<CPS::SP::Ph1::Shunt>(comp))
517 S += std::pow(V, 2) * Complex(-**(shuntPtr->mConductancePerUnit),
518 **(shuntPtr->mSusceptancePerUnit));
521 sol_P(node_idx) = S.real();
522 sol_Q(node_idx) = S.imag();
527 sol_P = CPS::Vector(n);
528 sol_Q = CPS::Vector(n);
529 sol_V = CPS::Vector(n);
530 sol_D = CPS::Vector(n);
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.
CPS::TopologicalNode::List mPQBuses
Vector of nodes characterized as PQ buses.
UInt mNumPQBuses
Number of PQ nodes.
std::vector< std::shared_ptr< CPS::SP::Ph1::PiLine > > mLines
Vector of line components.
std::vector< std::shared_ptr< CPS::SP::Ph1::SynchronGenerator > > mSynchronGenerators
Vector of synchronous generator components.
std::vector< std::shared_ptr< CPS::SP::Ph1::Transformer > > mTransformers
Vector of transformer components.
CPS::Matrix mJ
Jacobian matrix.
CPS::Vector mX
Solution vector.
CPS::Bool solutionInitialized
Flag whether solution vectors are initialized.
CPS::Real mBaseApparentPower
Base power of per-unit system.
CPS::SparseMatrixCompRow mY
Admittance matrix.
CPS::Bool solutionComplexInitialized
Flag whether complex solution vectors are initialized.
UInt mNumPVBuses
Number of PV nodes.
CPS::Real B(int i, int j)
Gets the imaginary part of admittance matrix element.
CPS::Bool isConverged
Convergence flag.
CPS::Vector mF
Vector of mismatch values.
CPS::UInt mIterations
Actual number of iterations.
CPS::SystemTopology mSystem
System list.
std::map< CPS::TopologicalNode::Ptr, CPS::Real > mBaseVoltageAtNode
Map providing determined base voltages for each node.
CPS::TopologicalNode::List mVDBuses
Vector of nodes characterized as VD buses.
CPS::TopologicalNode::List mPVBuses
Vector of nodes characterized as PV buses.
CPS::Real G(int i, int j)
Gets the real part of admittance matrix element.
std::vector< CPS::UInt > mPQPVBusIndices
Vector with indices of both PQ and PV buses.
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.