9#include <dpsim/PFSolver.h>
10#include <dpsim/SequentialScheduler.h>
17 CPS::Real timeStep, CPS::Logger::Level logLevel)
18 : Solver(name +
"_PF", logLevel) {
24 SPDLOG_LOGGER_INFO(
mSLog,
"#### INITIALIZATION OF POWERFLOW SOLVER ");
25 for (
auto comp :
mSystem.mComponents) {
26 if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
27 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(comp))
29 else if (std::shared_ptr<CPS::SP::Ph1::Load> load =
30 std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp))
32 else if (std::shared_ptr<CPS::SP::Ph1::Transformer> trafo =
33 std::dynamic_pointer_cast<CPS::SP::Ph1::Transformer>(comp))
35 else if (std::shared_ptr<CPS::SP::Ph1::PiLine> line =
36 std::dynamic_pointer_cast<CPS::SP::Ph1::PiLine>(comp))
38 else if (std::shared_ptr<CPS::SP::Ph1::NetworkInjection> extnet =
39 std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(
42 else if (std::shared_ptr<CPS::SP::Ph1::Shunt> shunt =
43 std::dynamic_pointer_cast<CPS::SP::Ph1::Shunt>(comp))
45 else if (std::shared_ptr<CPS::SP::Ph1::SolidStateTransformer> sst =
46 std::dynamic_pointer_cast<CPS::SP::Ph1::SolidStateTransformer>(
49 else if (std::shared_ptr<CPS::SP::Ph1::AvVoltageSourceInverterDQ> vsi =
50 std::dynamic_pointer_cast<
73 auto sparseJ =
mJ.sparseView();
74 Eigen::SparseLU<SparseMatrix> lu(sparseJ);
79 SPDLOG_LOGGER_INFO(
mSLog,
"Assigning simulation nodes to topology nodes:");
80 UInt matrixNodeIndexIdx = 0;
81 for (UInt idx = 0; idx <
mSystem.mNodes.size(); ++idx) {
82 mSystem.mNodes[idx]->setMatrixNodeIndex(0, matrixNodeIndexIdx);
83 SPDLOG_LOGGER_INFO(
mSLog,
"Node {}: MatrixNodeIndex {}",
85 mSystem.mNodes[idx]->matrixNodeIndex());
88 SPDLOG_LOGGER_INFO(
mSLog,
"Number of simulation nodes: {:d}",
93 for (
auto comp :
mSystem.mComponents) {
94 std::dynamic_pointer_cast<SimPowerComp<Complex>>(comp)
95 ->updateMatrixNodeIndices();
99 mSLog,
"-- Initialize components from terminals or nodes of topology");
100 for (
auto comp :
mSystem.mComponents) {
101 auto pComp = std::dynamic_pointer_cast<SimPowerComp<Complex>>(comp);
105 pComp->initializeFromNodesAndTerminals(
mSystem.mSystemFrequency);
108 SPDLOG_LOGGER_INFO(
mSLog,
109 "-- Calculate per unit parameters for all components");
114 for (
auto line :
mLines) {
123 for (
auto load :
mLoads) {
138 if (std::abs(gen->attributeTyped<Real>(
"P_set")->get()) > maxPower)
139 maxPower = std::abs(gen->attributeTyped<Real>(
"P_set")->get());
142 if (trafo->attributeTyped<Real>(
"S")->get() > maxPower)
143 maxPower = trafo->attributeTyped<Real>(
"S")->get();
149 SPDLOG_LOGGER_WARN(
mSLog,
150 "No suitable quantity found for setting "
151 "mBaseApparentPower. Using {} VA.",
162 SPDLOG_LOGGER_INFO(
mSLog,
"-- Determine powerflow bus type for each node");
165 for (
auto node :
mSystem.mNodes) {
166 bool connectedPV =
false;
167 bool connectedPQ =
false;
168 bool connectedVD =
false;
170 for (
auto comp :
mSystem.mComponentsAtNode[node]) {
171 if (std::shared_ptr<CPS::SP::Ph1::Load> load =
172 std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
173 if (load->mPowerflowBusType == CPS::PowerflowBusType::PQ) {
176 }
else if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
177 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
179 if (gen->mPowerflowBusType == CPS::PowerflowBusType::PV) {
181 }
else if (gen->mPowerflowBusType == CPS::PowerflowBusType::VD) {
184 }
else if (std::shared_ptr<CPS::SP::Ph1::NetworkInjection> extnet =
185 std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(
187 if (extnet->mPowerflowBusType == CPS::PowerflowBusType::VD) {
189 }
else if (extnet->mPowerflowBusType == CPS::PowerflowBusType::PV) {
197 if (!connectedPV && connectedPQ && !connectedVD) {
199 mSLog,
"{}: only PQ type component connected -> set as PQ bus",
204 else if (!connectedPV && !connectedPQ && !connectedVD) {
205 SPDLOG_LOGGER_INFO(
mSLog,
"{}: no component connected -> set as PQ bus",
210 else if (connectedPV && !connectedPQ && !connectedVD) {
212 mSLog,
"{}: only PV type component connected -> set as PV bus",
217 else if (connectedPV && connectedPQ && !connectedVD) {
219 mSLog,
"{}: PV and PQ type component connected -> set as PV bus",
224 else if (!connectedPV && !connectedPQ && connectedVD) {
226 mSLog,
"{}: only VD type component connected -> set as VD bus",
231 else if (connectedPV && !connectedPQ && connectedVD) {
233 mSLog,
"{}: VD and PV type component connect -> set as VD bus",
238 else if (connectedPV && connectedPQ && connectedVD) {
240 mSLog,
"{}: VD, PV and PQ type component connect -> set as VD bus",
245 std::stringstream ss;
246 ss <<
"Node>>" << node->name()
247 <<
": combination of connected components is invalid";
248 throw std::invalid_argument(ss.str());
264 SPDLOG_LOGGER_INFO(
mSLog,
"#### Create index vectors for power flow solver:");
272 SPDLOG_LOGGER_INFO(
mSLog,
"-- Determine base voltages for each node "
273 "according to connected components");
276 for (
auto node :
mSystem.mNodes) {
277 CPS::Real baseVoltage_ = 0;
278 for (
auto comp :
mSystem.mComponentsAtNode[node]) {
279 if (std::shared_ptr<CPS::SP::Ph1::AvVoltageSourceInverterDQ> vsi =
280 std::dynamic_pointer_cast<
282 baseVoltage_ = vsi->getNomVoltage();
285 "Choose base voltage {}V of {} to convert pu-solution of {}.",
286 baseVoltage_, vsi->name(), node->name());
288 }
else if (std::shared_ptr<CPS::SP::Ph1::RXLine> rxline =
289 std::dynamic_pointer_cast<CPS::SP::Ph1::RXLine>(comp)) {
290 baseVoltage_ = rxline->getBaseVoltage();
293 "Choose base voltage {}V of {} to convert pu-solution of {}.",
294 baseVoltage_, rxline->name(), node->name());
296 }
else if (std::shared_ptr<CPS::SP::Ph1::PiLine> line =
297 std::dynamic_pointer_cast<CPS::SP::Ph1::PiLine>(comp)) {
298 baseVoltage_ = line->getBaseVoltage();
301 "Choose base voltage {}V of {} to convert pu-solution of {}.",
302 baseVoltage_, line->name(), node->name());
304 }
else if (std::shared_ptr<CPS::SP::Ph1::Transformer> trans =
305 std::dynamic_pointer_cast<CPS::SP::Ph1::Transformer>(
307 if (trans->terminal(0)->node()->name() == node->name()) {
308 baseVoltage_ = trans->getNominalVoltageEnd1();
311 "Choose base voltage {}V of {} to convert pu-solution of {}.",
312 baseVoltage_, trans->name(), node->name());
314 }
else if (trans->terminal(1)->node()->name() == node->name()) {
315 baseVoltage_ = trans->getNominalVoltageEnd2();
318 "Choose base voltage {}V of {} to convert pu-solution of {}.",
319 baseVoltage_, trans->name(), node->name());
322 }
else if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
323 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
325 baseVoltage_ = gen->getBaseVoltage();
328 "Choose base voltage {}V of {} to convert pu-solution of {}.",
329 baseVoltage_, gen->name(), node->name());
331 }
else if (std::shared_ptr<CPS::SP::Ph1::Load> load =
332 std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
333 baseVoltage_ = load->getNomVoltage();
335 mSLog,
"Choose base voltage of {} V to convert pu-solution of {}.",
336 baseVoltage_, load->name(), node->name());
338 }
else if (std::shared_ptr<CPS::SP::Ph1::NetworkInjection> extnet =
339 std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(
341 baseVoltage_ = extnet->getBaseVoltage();
343 mSLog,
"Choose base voltage of {}V to convert pu-solution of {}.",
344 baseVoltage_, extnet->name(), node->name());
347 SPDLOG_LOGGER_WARN(
mSLog,
"Unable to get base voltage at {}",
356 for (
auto node :
mSystem.mNodes) {
361 SPDLOG_LOGGER_WARN(
mSLog,
"No base voltage entry for {}", node->name());
367 if (std::abs(it->second) < 1e-6) {
368 SPDLOG_LOGGER_WARN(
mSLog,
"Zero base voltage for {}", node->name());
374 SPDLOG_LOGGER_INFO(
mSLog,
"Base voltage summary: missing={}, zero={}",
375 numMissing, numZero);
381 mExternalGrids[0]->modifyPowerFlowBusType(CPS::PowerflowBusType::VD);
385 if (gen->node(0)->name() == name) {
386 gen->modifyPowerFlowBusType(CPS::PowerflowBusType::VD);
390 throw std::invalid_argument(
"Invalid slack bus, no external grid or "
391 "synchronous generator attached");
396 CPS::String name, CPS::PowerflowBusType powerFlowBusType) {
397 for (
auto comp :
mSystem.mComponents) {
398 if (comp->name() == name) {
399 if (std::shared_ptr<CPS::SP::Ph1::NetworkInjection> extnet =
400 std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(comp))
401 extnet->modifyPowerFlowBusType(powerFlowBusType);
402 else if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
403 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
405 gen->modifyPowerFlowBusType(powerFlowBusType);
412 if (
mBehaviour == Behaviour::Initialization) {
413 SPDLOG_LOGGER_INFO(
mSLog,
"-- Set solver behaviour to Initialization");
416 SPDLOG_LOGGER_INFO(
mSLog,
"-- Set component behaviour to Initialization");
417 for (
auto comp :
mSystem.mComponents) {
419 std::dynamic_pointer_cast<CPS::TopologicalPowerComp>(comp);
421 powerComp->setBehaviour(
422 TopologicalPowerComp::Behaviour::Initialization);
425 SPDLOG_LOGGER_INFO(
mSLog,
"-- Set solver behaviour to Simulation");
428 SPDLOG_LOGGER_INFO(
mSLog,
"-- Set component behaviour to PFSimulation");
429 for (
auto comp :
mSystem.mComponents) {
431 std::dynamic_pointer_cast<CPS::TopologicalPowerComp>(comp);
433 powerComp->setBehaviour(TopologicalPowerComp::Behaviour::PFSimulation);
441 mY = CPS::SparseMatrixComp(n, n);
442 for (
auto line :
mLines) {
443 line->pfApplyAdmittanceMatrixStamp(
mY);
447 if (**trans->mResistance == 0 && **trans->mInductance == 0) {
448 SPDLOG_LOGGER_INFO(
mSLog,
"{} {} ignored for R = 0 and L = 0",
449 trans->type(), trans->name());
452 trans->pfApplyAdmittanceMatrixStamp(
mY);
455 shunt->pfApplyAdmittanceMatrixStamp(
mY);
459 throw std::invalid_argument(
"There are no bus");
503 SPDLOG_LOGGER_DEBUG(
mSLog,
"Mismatch vector at iteration {}: \n {}", i,
mF);
513void PFSolver::SolveTask::execute(Real time, Int timeStepCount) {
521 return Task::List{std::make_shared<SolveTask>(*
this)};
void determinePFBusType()
Determine bus type for all buses.
std::vector< std::shared_ptr< CPS::SP::Ph1::Load > > mLoads
Vector of load components.
CPS::Bool mKeepLastSolution
Use last converged solution as initial guess.
CPS::TopologicalNode::List mPQBuses
Vector of nodes characterized as PQ buses.
UInt mNumPQBuses
Number of PQ nodes.
virtual void solveJacobianSystem()
Solve the linearized system mJ*mX = mF into mX; sparse subclass overrides.
UInt mNumVDBuses
Number of PV nodes.
Real mTolerance
Solver tolerance.
CPS::String logVector(std::vector< CPS::UInt > indexVector)
Logging for integer vectors.
std::vector< std::shared_ptr< CPS::SP::Ph1::PiLine > > mLines
Vector of line components.
CPS::Task::List getTasks() override
Get tasks for scheduler.
void assignMatrixNodeIndices()
Assignment of matrix indices for nodes.
std::vector< CPS::UInt > mVDBusIndices
Vector with indices of VD buses.
virtual void setUpJacobianStorage()
Allocate Jacobian storage; dense by default, sparse subclass overrides.
void initializeComponents()
Initialization of individual components.
std::vector< std::shared_ptr< CPS::SP::Ph1::SynchronGenerator > > mSynchronGenerators
Vector of synchronous generator components.
std::vector< CPS::UInt > mPQBusIndices
Vector with indices of PQ buses.
void modifyPowerFlowBusComponent(CPS::String name, CPS::PowerflowBusType powerFlowBusType)
Allows to modify the powerflow bus type of a specific component.
std::vector< std::shared_ptr< CPS::SP::Ph1::NetworkInjection > > mExternalGrids
Vector of external grid components.
std::vector< std::shared_ptr< CPS::SP::Ph1::SolidStateTransformer > > mSolidStateTransformers
Vector of solid state transformer components.
std::vector< CPS::UInt > mPVBusIndices
Vector with indices of PV buses.
void setVDNode(CPS::String name)
Set a node to VD using its name.
std::vector< std::shared_ptr< CPS::SP::Ph1::Transformer > > mTransformers
Vector of transformer components.
std::vector< std::shared_ptr< CPS::SP::Ph1::Shunt > > mShunts
Vector of shunt components.
CPS::Bool checkConvergence()
Check whether below tolerance.
CPS::Matrix mJ
Jacobian matrix.
CPS::UInt mMaxIterations
Maximum number of iterations.
CPS::Vector mX
Solution vector.
std::vector< std::shared_ptr< CPS::SP::Ph1::AvVoltageSourceInverterDQ > > mAverageVoltageSourceInverters
Vector of average voltage source inverters.
CPS::Real mBaseApparentPower
Base power of per-unit system.
void setBaseApparentPower()
Set apparent base power of per-unit system.
virtual void calculateMismatch()=0
Calculate mismatch.
CPS::SparseMatrixCompRow mY
Admittance matrix.
UInt mNumPVBuses
Number of PV nodes.
CPS::Real B(int i, int j)
Gets the imaginary part of admittance matrix element.
void composeAdmittanceMatrix()
Compose admittance matrix.
CPS::Bool isConverged
Convergence flag.
CPS::Vector mF
Vector of mismatch values.
CPS::UInt mIterations
Actual number of iterations.
PFSolver(CPS::String name, CPS::SystemTopology system, Real timeStep, CPS::Logger::Level logLevel)
Constructor to be used in simulation examples.
CPS::SystemTopology mSystem
System list.
virtual void calculateJacobian()=0
Calculate the Jacobian.
void determineNodeBaseVoltages()
Determine base voltages for each node.
void setSolverAndComponentBehaviour(Solver::Behaviour behaviour) override
set solver and component to initialization or simulation behaviour
std::map< CPS::TopologicalNode::Ptr, CPS::Real > mBaseVoltageAtNode
Map providing determined base voltages for each node.
virtual void setSolution()=0
Set final solution.
void initialize() override
Initialization of the solver.
virtual void generateInitialSolution(Real time, bool keep_last_solution=false)=0
Generate initial solution for current time step.
virtual void updateSolution()=0
Update solution in each iteration.
Bool solvePowerflow()
Solves the powerflow problem.
CPS::TopologicalNode::List mVDBuses
Vector of nodes characterized as VD buses.
CPS::TopologicalNode::List mPVBuses
Vector of nodes characterized as PV buses.
UInt mNumUnknowns
Number of unknowns, defining system dimension.
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.
Real mTimeStep
Time step for fixed step solvers.
Behaviour mBehaviour
Solver behaviour initialization or simulation.
CPS::Logger::Log mSLog
Logger.
Bool mInitFromNodesAndTerminals