21PowerFlow::PowerFlow(std::vector<Element*> elementList) :
ElectricCalculation() { GetElementsFromList(elementList); }
22PowerFlow::~PowerFlow() {}
23bool PowerFlow::InitPowerFlow(std::vector<BusType>& busType,
24 std::vector<std::complex<double> >& voltage,
25 std::vector<std::complex<double> >& power,
26 std::vector<std::complex<double> >& loadPower,
27 std::vector<ReactiveLimits>& reactiveLimit,
28 double systemPowerBase,
31 double radInitAngle = wxDegToRad(initAngle);
37 if (!
GetYBus(m_yBus, systemPowerBase)) {
38 m_errorMsg = _(
"No buses found on the system.");
47 m_numberOfBuses =
static_cast<int>(m_yBus.size());
53 reactiveLimit.clear();
55 reactiveLimit.resize(m_numberOfBuses);
58 Bus* slackBus =
nullptr;
62 if (data.isConnected) {
70 else if (data.isVoltageControlled) {
71 bool hasSyncMachine =
false;
94 v = data.controlledVoltage;
97 else if (busType[busNumber] ==
BUS_PV) {
98 v = data.controlledVoltage;
99 t = std::arg(data.voltage);
102 v = std::abs(data.voltage);
103 if (v <= 0.1) v = 1.0;
104 t = std::arg(data.voltage);
106 voltage.push_back(std::complex<double>(v * std::cos(t), v * std::sin(t)));
117 power.push_back(std::complex<double>(0.0, 0.0));
118 loadPower.push_back(std::complex<double>(0.0, 0.0));
126 power[busNumber] += std::complex<double>(childData.activePower, childData.reactivePower);
128 if (busType[busNumber] ==
BUS_PV) {
129 if (childData.haveMaxReactive && reactiveLimit[busNumber].maxLimitType !=
RL_UNLIMITED_SOURCE) {
130 reactiveLimit[busNumber].maxLimitType =
RL_LIMITED;
131 reactiveLimit[busNumber].maxLimit += childData.maxReactive;
133 else if (!childData.haveMaxReactive)
136 if (childData.haveMinReactive && reactiveLimit[busNumber].minLimitType !=
RL_UNLIMITED_SOURCE) {
137 reactiveLimit[busNumber].minLimitType =
RL_LIMITED;
138 reactiveLimit[busNumber].minLimit += childData.minReactive;
140 else if (!childData.haveMinReactive)
152 power[busNumber] += std::complex<double>(-childData.activePower, childData.reactivePower);
153 loadPower[busNumber] += std::complex<double>(-childData.activePower, 0.0);
155 if (busType[busNumber] ==
BUS_PV) {
156 if (childData.haveMaxReactive && reactiveLimit[busNumber].maxLimitType !=
RL_UNLIMITED_SOURCE) {
157 reactiveLimit[busNumber].maxLimitType =
RL_LIMITED;
158 reactiveLimit[busNumber].maxLimit += childData.maxReactive;
160 else if (!childData.haveMaxReactive)
163 if (childData.haveMinReactive && reactiveLimit[busNumber].minLimitType !=
RL_UNLIMITED_SOURCE) {
164 reactiveLimit[busNumber].minLimitType =
RL_LIMITED;
165 reactiveLimit[busNumber].minLimit += childData.minReactive;
167 else if (!childData.haveMinReactive)
179 if (childData.loadType == CONST_POWER) {
180 power[busNumber] += std::complex<double>(-childData.activePower, -childData.reactivePower);
181 loadPower[busNumber] += std::complex<double>(-childData.activePower, -childData.reactivePower);
193 double reactivePower = childData.reactivePower;
195 if (childData.calcQInPowerFlow) {
196 indMotor->InitPowerFlowMotor(systemPowerBase, data.number);
197 if (!indMotor->CalculateReactivePower(std::abs(voltage[childData.busNum]))) {
198 m_errorMsg = _(
"It was not possible to solve the induction motors.");
201 reactivePower = indMotor->GetElectricalData().qValue;
204 power[busNumber] += std::complex<double>(-childData.activePower, -reactivePower);
205 loadPower[busNumber] += std::complex<double>(-childData.activePower, -reactivePower);
212 if (emtElement->IsOnline() && !emtElement->GetParentList().empty()) {
213 if (bus == emtElement->GetParentList()[0]) {
215 power[busNumber] -= childData.power;
216 loadPower[busNumber] -= childData.power;
226 bool haveSlackBus =
false;
227 bool slackBusHaveGeneration =
false;
228 for (
unsigned int i = 0; i < busType.size(); i++) {
232 if (syncGenerator->
IsOnline() && slackBus == syncGenerator->
GetParentList()[0]) slackBusHaveGeneration =
true;
238 m_errorMsg = _(
"There is no slack bus on the system.");
241 if (!slackBusHaveGeneration) {
242 m_errorMsg = _(
"The slack bus don't have generation.");
249bool PowerFlow::RunGaussSeidel(
double systemPowerBase,
255 std::vector<BusType> busType;
256 std::vector<std::complex<double> > voltage;
257 std::vector<std::complex<double> > power;
258 std::vector<std::complex<double> > loadPower;
259 std::vector<ReactiveLimits> reactiveLimit;
261 if (!InitPowerFlow(busType, voltage, power, loadPower, reactiveLimit, systemPowerBase, initAngle))
return false;
264 std::vector<std::complex<double> > oldVoltage;
265 oldVoltage.resize(voltage.size());
267 auto oldBusType = busType;
270 double emtPowerError = 1e3;
274 if (iteration >= maxIteration) {
275 m_errorMsg = _(
"The maximum number of iterations was reached.");
280 if (!CalculateMotorsReactivePower(voltage, power)) {
281 m_errorMsg = _(
"It was not possible to solve the induction motors.");
286 for (
int i = 0; i < m_numberOfBuses; i++) oldVoltage[i] = voltage[i];
288 double iterationError = GaussSeidel(busType, voltage, oldVoltage, power, accFactor);
290 if (HasInvalidValue(voltage)) {
291 m_errorMsg = _(
"The power flow solution has invalid voltage values.");
295 if (HasInvalidValue(power)) {
296 m_errorMsg = _(
"The power flow solution has invalid power values.");
301 if (iterationError < error) {
304 double oldError = emtPowerError;
307 if (abs(emtPowerError - oldError) < 1e-12) {
308 m_errorMsg = _(
"Impossible to reach a convergence with the current Electromagnetic Transient Elements.");
312 else emtPowerError = 0.0;
314 if (!CheckReactiveLimits(busType, reactiveLimit, power, loadPower) && emtPowerError < error)
break;
319 m_iterations = iteration;
322 for (
int i = 0; i < m_numberOfBuses; i++) {
323 std::complex<double> sBus = std::complex<double>(0.0, 0.0);
324 for (
int j = 0; j < m_numberOfBuses; j++) sBus += voltage[i] * std::conj(voltage[j]) * std::conj(m_yBus[i][j]);
334bool PowerFlow::HasInvalidValue(
const std::vector< std::complex<double> >& value)
336 for (
size_t i = 0; i < value.size(); i++)
338 if (!std::isfinite(value[i].real()) ||
339 !std::isfinite(value[i].imag()))
347bool PowerFlow::RunNewtonRaphson(
double systemPowerBase,
353 std::vector<BusType> busType;
354 std::vector<std::complex<double> > voltage;
355 std::vector<std::complex<double> > power;
356 std::vector<std::complex<double> > loadPower;
357 std::vector<ReactiveLimits> reactiveLimit;
359 if (!InitPowerFlow(busType, voltage, power, loadPower, reactiveLimit, systemPowerBase, initAngle))
return false;
360 auto oldBusType = busType;
365 GetNumPVPQ(busType, numPQ, numPV);
368 std::vector<double> dPdQ;
369 dPdQ.resize(numPV + 2 * numPQ, 0.0);
374 if (iteration >= maxIteration) {
375 m_errorMsg = _(
"The maximum number of iterations was reached.");
380 if (!CalculateMotorsReactivePower(voltage, power)) {
381 m_errorMsg = _(
"It was not possible to solve the induction motors.");
388 std::fill(dPdQ.begin(), dPdQ.end(), 0.0);
391 int indexDQ = numPQ + numPV;
392 for (
int i = 0; i < m_numberOfBuses; i++) {
394 for (
int j = 0; j < m_numberOfBuses; j++) {
396 std::complex<double> sInj = std::conj(m_yBus[i][j]) * voltage[i] * std::conj(voltage[j]);
397 dPdQ[indexDP] += sInj.real();
400 if (busType[i] ==
BUS_PQ) dPdQ[indexDQ] += sInj.imag();
404 dPdQ[indexDP] = power[i].real() - dPdQ[indexDP];
408 if (busType[i] ==
BUS_PQ) {
409 dPdQ[indexDQ] = power[i].imag() - dPdQ[indexDQ];
416 double iterationError = 0.0;
417 for (
unsigned int i = 0; i < dPdQ.size(); ++i) {
418 if (iterationError < std::abs(dPdQ[i])) iterationError = std::abs(dPdQ[i]);
423 if (iterationError < error) {
424 for (
int i = 0; i < m_numberOfBuses; i++) {
425 std::complex<double> sBus(0.0, 0.0);
426 for (
int j = 0; j < m_numberOfBuses; j++)
427 sBus += voltage[i] * std::conj(voltage[j]) * std::conj(m_yBus[i][j]);
433 if (!CheckReactiveLimits(busType, reactiveLimit, power, loadPower) && emtPowerError < error)
436 GetNumPVPQ(busType, numPQ, numPV);
437 dPdQ.assign(numPV + 2 * numPQ, 0.0);
441 NewtonRaphson(busType, voltage, power, numPV, numPQ, dPdQ, inertia);
443 if (HasInvalidValue(voltage)) {
444 m_errorMsg = _(
"The power flow solution has invalid voltage values.");
448 if (HasInvalidValue(power)) {
449 m_errorMsg = _(
"The power flow solution has invalid power values.");
456 m_iterations = iteration;
461 for (
int i = 0; i < m_numberOfBuses; i++) {
462 std::complex<double> sBus = std::complex<double>(0.0, 0.0);
463 for (
int j = 0; j < m_numberOfBuses; j++) sBus += voltage[i] * std::conj(voltage[j]) * std::conj(m_yBus[i][j]);
472bool PowerFlow::RunGaussNewton(
double systemPowerBase,
480 std::vector<BusType> busType;
481 std::vector<std::complex<double> > voltage;
482 std::vector<std::complex<double> > power;
483 std::vector<std::complex<double> > loadPower;
484 std::vector<ReactiveLimits> reactiveLimit;
486 if (!InitPowerFlow(busType, voltage, power, loadPower, reactiveLimit, systemPowerBase, initAngle))
return false;
489 std::vector<std::complex<double> > oldVoltage;
490 oldVoltage.resize(voltage.size());
492 auto oldBusType = busType;
498 if (iteration >= maxIteration) {
499 m_errorMsg = _(
"The maximum number of iterations was reached.");
504 if (!CalculateMotorsReactivePower(voltage, power)) {
505 m_errorMsg = _(
"It was not possible to solve the induction motors.");
510 for (
int i = 0; i < m_numberOfBuses; i++) oldVoltage[i] = voltage[i];
512 double iterationError = GaussSeidel(busType, voltage, oldVoltage, power, accFactor);
514 if (iterationError < gaussTol)
break;
522 GetNumPVPQ(busType, numPQ, numPV);
525 std::vector<double> dPdQ;
526 dPdQ.resize(numPV + 2 * numPQ, 0.0);
530 if (iteration >= maxIteration) {
531 m_errorMsg = _(
"The maximum number of iterations was reached.");
536 if (!CalculateMotorsReactivePower(voltage, power)) {
537 m_errorMsg = _(
"It was not possible to solve the induction motors.");
544 std::fill(dPdQ.begin(), dPdQ.end(), 0.0);
547 int indexDQ = numPQ + numPV;
548 for (
int i = 0; i < m_numberOfBuses; i++) {
550 for (
int j = 0; j < m_numberOfBuses; j++) {
552 std::complex<double> sInj = std::conj(m_yBus[i][j]) * voltage[i] * std::conj(voltage[j]);
553 dPdQ[indexDP] += sInj.real();
556 if (busType[i] ==
BUS_PQ) dPdQ[indexDQ] += sInj.imag();
560 dPdQ[indexDP] = power[i].real() - dPdQ[indexDP];
564 if (busType[i] ==
BUS_PQ) {
565 dPdQ[indexDQ] = power[i].imag() - dPdQ[indexDQ];
572 double iterationError = 0.0;
573 for (
unsigned int i = 0; i < dPdQ.size(); ++i) {
574 if (iterationError < std::abs(dPdQ[i])) iterationError = std::abs(dPdQ[i]);
579 if (iterationError < error) {
582 if (!CheckReactiveLimits(busType, reactiveLimit, power, loadPower) && emtPowerError < error)
585 GetNumPVPQ(busType, numPQ, numPV);
587 dPdQ.resize(numPV + 2 * numPQ, 0.0);
591 NewtonRaphson(busType, voltage, power, numPV, numPQ, dPdQ, inertia);
595 m_iterations = iteration;
598 for (
int i = 0; i < m_numberOfBuses; i++) {
599 std::complex<double> sBus = std::complex<double>(0.0, 0.0);
600 for (
int j = 0; j < m_numberOfBuses; j++) sBus += voltage[i] * std::conj(voltage[j]) * std::conj(m_yBus[i][j]);
609void PowerFlow::ResetVoltages()
614 data.voltage = std::complex<double>(1.0, 0.0);
615 if (data.isVoltageControlled) {
616 data.voltage = std::complex<double>(data.controlledVoltage, 0.0);
620 data.voltage = std::complex<double>(0.0, 0.0);
621 data.harmonicOrder.clear();
622 data.harmonicVoltage.clear();
624 bus->SetElectricalData(data);
628void PowerFlow::GetNumPVPQ(std::vector<BusType> busType,
int& numPQ,
int& numPV)
632 for (
auto it = busType.begin(), itEnd = busType.end(); it != itEnd; ++it) {
640double PowerFlow::GaussSeidel(std::vector<BusType> busType,
641 std::vector<std::complex<double> >& voltage,
642 std::vector<std::complex<double> > oldVoltage,
643 std::vector<std::complex<double> >& power,
648 for (
int i = 0; i < m_numberOfBuses; i++) {
649 if (busType[i] ==
BUS_PQ) {
650 std::complex<double> yeSum(0.0, 0.0);
651 for (
int k = 0; k < m_numberOfBuses; k++) {
654 yeSum += m_yBus[i][k] * voltage[k];
659 std::complex<double> newVolt = (1.0 / m_yBus[i][i]) * (std::conj(power[i]) / std::conj(voltage[i]) - yeSum);
662 newVolt = std::complex<double>(accFactor * (newVolt.real() - voltage[i].real()) + voltage[i].real(),
663 accFactor * (newVolt.imag() - voltage[i].imag()) + voltage[i].imag());
665 voltage[i] = newVolt;
667 if (busType[i] ==
BUS_PV) {
668 std::complex<double> yeSum(0.0, 0.0);
669 for (
int k = 0; k < m_numberOfBuses; k++) {
672 yeSum += m_yBus[i][k] * voltage[k];
675 std::complex<double> yeSumT = yeSum + (m_yBus[i][i] * voltage[i]);
678 std::complex<double> qCalc = std::conj(voltage[i]) * yeSumT;
679 power[i] = std::complex<double>(power[i].real(), -qCalc.imag());
682 std::complex<double> newVolt = (1.0 / m_yBus[i][i]) * (std::conj(power[i]) / std::conj(voltage[i]) - yeSum);
685 newVolt = std::complex<double>(accFactor * (newVolt.real() - voltage[i].real()) + voltage[i].real(),
686 accFactor * (newVolt.imag() - voltage[i].imag()) + voltage[i].imag());
689 voltage[i] = std::complex<double>(std::abs(voltage[i]) * std::cos(std::arg(newVolt)),
690 std::abs(voltage[i]) * std::sin(std::arg(newVolt)));
693 double busError = std::max(std::abs(voltage[i].real() - oldVoltage[i].real()),
694 std::abs(voltage[i].imag() - oldVoltage[i].imag()));
696 if (busError > error) error = busError;
701void PowerFlow::NewtonRaphson(std::vector<BusType> busType,
702 std::vector<std::complex<double> >& voltage,
703 std::vector<std::complex<double> > power,
706 std::vector<double> dPdQ,
710 std::vector<std::vector<double> > jacobMatrix = CalculateJacobianMatrix(voltage, power, busType, numPV, numPQ);
713 for (
unsigned int i = 0; i < dPdQ.size(); ++i) { dPdQ[i] = inertia * dPdQ[i]; }
720 int indexDV = numPQ + numPV;
721 for (
int i = 0; i < m_numberOfBuses; i++) {
723 if (busType[i] ==
BUS_PV) {
724 double newV = std::abs(voltage[i]);
725 double newT = std::arg(voltage[i]) + dTdV[indexDT];
726 voltage[i] = std::complex<double>(newV * std::cos(newT), newV * std::sin(newT));
731 double newV = std::abs(voltage[i]) + dTdV[indexDV];
732 double newT = std::arg(voltage[i]) + dTdV[indexDT];
733 voltage[i] = std::complex<double>(newV * std::cos(newT), newV * std::sin(newT));
741std::vector<std::vector<double>>
742PowerFlow::CalculateJacobianMatrix(
743 const std::vector<std::complex<double>>& voltage,
744 const std::vector<std::complex<double>>& power,
745 const std::vector<BusType>& busType,
749 int nvar = 2 * numPQ + numPV;
751 std::vector<std::vector<double>> J(nvar, std::vector<double>(nvar, 0.0));
753 int n = m_numberOfBuses;
756 std::vector<double> V(n);
757 std::vector<double> T(n);
759 for (
int i = 0; i < n; i++)
761 V[i] = std::abs(voltage[i]);
762 T[i] = std::arg(voltage[i]);
766 std::vector<std::complex<double>> I(n);
768 for (
int i = 0; i < n; i++)
771 for (
int k = 0; k < n; k++)
772 I[i] += m_yBus[i][k] * voltage[k];
776 std::vector<std::complex<double>> S(n);
778 for (
int i = 0; i < n; i++)
779 S[i] = voltage[i] * std::conj(I[i]);
782 int rowQ = numPV + numPQ;
784 for (
int i = 0; i < n; i++)
790 int colV = numPV + numPQ;
792 for (
int j = 0; j < n; j++)
797 double G = m_yBus[i][j].real();
798 double B = m_yBus[i][j].imag();
800 double dtheta = T[i] - T[j];
804 double Pi = S[i].real();
805 double Qi = S[i].imag();
808 J[rowP][colTheta] = -Qi - B * V[i] * V[i];
812 J[rowQ][colTheta] = Pi - G * V[i] * V[i];
817 J[rowP][colTheta] = V[i] * V[j] * (G * sin(dtheta) - B * cos(dtheta));
820 J[rowQ][colTheta] = -V[i] * V[j] * (G * cos(dtheta) + B * sin(dtheta));
828 for (
int j = 0; j < n; j++)
833 double G = m_yBus[i][j].real();
834 double B = m_yBus[i][j].imag();
836 double dtheta = T[i] - T[j];
840 double Pi = S[i].real();
841 double Qi = S[i].imag();
844 J[rowP][colV] = Pi / V[i] + G * V[i];
847 J[rowQ][colV] = Qi / V[i] - B * V[i];
852 J[rowP][colV] = V[i] * (G * cos(dtheta) + B * sin(dtheta));
855 J[rowQ][colV] = V[i] * (G * sin(dtheta) - B * cos(dtheta));
868bool PowerFlow::CheckReactiveLimits(std::vector<BusType>& busType,
869 std::vector<ReactiveLimits>& reactiveLimit,
870 std::vector<std::complex<double> >& power,
871 std::vector<std::complex<double> > loadPower)
873 bool limitReach =
false;
874 for (
int i = 0; i < m_numberOfBuses; i++) {
875 if (busType[i] ==
BUS_PV) {
876 if (reactiveLimit[i].maxLimitType ==
RL_LIMITED) {
877 if (power[i].imag() - loadPower[i].imag() > reactiveLimit[i].maxLimit) {
878 power[i] = std::complex<double>(power[i].real(), reactiveLimit[i].maxLimit + loadPower[i].imag());
884 if (reactiveLimit[i].minLimitType ==
RL_LIMITED) {
885 if (power[i].imag() - loadPower[i].imag() < reactiveLimit[i].minLimit) {
886 power[i] = std::complex<double>(power[i].real(), reactiveLimit[i].minLimit + loadPower[i].imag());
897bool PowerFlow::CalculateMotorsReactivePower(std::vector<std::complex<double> > voltage,
898 std::vector<std::complex<double> >& power)
902 auto data = motor->GetElectricalData();
903 if (motor->
IsOnline() && data.calcQInPowerFlow) {
904 double oldQ = data.qValue;
905 if (!motor->CalculateReactivePower(std::abs(voltage[data.busNum])))
return false;
906 double dQ = oldQ - motor->GetElectricalData().qValue;
907 power[data.busNum] += std::complex<double>(0.0, dQ);
Node for power elements. All others power elements are connected through this.
Element to connect ATP-EMTP.
Base class for electrical calculations providing general utility methods.
std::vector< Bus * > m_busList
List of buses in the system.
virtual void UpdateElementsPowerFlow(std::vector< std::complex< double > > voltage, std::vector< std::complex< double > > power, std::vector< BusType > busType, std::vector< ReactiveLimits > reactiveLimit, double systemPowerBase)
Update the elements after the power flow calculation.
std::vector< Load * > m_loadList
List of load elements in the system.
bool CalculateEMTElementsAdmittance(const double &basePower, wxString &errorMsg)
Calculate the admittance of EMT elements.
double CalculateEMTPowerError(const std::vector< std::complex< double > > &voltage, std::vector< std::complex< double > > &power, const double &basePower, wxString &errorMsg)
Calculate the power mismatch error for EMT simulation.
std::vector< IndMotor * > m_indMotorList
List of induction motors in the system.
bool CalculateEMTElementsPower(const double &basePower, wxString &errorMsg, bool updateCurrent=true)
Calculate the power of EMT elements.
std::vector< SyncGenerator * > m_syncGeneratorList
List of synchronous generators in the system.
std::vector< EMTElement * > m_emtElementList
List of electromagnetic transient (EMT) elements in the system.
std::vector< std::complex< double > > GaussianElimination(std::vector< std::vector< std::complex< double > > > matrix, std::vector< std::complex< double > > array)
Solve a linear system using Gaussian elimination (complex version).
virtual bool GetYBus(std::vector< std::vector< std::complex< double > > > &yBus, double systemPowerBase, YBusSequence sequence=POSITIVE_SEQ, bool includeSyncMachines=false, bool allLoadsAsImpedances=false, bool usePowerFlowVoltagesOnImpedances=false)
Get the admittance matrix from the list of elements (use GetElementsFromList first).
std::vector< SyncMotor * > m_syncMotorList
List of synchronous motors in the system.
virtual std::vector< Element * > GetParentList() const
Get the parent list.
bool IsOnline() const
Checks if the element is online or offline.
Induction motor power element.
Loas shunt power element.
Synchronous generator power element.
Synchronous motor (synchronous compensator) power element.