diff --git a/dpsim-models/include/dpsim-models/SP/SP_Ph1_NetworkInjection.h b/dpsim-models/include/dpsim-models/SP/SP_Ph1_NetworkInjection.h index b8f33336b5..bf99c32006 100644 --- a/dpsim-models/include/dpsim-models/SP/SP_Ph1_NetworkInjection.h +++ b/dpsim-models/include/dpsim-models/SP/SP_Ph1_NetworkInjection.h @@ -16,104 +16,114 @@ namespace CPS { namespace SP { namespace Ph1 { - /// \brief Network injection model - /// - /// This model represents network injections by an ideal voltage source. - /// The voltage source can be configured to use different types of SignalGenerators using the various setParameters functions - /// When the SineWaveGenerator is configured via the void setParameters(Complex voltageRef, Real srcFreq = 0.0) function, - /// the frequency, magnitude and phase of the sine wave can be modified through the mVoltageRef and mSrcFreq attributes. - /// See SP_Ph1_VoltageSource.h for more details. - class NetworkInjection: - public CompositePowerComp, - public SharedFactory, - public PFSolverInterfaceBus, - public DAEInterface { - - private: - // ### Electrical Subcomponents ### - /// Voltage source - std::shared_ptr mSubVoltageSource; - - // #### solver #### - /// Vector to collect subcomponent right vector stamps - std::vector mRightVectorStamps; - - // #### Powerflow section #### - /// Base voltage [V] - const Attribute::Ptr mBaseVoltage; - - public: - const Attribute::Ptr mVoltageRef; - const Attribute::Ptr mSrcFreq; - - // #### Powerflow section #### - /// Voltage set point [V] - const Attribute::Ptr mVoltageSetPoint; - /// Voltage set point [pu] - const Attribute::Ptr mVoltageSetPointPerUnit; - /// Active Power Injection [W] - const Attribute::Ptr mActivePowerInjection; - /// Reactive Power Injection [Var] - const Attribute::Ptr mReactivePowerInjection; - - /// Defines UID, name and logging level - NetworkInjection(String uid, String name, Logger::Level logLevel = Logger::Level::off); - /// Defines name and logging level - NetworkInjection(String name, Logger::Level logLevel = Logger::Level::off) - : NetworkInjection(name, name, logLevel) { } - /// - SimPowerComp::Ptr clone(String name) override; - - // #### General #### - /// Initializes component from power flow data - void initializeFromNodesAndTerminals(Real frequency) override; - - // #### Powerflow section #### - /// Set parameters relevant for PF solver - void setParameters(Real vSetPointPerUnit); - /// Set base voltage - void setBaseVoltage(Real baseVoltage); - /// Calculates component's parameters in specified per-unit system - void calculatePerUnitParameters(Real baseApparentPower, Real baseOmega); - /// Modify powerflow bus type - void modifyPowerFlowBusType(PowerflowBusType powerflowBusType) override; - /// Update power injection - void updatePowerInjection(Complex powerInj); - - // #### MNA Section #### - /// Setter for reference voltage and frequency with a sine wave generator - /// This will initialize the values of mVoltageRef and mSrcFreq to match the given parameters - /// However, the attributes can be modified during the simulation to dynamically change the magnitude, frequency, and phase of the sine wave. - void setParameters(Complex voltageRef, Real srcFreq = 0.0); - /// Setter for reference signal of type frequency ramp - /// This will create a FrequencyRampGenerator which will not react to external changes to mVoltageRef or mSrcFreq! - void setParameters(Complex initialPhasor, Real freqStart, Real rocof, Real timeStart, Real duration, bool smoothRamp = true); - /// Setter for reference signal of type cosine frequency modulation - /// This will create a CosineFMGenerator which will not react to external changes to mVoltageRef or mSrcFreq! - void setParameters(Complex initialPhasor, Real modulationFrequency, Real modulationAmplitude, Real baseFrequency = 0.0, bool zigzag = false); - - /// Stamps right side (source) vector - void mnaParentApplyRightSideVectorStamp(Matrix& rightVector) override; - /// Returns current through the component - void mnaCompUpdateCurrent(const Matrix& leftVector) override; - /// Updates voltage across component - void mnaCompUpdateVoltage(const Matrix& leftVector) override; - /// MNA pre step operations - void mnaParentPreStep(Real time, Int timeStepCount) override; - /// MNA post step operations - void mnaParentPostStep(Real time, Int timeStepCount, Attribute::Ptr &leftVector) override; - /// Add MNA pre step dependencies - void mnaParentAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) override; - /// Add MNA post step dependencies - void mnaParentAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute::Ptr &leftVector) override; - - // #### DAE Section #### - /// Residual function for DAE Solver - void daeResidual(double ttime, const double state[], const double dstate_dt[], double resid[], std::vector& off) override; - ///Voltage Getter - Complex daeInitialize() override; - - +/// \brief Network injection model +/// +/// This model represents network injections by an ideal voltage source. +/// The voltage source can be configured to use different types of SignalGenerators using the various setParameters functions +/// When the SineWaveGenerator is configured via the void setParameters(Complex voltageRef, Real srcFreq = 0.0) function, +/// the frequency, magnitude and phase of the sine wave can be modified through the mVoltageRef and mSrcFreq attributes. +/// See SP_Ph1_VoltageSource.h for more details. +class NetworkInjection : public CompositePowerComp, + public SharedFactory, + public PFSolverInterfaceBus, + public DAEInterface { + +private: + // ### Electrical Subcomponents ### + /// Voltage source + std::shared_ptr mSubVoltageSource; + + // #### solver #### + /// Vector to collect subcomponent right vector stamps + std::vector mRightVectorStamps; + + // #### Powerflow section #### + /// Base voltage [V] + const Attribute::Ptr mBaseVoltage; + +public: + const Attribute::Ptr mVoltageRef; + const Attribute::Ptr mSrcFreq; + + // #### Powerflow section #### + /// Voltage set point [V] + const Attribute::Ptr mVoltageSetPoint; + /// Voltage set point [pu] + const Attribute::Ptr mVoltageSetPointPerUnit; + /// Active Power Injection [W] + const Attribute::Ptr mActivePowerInjection; + /// Reactive Power Injection [Var] + const Attribute::Ptr mReactivePowerInjection; + + /// Defines UID, name and logging level + NetworkInjection(String uid, String name, + Logger::Level logLevel = Logger::Level::off); + /// Defines name and logging level + NetworkInjection(String name, Logger::Level logLevel = Logger::Level::off) + : NetworkInjection(name, name, logLevel) {} + /// + SimPowerComp::Ptr clone(String name) override; + + // #### General #### + /// Initializes component from power flow data + void initializeFromNodesAndTerminals(Real frequency) override; + + // #### Powerflow section #### + /// Set parameters relevant for PF solver + void setParameters(Real vSetPointPerUnit); + /// Set base voltage + void setBaseVoltage(Real baseVoltage); + /// Calculates component's parameters in specified per-unit system + void calculatePerUnitParameters(Real baseApparentPower, Real baseOmega); + /// Modify powerflow bus type + void modifyPowerFlowBusType(PowerflowBusType powerflowBusType) override; + /// Update power injection + void updatePowerInjection(Complex powerInj); + + // #### MNA Section #### + /// Setter for reference voltage and frequency with a sine wave generator + /// This will initialize the values of mVoltageRef and mSrcFreq to match the given parameters + /// However, the attributes can be modified during the simulation to dynamically change the magnitude, frequency, and phase of the sine wave. + void setParameters(Complex voltageRef, Real srcFreq = 0.0); + /// Setter for reference signal of type frequency ramp + /// This will create a FrequencyRampGenerator which will not react to external changes to mVoltageRef or mSrcFreq! + void setParameters(Complex initialPhasor, Real freqStart, Real rocof, + Real timeStart, Real duration, bool smoothRamp = true); + /// Setter for reference signal of type cosine frequency modulation + /// This will create a CosineFMGenerator which will not react to external changes to mVoltageRef or mSrcFreq! + void setParameters(Complex initialPhasor, Real modulationFrequency, + Real modulationAmplitude, Real baseFrequency = 0.0, + bool zigzag = false); + + /// Stamps right side (source) vector + void mnaParentApplyRightSideVectorStamp(Matrix &rightVector) override; + /// Returns current through the component + void mnaCompUpdateCurrent(const Matrix &leftVector) override; + /// Updates voltage across component + void mnaCompUpdateVoltage(const Matrix &leftVector) override; + /// MNA pre step operations + void mnaParentPreStep(Real time, Int timeStepCount) override; + /// MNA post step operations + void mnaParentPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) override; + /// Add MNA pre step dependencies + void mnaParentAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) override; + /// Add MNA post step dependencies + void + mnaParentAddPostStepDependencies(AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) override; + + // #### DAE Section #### + /// Residual function for DAE Solver + void daeResidual(double ttime, const double state[], const double dstate_dt[], + double resid[], std::vector &off) override; + ///Voltage Getter + Complex daeInitialize() override; }; } // namespace Ph1 } // namespace SP diff --git a/dpsim-models/src/SP/SP_Ph1_Load.cpp b/dpsim-models/src/SP/SP_Ph1_Load.cpp index 11535026fb..89014774b5 100644 --- a/dpsim-models/src/SP/SP_Ph1_Load.cpp +++ b/dpsim-models/src/SP/SP_Ph1_Load.cpp @@ -40,10 +40,13 @@ void SP::Ph1::Load::setParameters(Real activePower, Real reactivePower, **mActivePower, **mReactivePower); mSLog->flush(); - SPDLOG_LOGGER_INFO(mSLog, "Active Power={}[W]\nReactive Power={} [VAr]\nNominal Voltage={} [V]", **mActivePower, **mReactivePower, **mNomVoltage); - mSLog->flush(); + SPDLOG_LOGGER_INFO( + mSLog, + "Active Power={}[W]\nReactive Power={} [VAr]\nNominal Voltage={} [V]", + **mActivePower, **mReactivePower, **mNomVoltage); + mSLog->flush(); - mParametersSet = true; + mParametersSet = true; } // #### Powerflow section #### diff --git a/dpsim/src/PFSolver.cpp b/dpsim/src/PFSolver.cpp index c8eb6f9a1a..bb820e5e8c 100644 --- a/dpsim/src/PFSolver.cpp +++ b/dpsim/src/PFSolver.cpp @@ -182,144 +182,135 @@ void PFSolver::determinePFBusType() { } } - for (auto comp : mSystem.mComponentsAtNode[node]) { - if (std::shared_ptr load = std::dynamic_pointer_cast(comp)) { - if (load->mPowerflowBusType == CPS::PowerflowBusType::PQ) { - connectedPQ = true; - } - } - else if (std::shared_ptr gen = std::dynamic_pointer_cast(comp)) { - if (gen->mPowerflowBusType == CPS::PowerflowBusType::PV) { - connectedPV = true; - } - else if (gen->mPowerflowBusType == CPS::PowerflowBusType::VD) { - connectedVD = true; - } - } - else if (std::shared_ptr extnet = std::dynamic_pointer_cast(comp)) { - if (extnet->mPowerflowBusType == CPS::PowerflowBusType::VD) { - connectedVD = true; - } - else if (extnet->mPowerflowBusType == CPS::PowerflowBusType::PV) { - connectedPV = true; - } - } - } - - // determine powerflow bus types according connected type of connected components - // only PQ type component connected -> set as PQ bus - if (!connectedPV && connectedPQ && !connectedVD) { - SPDLOG_LOGGER_INFO(mSLog, "{}: only PQ type component connected -> set as PQ bus", node->name()); - mPQBusIndices.push_back(node->matrixNodeIndex()); - mPQBuses.push_back(node); - } // no component connected -> set as PQ bus (P & Q will be zero) - else if (!connectedPV && !connectedPQ && !connectedVD) { - SPDLOG_LOGGER_INFO(mSLog, "{}: no component connected -> set as PQ bus", node->name()); - mPQBusIndices.push_back(node->matrixNodeIndex()); - mPQBuses.push_back(node); - } // only PV type component connected -> set as PV bus - else if (connectedPV && !connectedPQ && !connectedVD) { - SPDLOG_LOGGER_INFO(mSLog, "{}: only PV type component connected -> set as PV bus", node->name()); - mPVBusIndices.push_back(node->matrixNodeIndex()); - mPVBuses.push_back(node); - } // PV and PQ type component connected -> set as PV bus (TODO: bus type should be modifiable by user afterwards) - else if (connectedPV && connectedPQ && !connectedVD) { - SPDLOG_LOGGER_INFO(mSLog, "{}: PV and PQ type component connected -> set as PV bus", node->name()); - mPVBusIndices.push_back(node->matrixNodeIndex()); - mPVBuses.push_back(node); - } // only VD type component connected -> set as VD bus - else if (!connectedPV && !connectedPQ && connectedVD) { - SPDLOG_LOGGER_INFO(mSLog, "{}: only VD type component connected -> set as VD bus", node->name()); - mVDBusIndices.push_back(node->matrixNodeIndex()); - mVDBuses.push_back(node); - } // VD and PV type component connect -> set as VD bus - else if (connectedPV && !connectedPQ && connectedVD) { - SPDLOG_LOGGER_INFO(mSLog, "{}: VD and PV type component connect -> set as VD bus", node->name()); - mVDBusIndices.push_back(node->matrixNodeIndex()); - mVDBuses.push_back(node); - } // VD, PV and PQ type component connect -> set as VD bus - else if (connectedPV && connectedPQ && connectedVD) { - SPDLOG_LOGGER_INFO(mSLog, "{}: VD, PV and PQ type component connect -> set as VD bus", node->name()); - mVDBusIndices.push_back(node->matrixNodeIndex()); - mVDBuses.push_back(node); - } - else { - std::stringstream ss; - ss << "Node>>" << node->name() << ": combination of connected components is invalid"; - throw std::invalid_argument(ss.str()); - } - } - - mNumPQBuses = mPQBusIndices.size(); - mNumPVBuses = mPVBusIndices.size(); - mNumVDBuses = mVDBusIndices.size(); - mNumUnknowns = 2*mNumPQBuses + mNumPVBuses; - - // Aggregate PQ bus and PV bus index vectors for easy handling in solver - mPQPVBusIndices.reserve(mNumPQBuses + mNumPVBuses); - mPQPVBusIndices.insert(mPQPVBusIndices.end(), mPQBusIndices.begin(), mPQBusIndices.end()); - mPQPVBusIndices.insert(mPQPVBusIndices.end(), mPVBusIndices.begin(), mPVBusIndices.end()); - - SPDLOG_LOGGER_INFO(mSLog, "#### Create index vectors for power flow solver:"); - SPDLOG_LOGGER_INFO(mSLog, "PQ Buses: {}", logVector(mPQBusIndices)); - SPDLOG_LOGGER_INFO(mSLog, "PV Buses: {}", logVector(mPVBusIndices)); - SPDLOG_LOGGER_INFO(mSLog, "VD Buses: {}", logVector(mVDBusIndices)); + // determine powerflow bus types according connected type of connected components + // only PQ type component connected -> set as PQ bus + if (!connectedPV && connectedPQ && !connectedVD) { + SPDLOG_LOGGER_INFO( + mSLog, "{}: only PQ type component connected -> set as PQ bus", + node->name()); + mPQBusIndices.push_back(node->matrixNodeIndex()); + mPQBuses.push_back(node); + } // no component connected -> set as PQ bus (P & Q will be zero) + else if (!connectedPV && !connectedPQ && !connectedVD) { + SPDLOG_LOGGER_INFO(mSLog, "{}: no component connected -> set as PQ bus", + node->name()); + mPQBusIndices.push_back(node->matrixNodeIndex()); + mPQBuses.push_back(node); + } // only PV type component connected -> set as PV bus + else if (connectedPV && !connectedPQ && !connectedVD) { + SPDLOG_LOGGER_INFO( + mSLog, "{}: only PV type component connected -> set as PV bus", + node->name()); + mPVBusIndices.push_back(node->matrixNodeIndex()); + mPVBuses.push_back(node); + } // PV and PQ type component connected -> set as PV bus (TODO: bus type should be modifiable by user afterwards) + else if (connectedPV && connectedPQ && !connectedVD) { + SPDLOG_LOGGER_INFO( + mSLog, "{}: PV and PQ type component connected -> set as PV bus", + node->name()); + mPVBusIndices.push_back(node->matrixNodeIndex()); + mPVBuses.push_back(node); + } // only VD type component connected -> set as VD bus + else if (!connectedPV && !connectedPQ && connectedVD) { + SPDLOG_LOGGER_INFO( + mSLog, "{}: only VD type component connected -> set as VD bus", + node->name()); + mVDBusIndices.push_back(node->matrixNodeIndex()); + mVDBuses.push_back(node); + } // VD and PV type component connect -> set as VD bus + else if (connectedPV && !connectedPQ && connectedVD) { + SPDLOG_LOGGER_INFO( + mSLog, "{}: VD and PV type component connect -> set as VD bus", + node->name()); + mVDBusIndices.push_back(node->matrixNodeIndex()); + mVDBuses.push_back(node); + } // VD, PV and PQ type component connect -> set as VD bus + else if (connectedPV && connectedPQ && connectedVD) { + SPDLOG_LOGGER_INFO( + mSLog, "{}: VD, PV and PQ type component connect -> set as VD bus", + node->name()); + mVDBusIndices.push_back(node->matrixNodeIndex()); + mVDBuses.push_back(node); + } else { + std::stringstream ss; + ss << "Node>>" << node->name() + << ": combination of connected components is invalid"; + throw std::invalid_argument(ss.str()); + } + } + + mNumPQBuses = mPQBusIndices.size(); + mNumPVBuses = mPVBusIndices.size(); + mNumVDBuses = mVDBusIndices.size(); + mNumUnknowns = 2 * mNumPQBuses + mNumPVBuses; + + // Aggregate PQ bus and PV bus index vectors for easy handling in solver + mPQPVBusIndices.reserve(mNumPQBuses + mNumPVBuses); + mPQPVBusIndices.insert(mPQPVBusIndices.end(), mPQBusIndices.begin(), + mPQBusIndices.end()); + mPQPVBusIndices.insert(mPQPVBusIndices.end(), mPVBusIndices.begin(), + mPVBusIndices.end()); + + SPDLOG_LOGGER_INFO(mSLog, "#### Create index vectors for power flow solver:"); + SPDLOG_LOGGER_INFO(mSLog, "PQ Buses: {}", logVector(mPQBusIndices)); + SPDLOG_LOGGER_INFO(mSLog, "PV Buses: {}", logVector(mPVBusIndices)); + SPDLOG_LOGGER_INFO(mSLog, "VD Buses: {}", logVector(mVDBusIndices)); } void PFSolver::determineNodeBaseVoltages() { - SPDLOG_LOGGER_INFO(mSLog, "-- Determine base voltages for each node according to connected components"); - mSLog->flush(); + SPDLOG_LOGGER_INFO(mSLog, "-- Determine base voltages for each node " + "according to connected components"); + mSLog->flush(); - for (auto node : mSystem.mNodes) { - CPS::Real baseVoltage_ = 0; - for (auto comp : mSystem.mComponentsAtNode[node]) { - if (std::shared_ptr vsi = std::dynamic_pointer_cast(comp)) { - baseVoltage_=Math::abs(vsi->attributeTyped("vnom")->get()); - SPDLOG_LOGGER_INFO(mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", baseVoltage_, vsi->name(), node->name()); - break; - } - else if (std::shared_ptr rxline = std::dynamic_pointer_cast(comp)) { - baseVoltage_ = rxline->attributeTyped("base_Voltage")->get(); - SPDLOG_LOGGER_INFO(mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", baseVoltage_, rxline->name(), node->name()); - break; - } - else if (std::shared_ptr line = std::dynamic_pointer_cast(comp)) { - baseVoltage_ = line->attributeTyped("base_Voltage")->get(); - SPDLOG_LOGGER_INFO(mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", baseVoltage_, line->name(), node->name()); - break; - } - else if (std::shared_ptr trans = std::dynamic_pointer_cast(comp)) { - if (trans->terminal(0)->node()->name() == node->name()){ - baseVoltage_ = trans->attributeTyped("nominal_voltage_end1")->get(); - SPDLOG_LOGGER_INFO(mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", baseVoltage_, trans->name(), node->name()); - break; - } - else if (trans->terminal(1)->node()->name() == node->name()){ - baseVoltage_ = trans->attributeTyped("nominal_voltage_end2")->get(); - SPDLOG_LOGGER_INFO(mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", baseVoltage_, trans->name(), node->name()); - break; - } - } - else if (std::shared_ptr gen = std::dynamic_pointer_cast(comp)) { - baseVoltage_ = gen->attributeTyped("base_Voltage")->get(); - SPDLOG_LOGGER_INFO(mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", baseVoltage_, gen->name(), node->name()); - break; - } - /*else if (std::shared_ptr load = std::dynamic_pointer_cast(comp)) { - baseVoltage_ = load->attributeTyped("V_nom")->get(); - mSLog->info("Choose base voltage of {}V to convert pu-solution of {}.", baseVoltage_, load->name(), node->name()); - break; - } - */ - else if (std::shared_ptr extnet = std::dynamic_pointer_cast(comp)) { - baseVoltage_ = extnet->attributeTyped("base_Voltage")->get(); - mSLog->info("Choose base voltage of {}V to convert pu-solution of {}.", baseVoltage_, extnet->name(), node->name()); - break; - } - else { - SPDLOG_LOGGER_WARN(mSLog, "Unable to get base voltage at {}", node->name()); - } + for (auto node : mSystem.mNodes) { + CPS::Real baseVoltage_ = 0; + for (auto comp : mSystem.mComponentsAtNode[node]) { + if (std::shared_ptr vsi = + std::dynamic_pointer_cast< + CPS::SP::Ph1::AvVoltageSourceInverterDQ>(comp)) { + baseVoltage_ = + Math::abs(vsi->attributeTyped("vnom")->get()); + SPDLOG_LOGGER_INFO( + mSLog, + "Choose base voltage {}V of {} to convert pu-solution of {}.", + baseVoltage_, vsi->name(), node->name()); + break; + } else if (std::shared_ptr rxline = + std::dynamic_pointer_cast(comp)) { + baseVoltage_ = rxline->attributeTyped("base_Voltage")->get(); + SPDLOG_LOGGER_INFO( + mSLog, + "Choose base voltage {}V of {} to convert pu-solution of {}.", + baseVoltage_, rxline->name(), node->name()); + break; + } else if (std::shared_ptr line = + std::dynamic_pointer_cast(comp)) { + baseVoltage_ = line->attributeTyped("base_Voltage")->get(); + SPDLOG_LOGGER_INFO( + mSLog, + "Choose base voltage {}V of {} to convert pu-solution of {}.", + baseVoltage_, line->name(), node->name()); + break; + } else if (std::shared_ptr trans = + std::dynamic_pointer_cast( + comp)) { + if (trans->terminal(0)->node()->name() == node->name()) { + baseVoltage_ = + trans->attributeTyped("nominal_voltage_end1")->get(); + SPDLOG_LOGGER_INFO( + mSLog, + "Choose base voltage {}V of {} to convert pu-solution of {}.", + baseVoltage_, trans->name(), node->name()); + break; + } else if (trans->terminal(1)->node()->name() == node->name()) { + baseVoltage_ = + trans->attributeTyped("nominal_voltage_end2")->get(); + SPDLOG_LOGGER_INFO( + mSLog, + "Choose base voltage {}V of {} to convert pu-solution of {}.", + baseVoltage_, trans->name(), node->name()); + break; } } else if (std::shared_ptr gen = std::dynamic_pointer_cast( @@ -330,6 +321,20 @@ void PFSolver::determineNodeBaseVoltages() { "Choose base voltage {}V of {} to convert pu-solution of {}.", baseVoltage_, gen->name(), node->name()); break; + } + /*else if (std::shared_ptr load = std::dynamic_pointer_cast(comp)) { + baseVoltage_ = load->attributeTyped("V_nom")->get(); + mSLog->info("Choose base voltage of {}V to convert pu-solution of {}.", baseVoltage_, load->name(), node->name()); + break; + } + */ + else if (std::shared_ptr extnet = + std::dynamic_pointer_cast( + comp)) { + baseVoltage_ = extnet->attributeTyped("base_Voltage")->get(); + mSLog->info("Choose base voltage of {}V to convert pu-solution of {}.", + baseVoltage_, extnet->name(), node->name()); + break; } else { SPDLOG_LOGGER_WARN(mSLog, "Unable to get base voltage at {}", node->name()); @@ -480,4 +485,4 @@ void PFSolver::SolveTask::execute(Real time, Int timeStepCount) { Task::List PFSolver::getTasks() { return Task::List{std::make_shared(*this)}; -} +} \ No newline at end of file diff --git a/dpsim/src/PFSolverPowerPolar.cpp b/dpsim/src/PFSolverPowerPolar.cpp index e200852a48..5d8c8ee203 100644 --- a/dpsim/src/PFSolverPowerPolar.cpp +++ b/dpsim/src/PFSolverPowerPolar.cpp @@ -34,104 +34,146 @@ void PFSolverPowerPolar::generateInitialSolution(Real time, } // set initial solution for the new time - for (auto pq : mPQBuses) { - if (!keep_last_solution) { - sol_V(pq->matrixNodeIndex()) = 1.0; - sol_D(pq->matrixNodeIndex()) = 0.0; - sol_V_complex(pq->matrixNodeIndex()) = CPS::Complex(sol_V[pq->matrixNodeIndex()], sol_D[pq->matrixNodeIndex()]); - } - for (auto comp : mSystem.mComponentsAtNode[pq]) { - if (std::shared_ptr load = std::dynamic_pointer_cast(comp)) { - sol_P(pq->matrixNodeIndex()) -= load->attributeTyped("P_pu")->get(); - sol_Q(pq->matrixNodeIndex()) -= load->attributeTyped("Q_pu")->get(); - } - else if(std::shared_ptr sst = - std::dynamic_pointer_cast(comp)){ - sol_P(pq->matrixNodeIndex()) -= sst->getNodalInjection(pq).real(); - sol_Q(pq->matrixNodeIndex()) -= sst->getNodalInjection(pq).imag(); - } - else if (std::shared_ptr vsi = - std::dynamic_pointer_cast(comp)) { - // TODO: add per-unit attributes to VSI and use here - sol_P(pq->matrixNodeIndex()) += vsi->attributeTyped("P_ref")->get() / mBaseApparentPower; - sol_Q(pq->matrixNodeIndex()) += vsi->attributeTyped("Q_ref")->get() / mBaseApparentPower; - } - else if (std::shared_ptr gen = std::dynamic_pointer_cast(comp)) { - sol_P(pq->matrixNodeIndex()) += gen->attributeTyped("P_set_pu")->get(); - sol_Q(pq->matrixNodeIndex()) += gen->attributeTyped("Q_set_pu")->get(); - } - sol_S_complex(pq->matrixNodeIndex()) = CPS::Complex(sol_P[pq->matrixNodeIndex()], sol_Q[pq->matrixNodeIndex()]); - } - } - - for (auto pv : mPVBuses) { - if (!keep_last_solution) { - sol_Q(pv->matrixNodeIndex()) = 0; - sol_D(pv->matrixNodeIndex()) = 0; - } - for (auto comp : mSystem.mComponentsAtNode[pv]) { - if (std::shared_ptr gen = std::dynamic_pointer_cast(comp)) { - sol_P(pv->matrixNodeIndex()) += gen->attributeTyped("P_set_pu")->get(); - sol_V(pv->matrixNodeIndex()) = gen->attributeTyped("V_set_pu")->get(); - sol_Q(pv->matrixNodeIndex()) += gen->attributeTyped("Q_set_pu")->get(); - } - else if (std::shared_ptr load = std::dynamic_pointer_cast(comp)) { - sol_P(pv->matrixNodeIndex()) -= load->attributeTyped("P_pu")->get(); - sol_Q(pv->matrixNodeIndex()) -= load->attributeTyped("Q_pu")->get(); - } - else if (std::shared_ptr vsi = - std::dynamic_pointer_cast(comp)) { - sol_P(pv->matrixNodeIndex()) += vsi->attributeTyped("P_ref")->get() / mBaseApparentPower; - } - else if (std::shared_ptr extnet = - std::dynamic_pointer_cast(comp)) { - sol_P(pv->matrixNodeIndex()) += extnet->attributeTyped("p_inj")->get() / mBaseApparentPower; - sol_V(pv->matrixNodeIndex()) = extnet->attributeTyped("V_set_pu")->get(); - // sol_Q(pv->matrixNodeIndex()) += extnet->attributeTyped("q_inj")->get() / mBaseApparentPower; //Todo allow initialisation of p_inj and q_inj in SP_NetworkInjection (use updatePowerInjection?) - } - sol_S_complex(pv->matrixNodeIndex()) = CPS::Complex(sol_P[pv->matrixNodeIndex()], sol_Q[pv->matrixNodeIndex()]); - sol_V_complex(pv->matrixNodeIndex()) = CPS::Complex(sol_V[pv->matrixNodeIndex()], sol_D[pv->matrixNodeIndex()]); - } - } + for (auto pq : mPQBuses) { + if (!keep_last_solution) { + sol_V(pq->matrixNodeIndex()) = 1.0; + sol_D(pq->matrixNodeIndex()) = 0.0; + sol_V_complex(pq->matrixNodeIndex()) = CPS::Complex( + sol_V[pq->matrixNodeIndex()], sol_D[pq->matrixNodeIndex()]); + } + for (auto comp : mSystem.mComponentsAtNode[pq]) { + if (std::shared_ptr load = + std::dynamic_pointer_cast(comp)) { + sol_P(pq->matrixNodeIndex()) -= + load->attributeTyped("P_pu")->get(); + sol_Q(pq->matrixNodeIndex()) -= + load->attributeTyped("Q_pu")->get(); + } else if (std::shared_ptr sst = + std::dynamic_pointer_cast< + CPS::SP::Ph1::SolidStateTransformer>(comp)) { + sol_P(pq->matrixNodeIndex()) -= sst->getNodalInjection(pq).real(); + sol_Q(pq->matrixNodeIndex()) -= sst->getNodalInjection(pq).imag(); + } else if (std::shared_ptr + vsi = std::dynamic_pointer_cast< + CPS::SP::Ph1::AvVoltageSourceInverterDQ>(comp)) { + // TODO: add per-unit attributes to VSI and use here + sol_P(pq->matrixNodeIndex()) += + vsi->attributeTyped("P_ref")->get() / + mBaseApparentPower; + sol_Q(pq->matrixNodeIndex()) += + vsi->attributeTyped("Q_ref")->get() / + mBaseApparentPower; + } else if (std::shared_ptr gen = + std::dynamic_pointer_cast< + CPS::SP::Ph1::SynchronGenerator>(comp)) { + sol_P(pq->matrixNodeIndex()) += + gen->attributeTyped("P_set_pu")->get(); + sol_Q(pq->matrixNodeIndex()) += + gen->attributeTyped("Q_set_pu")->get(); + } + sol_S_complex(pq->matrixNodeIndex()) = CPS::Complex( + sol_P[pq->matrixNodeIndex()], sol_Q[pq->matrixNodeIndex()]); + } + } + + for (auto pv : mPVBuses) { + if (!keep_last_solution) { + sol_Q(pv->matrixNodeIndex()) = 0; + sol_D(pv->matrixNodeIndex()) = 0; + } + for (auto comp : mSystem.mComponentsAtNode[pv]) { + if (std::shared_ptr gen = + std::dynamic_pointer_cast( + comp)) { + sol_P(pv->matrixNodeIndex()) += + gen->attributeTyped("P_set_pu")->get(); + sol_V(pv->matrixNodeIndex()) = + gen->attributeTyped("V_set_pu")->get(); + sol_Q(pv->matrixNodeIndex()) += + gen->attributeTyped("Q_set_pu")->get(); + } else if (std::shared_ptr load = + std::dynamic_pointer_cast(comp)) { + sol_P(pv->matrixNodeIndex()) -= + load->attributeTyped("P_pu")->get(); + sol_Q(pv->matrixNodeIndex()) -= + load->attributeTyped("Q_pu")->get(); + } else if (std::shared_ptr + vsi = std::dynamic_pointer_cast< + CPS::SP::Ph1::AvVoltageSourceInverterDQ>(comp)) { + sol_P(pv->matrixNodeIndex()) += + vsi->attributeTyped("P_ref")->get() / + mBaseApparentPower; + } else if (std::shared_ptr extnet = + std::dynamic_pointer_cast< + CPS::SP::Ph1::NetworkInjection>(comp)) { + sol_P(pv->matrixNodeIndex()) += + extnet->attributeTyped("p_inj")->get() / + mBaseApparentPower; + sol_V(pv->matrixNodeIndex()) = + extnet->attributeTyped("V_set_pu")->get(); + // sol_Q(pv->matrixNodeIndex()) += extnet->attributeTyped("q_inj")->get() / mBaseApparentPower; //Todo allow initialisation of p_inj and q_inj in SP_NetworkInjection (use updatePowerInjection?) + } + sol_S_complex(pv->matrixNodeIndex()) = CPS::Complex( + sol_P[pv->matrixNodeIndex()], sol_Q[pv->matrixNodeIndex()]); + sol_V_complex(pv->matrixNodeIndex()) = CPS::Complex( + sol_V[pv->matrixNodeIndex()], sol_D[pv->matrixNodeIndex()]); + } + } for (auto vd : mVDBuses) { - sol_P(vd->matrixNodeIndex()) = 0.0; - sol_Q(vd->matrixNodeIndex()) = 0.0; - sol_V(vd->matrixNodeIndex()) = 1.0; - sol_D(vd->matrixNodeIndex()) = 0.0; - - // if external injection at VD bus, reset the voltage to injection's voltage set-point - for (auto comp : mSystem.mComponentsAtNode[vd]) { - if (std::shared_ptr extnet = std::dynamic_pointer_cast(comp)) { - sol_V(vd->matrixNodeIndex()) = extnet->attributeTyped("V_set_pu")->get(); - sol_P(vd->matrixNodeIndex()) += extnet->attributeTyped("p_inj")->get() / mBaseApparentPower; // Todo add p_set q_set to extnet - sol_Q(vd->matrixNodeIndex()) += extnet->attributeTyped("q_inj")->get() / mBaseApparentPower; - } - - // if load at VD bus, substract P and Q - else if (std::shared_ptr load = std::dynamic_pointer_cast(comp)) { - sol_P(vd->matrixNodeIndex()) -= load->attributeTyped("P_pu")->get(); - sol_Q(vd->matrixNodeIndex()) -= load->attributeTyped("Q_pu")->get(); - } - - // if generator at VD, add P_set Q_Set - else if (std::shared_ptr gen = std::dynamic_pointer_cast(comp)) { - sol_P(vd->matrixNodeIndex()) += gen->attributeTyped("P_set_pu")->get(); - sol_Q(vd->matrixNodeIndex()) += gen->attributeTyped("Q_set_pu")->get(); - } + sol_P(vd->matrixNodeIndex()) = 0.0; + sol_Q(vd->matrixNodeIndex()) = 0.0; + sol_V(vd->matrixNodeIndex()) = 1.0; + sol_D(vd->matrixNodeIndex()) = 0.0; + + // if external injection at VD bus, reset the voltage to injection's voltage set-point + for (auto comp : mSystem.mComponentsAtNode[vd]) { + if (std::shared_ptr extnet = + std::dynamic_pointer_cast( + comp)) { + sol_V(vd->matrixNodeIndex()) = + extnet->attributeTyped("V_set_pu")->get(); + sol_P(vd->matrixNodeIndex()) += + extnet->attributeTyped("p_inj")->get() / + mBaseApparentPower; // Todo add p_set q_set to extnet + sol_Q(vd->matrixNodeIndex()) += + extnet->attributeTyped("q_inj")->get() / + mBaseApparentPower; } - // if generator at VD bus, reset the voltage to generator's set-point - if (!mSynchronGenerators.empty()) { - for (auto gen : mSynchronGenerators) - { - if (gen->node(0)->matrixNodeIndex() == vd->matrixNodeIndex()) - sol_V(vd->matrixNodeIndex()) = gen->attributeTyped("V_set_pu")->get(); - } + // if load at VD bus, substract P and Q + else if (std::shared_ptr load = + std::dynamic_pointer_cast(comp)) { + sol_P(vd->matrixNodeIndex()) -= + load->attributeTyped("P_pu")->get(); + sol_Q(vd->matrixNodeIndex()) -= + load->attributeTyped("Q_pu")->get(); + } + + // if generator at VD, add P_set Q_Set + else if (std::shared_ptr gen = + std::dynamic_pointer_cast( + comp)) { + sol_P(vd->matrixNodeIndex()) += + gen->attributeTyped("P_set_pu")->get(); + sol_Q(vd->matrixNodeIndex()) += + gen->attributeTyped("Q_set_pu")->get(); } + } + + // if generator at VD bus, reset the voltage to generator's set-point + if (!mSynchronGenerators.empty()) { + for (auto gen : mSynchronGenerators) { + if (gen->node(0)->matrixNodeIndex() == vd->matrixNodeIndex()) + sol_V(vd->matrixNodeIndex()) = + gen->attributeTyped("V_set_pu")->get(); + } + } - sol_S_complex(vd->matrixNodeIndex()) = CPS::Complex(sol_P[vd->matrixNodeIndex()], sol_Q[vd->matrixNodeIndex()]); - sol_V_complex(vd->matrixNodeIndex()) = CPS::Complex(sol_V[vd->matrixNodeIndex()], sol_D[vd->matrixNodeIndex()]); + sol_S_complex(vd->matrixNodeIndex()) = CPS::Complex( + sol_P[vd->matrixNodeIndex()], sol_Q[vd->matrixNodeIndex()]); + sol_V_complex(vd->matrixNodeIndex()) = CPS::Complex( + sol_V[vd->matrixNodeIndex()], sol_D[vd->matrixNodeIndex()]); } }