9 #include <dpsim/PFSolver.h>
10 #include <dpsim/SequentialScheduler.h>
13 using namespace DPsim;
17 CPS::Real timeStep, CPS::Logger::Level logLevel)
18 :
Solver(name +
"_PF", logLevel) {
24 SPDLOG_LOGGER_INFO(
mSLog,
"#### INITIALIZATION OF POWERFLOW SOLVER ");
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<
69 SPDLOG_LOGGER_INFO(
mSLog,
"Assigning simulation nodes to topology nodes:");
70 UInt matrixNodeIndexIdx = 0;
72 mSystem.
mNodes[idx]->setMatrixNodeIndex(0, matrixNodeIndexIdx);
73 SPDLOG_LOGGER_INFO(
mSLog,
"Node {}: MatrixNodeIndex {}",
78 SPDLOG_LOGGER_INFO(
mSLog,
"Number of simulation nodes: {:d}",
84 std::dynamic_pointer_cast<SimPowerComp<Complex>>(comp)
85 ->updateMatrixNodeIndices();
89 mSLog,
"-- Initialize components from terminals or nodes of topology");
91 auto pComp = std::dynamic_pointer_cast<SimPowerComp<Complex>>(comp);
98 SPDLOG_LOGGER_INFO(
mSLog,
99 "-- Calculate per unit parameters for all components");
104 for (
auto line :
mLines) {
113 for (
auto load :
mLoads) {
128 if (std::abs(gen->attributeTyped<Real>(
"P_set")->get()) > maxPower)
129 maxPower = std::abs(gen->attributeTyped<Real>(
"P_set")->get());
132 if (trafo->attributeTyped<Real>(
"S")->get() > maxPower)
133 maxPower = trafo->attributeTyped<Real>(
"S")->get();
139 SPDLOG_LOGGER_WARN(
mSLog,
140 "No suitable quantity found for setting "
141 "mBaseApparentPower. Using {} VA.",
152 SPDLOG_LOGGER_INFO(
mSLog,
"-- Determine powerflow bus type for each node");
156 bool connectedPV =
false;
157 bool connectedPQ =
false;
158 bool connectedVD =
false;
161 if (std::shared_ptr<CPS::SP::Ph1::Load> load =
162 std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
163 if (load->mPowerflowBusType == CPS::PowerflowBusType::PQ) {
166 }
else if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
167 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
169 if (gen->mPowerflowBusType == CPS::PowerflowBusType::PV) {
171 }
else if (gen->mPowerflowBusType == CPS::PowerflowBusType::VD) {
174 }
else if (std::shared_ptr<CPS::SP::Ph1::NetworkInjection> extnet =
175 std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(
177 if (extnet->mPowerflowBusType == CPS::PowerflowBusType::VD) {
179 }
else if (extnet->mPowerflowBusType == CPS::PowerflowBusType::PV) {
187 if (!connectedPV && connectedPQ && !connectedVD) {
189 mSLog,
"{}: only PQ type component connected -> set as PQ bus",
194 else if (!connectedPV && !connectedPQ && !connectedVD) {
195 SPDLOG_LOGGER_DEBUG(
mSLog,
"{}: no component connected -> set as PQ bus",
200 else if (connectedPV && !connectedPQ && !connectedVD) {
202 mSLog,
"{}: only PV type component connected -> set as PV bus",
207 else if (connectedPV && connectedPQ && !connectedVD) {
209 mSLog,
"{}: PV and PQ type component connected -> set as PV bus",
214 else if (!connectedPV && !connectedPQ && connectedVD) {
216 mSLog,
"{}: only VD type component connected -> set as VD bus",
221 else if (connectedPV && !connectedPQ && connectedVD) {
223 mSLog,
"{}: VD and PV type component connect -> set as VD bus",
228 else if (connectedPV && connectedPQ && connectedVD) {
230 mSLog,
"{}: VD, PV and PQ type component connect -> set as VD bus",
235 std::stringstream ss;
236 ss <<
"Node>>" << node->name()
237 <<
": combination of connected components is invalid";
238 throw std::invalid_argument(ss.str());
254 SPDLOG_LOGGER_INFO(
mSLog,
"#### Create index vectors for power flow solver:");
262 SPDLOG_LOGGER_INFO(
mSLog,
"-- Determine base voltages for each node "
263 "according to connected components");
267 CPS::Real baseVoltage_ = 0;
269 if (std::shared_ptr<CPS::SP::Ph1::AvVoltageSourceInverterDQ> vsi =
270 std::dynamic_pointer_cast<
273 Math::abs(vsi->attributeTyped<CPS::Complex>(
"vnom")->get());
276 "Choose base voltage {}V of {} to convert pu-solution of {}.",
277 baseVoltage_, vsi->name(), node->name());
279 }
else if (std::shared_ptr<CPS::SP::Ph1::RXLine> rxline =
280 std::dynamic_pointer_cast<CPS::SP::Ph1::RXLine>(comp)) {
281 baseVoltage_ = rxline->attributeTyped<CPS::Real>(
"base_Voltage")->get();
284 "Choose base voltage {}V of {} to convert pu-solution of {}.",
285 baseVoltage_, rxline->name(), node->name());
287 }
else if (std::shared_ptr<CPS::SP::Ph1::PiLine> line =
288 std::dynamic_pointer_cast<CPS::SP::Ph1::PiLine>(comp)) {
289 baseVoltage_ = line->attributeTyped<CPS::Real>(
"base_Voltage")->get();
292 "Choose base voltage {}V of {} to convert pu-solution of {}.",
293 baseVoltage_, line->name(), node->name());
295 }
else if (std::shared_ptr<CPS::SP::Ph1::Transformer> trans =
296 std::dynamic_pointer_cast<CPS::SP::Ph1::Transformer>(
298 if (trans->terminal(0)->node()->name() == node->name()) {
300 trans->attributeTyped<CPS::Real>(
"nominal_voltage_end1")->get();
303 "Choose base voltage {}V of {} to convert pu-solution of {}.",
304 baseVoltage_, trans->name(), node->name());
306 }
else if (trans->terminal(1)->node()->name() == node->name()) {
308 trans->attributeTyped<CPS::Real>(
"nominal_voltage_end2")->get();
311 "Choose base voltage {}V of {} to convert pu-solution of {}.",
312 baseVoltage_, trans->name(), node->name());
315 }
else if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
316 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
318 baseVoltage_ = gen->attributeTyped<CPS::Real>(
"base_Voltage")->get();
321 "Choose base voltage {}V of {} to convert pu-solution of {}.",
322 baseVoltage_, gen->name(), node->name());
325 SPDLOG_LOGGER_WARN(
mSLog,
"Unable to get base voltage at {}",
336 mExternalGrids[0]->modifyPowerFlowBusType(CPS::PowerflowBusType::VD);
340 if (gen->node(0)->name() == name) {
341 gen->modifyPowerFlowBusType(CPS::PowerflowBusType::VD);
345 throw std::invalid_argument(
"Invalid slack bus, no external grid or "
346 "synchronous generator attached");
351 CPS::String name, CPS::PowerflowBusType powerFlowBusType) {
353 if (comp->name() == name) {
354 if (std::shared_ptr<CPS::SP::Ph1::NetworkInjection> extnet =
355 std::dynamic_pointer_cast<CPS::SP::Ph1::NetworkInjection>(comp))
356 extnet->modifyPowerFlowBusType(powerFlowBusType);
357 else if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen =
358 std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(
360 gen->modifyPowerFlowBusType(powerFlowBusType);
367 if (
mBehaviour == Behaviour::Initialization) {
368 SPDLOG_LOGGER_INFO(
mSLog,
"-- Set solver behaviour to Initialization");
371 SPDLOG_LOGGER_INFO(
mSLog,
"-- Set component behaviour to Initialization");
374 std::dynamic_pointer_cast<CPS::TopologicalPowerComp>(comp);
376 powerComp->setBehaviour(
377 TopologicalPowerComp::Behaviour::Initialization);
380 SPDLOG_LOGGER_INFO(
mSLog,
"-- Set solver behaviour to Simulation");
383 SPDLOG_LOGGER_INFO(
mSLog,
"-- Set component behaviour to PFSimulation");
386 std::dynamic_pointer_cast<CPS::TopologicalPowerComp>(comp);
388 powerComp->setBehaviour(TopologicalPowerComp::Behaviour::PFSimulation);
396 mY = CPS::SparseMatrixComp(n, n);
397 for (
auto line :
mLines) {
398 line->pfApplyAdmittanceMatrixStamp(
mY);
402 if (**trans->mResistance == 0 && **trans->mInductance == 0) {
403 SPDLOG_LOGGER_INFO(
mSLog,
"{} {} ignored for R = 0 and L = 0",
404 trans->type(), trans->name());
407 trans->pfApplyAdmittanceMatrixStamp(
mY);
410 shunt->pfApplyAdmittanceMatrixStamp(
mY);
414 throw std::invalid_argument(
"There are no bus");
442 auto sparseJ =
mJ.sparseView();
445 Eigen::SparseLU<SparseMatrix> lu(sparseJ);
455 SPDLOG_LOGGER_DEBUG(
mSLog,
"Mismatch vector at iteration {}: \n {}", i,
mF);
465 void PFSolver::SolveTask::execute(Real time, Int timeStepCount) {
473 return Task::List{std::make_shared<SolveTask>(*
this)};
Real mSystemOmega
System angular frequency - omega.
Real mSystemFrequency
System frequency.
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.
void determinePFBusType()
Determine bus type for all buses.
std::vector< std::shared_ptr< CPS::SP::Ph1::Load > > mLoads
Vector of load components.
CPS::TopologicalNode::List mPQBuses
Vector of nodes characterized as PQ buses.
UInt mNumPQBuses
Number of PQ nodes.
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.
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.
Base class for more specific solvers such as MNA, ODE or IDA.
Real mTimeStep
Time step for fixed step solvers.
Behaviour mBehaviour
Solver behaviour initialization or simulation.
CPS::Logger::Log mSLog
Logger.
Bool mInitFromNodesAndTerminals