Power System Platform  2026w34a-beta
Loading...
Searching...
No Matches
ElectricCalculation Class Reference

Base class for electrical calculations providing general utility methods. More...

#include <ElectricCalculation.h>

Inheritance diagram for ElectricCalculation:

Public Member Functions

 ElectricCalculation ()
 Constructor.
 
 ~ElectricCalculation ()
 Destructor.
 
virtual void GetElementsFromList (std::vector< Element * > elementList)
 Separate the power elements from a generic list.
 
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).
 
virtual bool InvertMatrix (std::vector< std::vector< std::complex< double > > > matrix, std::vector< std::vector< std::complex< double > > > &inverse)
 Invert a matrix.
 
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.
 
void ABCtoDQ0 (std::complex< double > complexValue, double angle, double &dValue, double &qValue)
 Convert a complex phasor in ABC representation to DQ components.
 
void DQ0toABC (double dValue, double qValue, double angle, std::complex< double > &complexValue)
 Convert DQ components to a complex phasor in ABC representation.
 
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).
 
std::vector< double > GaussianElimination (std::vector< std::vector< double > > matrix, std::vector< double > array)
 Solve a linear system using Gaussian elimination (real version).
 
Machines::SyncMachineModel GetMachineModel (SyncGenerator *generator)
 Get the synchronous machine model used by the generator based on user-defined parameters.
 
std::vector< std::complex< double > > ComplexMatrixTimesVector (std::vector< std::vector< std::complex< double > > > matrix, std::vector< std::complex< double > > vector)
 Multiply a complex matrix by a complex vector.
 
void GetLUDecomposition (std::vector< std::vector< std::complex< double > > > matrix, std::vector< std::vector< std::complex< double > > > &matrixL, std::vector< std::vector< std::complex< double > > > &matrixU)
 Compute the LU decomposition of a matrix.
 
std::vector< std::complex< double > > LUEvaluate (std::vector< std::vector< std::complex< double > > > u, std::vector< std::vector< std::complex< double > > > l, std::vector< std::complex< double > > b)
 Solve a linear system using LU decomposition.
 
bool GetParentBus (Element *childElement, Bus *&parentBus)
 Get the parent bus of a given shunt element.
 
bool GetParentBus (Element *childElement, Bus *&parentBus1, Bus *&parentBus2)
 Get the parent buses of a two-terminal element (branch).
 
bool CalculateEMTElementsAdmittance (const double &basePower, wxString &errorMsg)
 Calculate the admittance of EMT elements.
 
bool CalculateEMTElementsPower (const double &basePower, wxString &errorMsg, bool updateCurrent=true)
 Calculate the power 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.
 
const std::vector< PowerElement * > GetPowerElementList () const
 Get the power elements of the system (use GetElementsFromList first).
 
const std::vector< Bus * > GetBusList () const
 Get the buses of the system (use GetElementsFromList first).
 
const std::vector< Capacitor * > GetCapacitorList () const
 Get the capacitors of the system (use GetElementsFromList first).
 
const std::vector< IndMotor * > GetIndMotorList () const
 Get the induction motors of the system (use GetElementsFromList first).
 
const std::vector< Inductor * > GetInductorList () const
 Get the inductors of the system (use GetElementsFromList first).
 
const std::vector< Line * > GetLineList () const
 Get the lines of the system (use GetElementsFromList first).
 
const std::vector< Load * > GetLoadList () const
 Get the loads of the system (use GetElementsFromList first).
 
const std::vector< SyncGenerator * > GetSyncGeneratorList () const
 Get the synchronous generators of the system (use GetElementsFromList first).
 
const std::vector< SyncMotor * > GetSyncMotorList () const
 Get the synchronous motors of the system (use GetElementsFromList first).
 
const std::vector< Transformer * > GetTransformerList () const
 Get the transformers of the system (use GetElementsFromList first).
 
const std::vector< HarmCurrent * > GetHarmCurrentList () const
 Get the harmonic current source of the system (use GetElementsFromList first).
 
const std::vector< EMTElement * > GetEMTElementList () const
 Get the electromagnetic element list of the system (use GetElementsFromList first).
 

Protected Member Functions

void GetNextConnection (const unsigned int &checkBusNumber, const std::vector< std::vector< std::complex< double > > > &yBus, std::vector< bool > &connToSlack)
 Recursively check if a bus is electrically connected to the slack bus.
 
void DistributeReactivePower (std::vector< ReactiveMachine > &machines, double qTotal)
 Distribute reactive power among synchronous machines connected to the same bus.
 

Protected Attributes

std::vector< PowerElement * > m_powerElementList
 List of power elements in the system.
 
std::vector< Bus * > m_busList
 List of buses in the system.
 
std::vector< Capacitor * > m_capacitorList
 List of capacitor elements in the system.
 
std::vector< IndMotor * > m_indMotorList
 List of induction motors in the system.
 
std::vector< Inductor * > m_inductorList
 List of inductors in the system.
 
std::vector< Line * > m_lineList
 List of transmission lines in the system.
 
std::vector< Load * > m_loadList
 List of load elements in the system.
 
std::vector< SyncGenerator * > m_syncGeneratorList
 List of synchronous generators in the system.
 
std::vector< SyncMotor * > m_syncMotorList
 List of synchronous motors in the system.
 
std::vector< Transformer * > m_transformerList
 List of transformers in the system.
 
std::vector< HarmCurrent * > m_harmCurrentList
 List of harmonic current sources in the system.
 
std::vector< EMTElement * > m_emtElementList
 List of electromagnetic transient (EMT) elements in the system.
 

Detailed Description

Base class for electrical calculations providing general utility methods.

Author
Thales Lima Oliveira
Date
09/01/2017

This class provides common utilities used by different electrical calculations such as power flow, short-circuit analysis and EMT simulations.

Definition at line 115 of file ElectricCalculation.h.

Constructor & Destructor Documentation

◆ ElectricCalculation()

ElectricCalculation::ElectricCalculation ( )

Constructor.

Definition at line 25 of file ElectricCalculation.cpp.

25{}

◆ ~ElectricCalculation()

ElectricCalculation::~ElectricCalculation ( )

Destructor.

Definition at line 26 of file ElectricCalculation.cpp.

26{}

Member Function Documentation

◆ ABCtoDQ0()

void ElectricCalculation::ABCtoDQ0 ( std::complex< double >  complexValue,
double  angle,
double &  dValue,
double &  qValue 
)

Convert a complex phasor in ABC representation to DQ components.

Parameters
complexValueComplex phasor value in ABC reference frame.
angleElectrical angle used for the transformation.
dValueResulting direct-axis component.
qValueResulting quadrature-axis component.

Definition at line 861 of file ElectricCalculation.cpp.

862{
863 dValue = -std::real(complexValue) * std::sin(angle) + std::imag(complexValue) * std::cos(angle);
864 qValue = std::real(complexValue) * std::cos(angle) + std::imag(complexValue) * std::sin(angle);
865}

◆ CalculateEMTElementsAdmittance()

bool ElectricCalculation::CalculateEMTElementsAdmittance ( const double &  basePower,
wxString &  errorMsg 
)

Calculate the admittance of EMT elements.

Parameters
basePowerSystem base power.
errorMsgError message in case of failure.
Returns
True if the calculation was successful.

Definition at line 1089 of file ElectricCalculation.cpp.

1090{
1091 for (EMTElement* emtElement : m_emtElementList) {
1092 if (!emtElement->IsOnline()) continue;
1093
1094 emtElement->UpdateData();
1095 if (!emtElement->CalculateCurrent(errorMsg)) return false;
1096 auto data = emtElement->GetEMTElementData();
1097 double baseCurrent = basePower / (sqrt(3.0) * data.baseVoltage);
1098 std::complex<double> current = data.currHarmonics[1] / baseCurrent; // Fundamental frequency current
1099 std::complex<double> y0 = current / data.puVoltage;
1100 data.y0 = y0;
1101 data.power = std::complex<double>(0.0, 0.0);
1102 emtElement->SetEMTElementData(data);
1103 }
1104 return true;
1105}
Element to connect ATP-EMTP.
Definition EMTElement.h:83
std::vector< EMTElement * > m_emtElementList
List of electromagnetic transient (EMT) elements in the system.

◆ CalculateEMTElementsPower()

bool ElectricCalculation::CalculateEMTElementsPower ( const double &  basePower,
wxString &  errorMsg,
bool  updateCurrent = true 
)

Calculate the power of EMT elements.

Parameters
basePowerSystem base power.
errorMsgError message in case of failure.
updateCurrentIf true, update the element currents during the calculation unsing EMTElement::CalculateCurrent(wxString&, const bool&).
Returns
True if the calculation was successful.

Definition at line 1107 of file ElectricCalculation.cpp.

1108{
1109 for (EMTElement* emtElement : m_emtElementList) {
1110 if (!emtElement->IsOnline()) continue;
1111
1112 emtElement->UpdateData();
1113 if (updateCurrent) {
1114 if (!emtElement->CalculateCurrent(errorMsg)) return false;
1115 }
1116 auto data = emtElement->GetEMTElementData();
1117 double baseCurrent = basePower / (sqrt(3.0) * data.baseVoltage);
1118 //std::complex<double> current = data.currHarmonics[1];
1119 std::complex<double> current = data.currHarmonics[1] / baseCurrent; // Fundamental frequency current
1120
1121 std::complex<double> i0 = data.y0 * data.puVoltage; // Current already injected via admittance matrix
1122 //std::complex<double> voltage = data.baseVoltage * data.puVoltage;
1123 //std::complex<double> power = (sqrt(3.0) * voltage * std::conj(current)) / basePower;
1124 std::complex<double> power = data.puVoltage * std::conj(current - i0);
1125 data.powerDiff = power - data.power;
1126 data.power = power;
1127 emtElement->SetEMTElementData(data);
1128
1129 //wxString currentStr = data.name + ":\n";
1130 //for (auto const& [harm, current] : data.currHarmonics)
1131 //{
1132 // currentStr += wxString::Format("I(%dh) = %f p.u.\n", harm, abs(current) / baseCurrent);
1133 //}
1134 //currentStr += wxString::Format("S = %e + j%e p.u.\n", data.power.real(), data.power.imag());
1135 //currentStr += wxString::Format("SDiff = %e p.u.\n", abs(data.powerDiff));
1136 //wxMessageBox(currentStr);
1137 }
1138 return true;
1139}
Here is the caller graph for this function:

◆ CalculateEMTPowerError()

double ElectricCalculation::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.

Parameters
voltageVector with bus voltages.
powerVector with injected powers.
basePowerSystem base power.
errorMsgError message in case of failure.
Returns
The calculated power error.

Definition at line 1141 of file ElectricCalculation.cpp.

1142{
1143 // Update buses voltages
1144 for (Bus* bus : m_busList) {
1145 auto data = bus->GetElectricalData();
1146 if (data.isConnected) {
1147 data.voltage = voltage[data.number];
1148 bus->SetElectricalData(data);
1149 }
1150 }
1151
1152 CalculateEMTElementsPower(basePower, errorMsg);
1153 // Update power array and calculate error
1154 double error = 0.0;
1155 for (EMTElement* emtElement : m_emtElementList) {
1156 if (!emtElement->IsOnline()) continue;
1157
1158 if (!emtElement->GetParentList().empty()) {
1159 if (emtElement->GetParentList()[0] != nullptr) {
1160 int numBus = static_cast<Bus*>(emtElement->GetParentList()[0])->GetElectricalData().number;
1161 auto data = emtElement->GetEMTElementData();
1162 power[numBus] += data.powerDiff;
1163 if (error < std::abs(data.powerDiff))
1164 error = std::abs(data.powerDiff);
1165 }
1166 }
1167 }
1168
1169 return error;
1170}
Node for power elements. All others power elements are connected through this.
Definition Bus.h:87
std::vector< Bus * > m_busList
List of buses in the system.
bool CalculateEMTElementsPower(const double &basePower, wxString &errorMsg, bool updateCurrent=true)
Calculate the power of EMT elements.
Here is the call graph for this function:

◆ ComplexMatrixTimesVector()

std::vector< std::complex< double > > ElectricCalculation::ComplexMatrixTimesVector ( std::vector< std::vector< std::complex< double > > >  matrix,
std::vector< std::complex< double > >  vector 
)

Multiply a complex matrix by a complex vector.

Parameters
matrixComplex matrix.
vectorComplex vector.
Returns
Resulting complex vector.

Definition at line 978 of file ElectricCalculation.cpp.

981{
982 std::vector<std::complex<double> > solution;
983 for (unsigned int i = 0; i < matrix.size(); i++) {
984 solution.push_back(std::complex<double>(0.0, 0.0));
985
986 for (unsigned int j = 0; j < matrix.size(); j++) { solution[i] += matrix[i][j] * vector[j]; }
987 }
988
989 return solution;
990}

◆ DistributeReactivePower()

void ElectricCalculation::DistributeReactivePower ( std::vector< ReactiveMachine > &  machines,
double  qTotal 
)
protected

Distribute reactive power among synchronous machines connected to the same bus.

The method ensures that reactive power limits of individual machines are respected during the distribution process.

Parameters
machinesList of machines participating in the reactive power sharing.
qTotalTotal reactive power to be distributed.

Definition at line 408 of file ElectricCalculation.cpp.

409{
410 int freeMachines = machines.size();
411 double qRemaining = qTotal;
412
413 bool changed = true;
414
415 while (changed && freeMachines > 0) {
416 changed = false;
417
418 double qShare = qRemaining / freeMachines;
419
420 for (auto& m : machines) {
421 if (m.fixed)
422 continue;
423
424 if (m.hasMax && qShare > m.qMax) {
425 m.q = m.qMax;
426 m.fixed = true;
427 qRemaining -= m.qMax;
428 freeMachines--;
429 changed = true;
430 }
431 else if (m.hasMin && qShare < m.qMin) {
432 m.q = m.qMin;
433 m.fixed = true;
434 qRemaining -= m.qMin;
435 freeMachines--;
436 changed = true;
437 }
438 else {
439 m.q = qShare;
440 }
441 }
442 }
443
444 if (freeMachines > 0) {
445 double qShare = qRemaining / freeMachines;
446 for (auto& m : machines) {
447 if (!m.fixed)
448 m.q = qShare;
449 }
450 }
451}
Here is the caller graph for this function:

◆ DQ0toABC()

void ElectricCalculation::DQ0toABC ( double  dValue,
double  qValue,
double  angle,
std::complex< double > &  complexValue 
)

Convert DQ components to a complex phasor in ABC representation.

Parameters
dValueDirect-axis component.
qValueQuadrature-axis component.
angleElectrical angle used for the transformation.
complexValueResulting complex phasor in ABC reference frame.

Definition at line 867 of file ElectricCalculation.cpp.

868{
869 double real = qValue * std::cos(angle) - dValue * std::sin(angle);
870 double imag = qValue * std::sin(angle) + dValue * std::cos(angle);
871 complexValue = std::complex<double>(real, imag);
872}

◆ GaussianElimination() [1/2]

std::vector< double > ElectricCalculation::GaussianElimination ( std::vector< std::vector< double > >  matrix,
std::vector< double >  array 
)

Solve a linear system using Gaussian elimination (real version).

Parameters
matrixCoefficient matrix of the system.
arrayRight-hand side vector.
Returns
Solution vector of the linear system.

Definition at line 918 of file ElectricCalculation.cpp.

920{
921 //[Ref] https://en.wikipedia.org/wiki/Gaussian_elimination
922
923 std::vector<double> solution;
924
925 std::vector<std::vector<double> > triangMatrix;
926 triangMatrix.resize(matrix.size());
927 for (unsigned int i = 0; i < matrix.size(); i++) { triangMatrix[i].resize(matrix.size()); }
928
929 for (unsigned int i = 0; i < matrix.size(); i++) { solution.push_back(array[i]); }
930
931 for (unsigned int i = 0; i < matrix.size(); i++) {
932 for (unsigned int j = 0; j < matrix.size(); j++) { triangMatrix[i][j] = matrix[i][j]; }
933 }
934
935 for (unsigned int k = 0; k < matrix.size(); k++) {
936 unsigned int k1 = k + 1;
937 for (unsigned int i = k; i < matrix.size(); i++) {
938 if (triangMatrix[i][k] != 0.0) {
939 for (unsigned int j = k1; j < matrix.size(); j++) {
940 triangMatrix[i][j] = triangMatrix[i][j] / triangMatrix[i][k];
941 }
942 solution[i] = solution[i] / triangMatrix[i][k];
943 }
944 }
945 for (unsigned int i = k1; i < matrix.size(); i++) {
946 if (triangMatrix[i][k] != 0.0) {
947 for (unsigned int j = k1; j < matrix.size(); j++) { triangMatrix[i][j] -= triangMatrix[k][j]; }
948 solution[i] -= solution[k];
949 }
950 }
951 }
952 for (int i = static_cast<int>(matrix.size()) - 2; i >= 0; i--) {
953 for (int j = static_cast<int>(matrix.size()) - 1; j >= i + 1; j--) {
954 solution[i] -= triangMatrix[i][j] * solution[j];
955 }
956 }
957
958 return solution;
959}

◆ GaussianElimination() [2/2]

std::vector< std::complex< double > > ElectricCalculation::GaussianElimination ( std::vector< std::vector< std::complex< double > > >  matrix,
std::vector< std::complex< double > >  array 
)

Solve a linear system using Gaussian elimination (complex version).

Parameters
matrixCoefficient matrix of the system.
arrayRight-hand side vector.
Returns
Solution vector of the linear system.

Definition at line 874 of file ElectricCalculation.cpp.

877{
878 //[Ref] https://en.wikipedia.org/wiki/Gaussian_elimination
879
880 std::vector<std::complex<double> > solution;
881
882 std::vector<std::vector<std::complex<double> > > triangMatrix;
883 triangMatrix.resize(matrix.size());
884 for (unsigned int i = 0; i < matrix.size(); i++) { triangMatrix[i].resize(matrix.size()); }
885
886 for (unsigned int i = 0; i < matrix.size(); i++) { solution.push_back(array[i]); }
887
888 for (unsigned int i = 0; i < matrix.size(); i++) {
889 for (unsigned int j = 0; j < matrix.size(); j++) { triangMatrix[i][j] = matrix[i][j]; }
890 }
891
892 for (unsigned int k = 0; k < matrix.size(); k++) {
893 unsigned int k1 = k + 1;
894 for (unsigned int i = k; i < matrix.size(); i++) {
895 if (triangMatrix[i][k] != std::complex<double>(0.0, 0.0)) {
896 for (unsigned int j = k1; j < matrix.size(); j++) {
897 triangMatrix[i][j] = triangMatrix[i][j] / triangMatrix[i][k];
898 }
899 solution[i] = solution[i] / triangMatrix[i][k];
900 }
901 }
902 for (unsigned int i = k1; i < matrix.size(); i++) {
903 if (triangMatrix[i][k] != std::complex<double>(0.0, 0.0)) {
904 for (unsigned int j = k1; j < matrix.size(); j++) { triangMatrix[i][j] -= triangMatrix[k][j]; }
905 solution[i] -= solution[k];
906 }
907 }
908 }
909 for (int i = static_cast<int>(matrix.size()) - 2; i >= 0; i--) {
910 for (int j = static_cast<int>(matrix.size()) - 1; j >= i + 1; j--) {
911 solution[i] -= triangMatrix[i][j] * solution[j];
912 }
913 }
914
915 return solution;
916}

◆ GetBusList()

const std::vector< Bus * > ElectricCalculation::GetBusList ( ) const
inline

Get the buses of the system (use GetElementsFromList first).

Returns
A list of bus elements.

Definition at line 298 of file ElectricCalculation.h.

298{ return m_busList; }

◆ GetCapacitorList()

const std::vector< Capacitor * > ElectricCalculation::GetCapacitorList ( ) const
inline

Get the capacitors of the system (use GetElementsFromList first).

Returns
A list of capacitor elements.

Definition at line 303 of file ElectricCalculation.h.

303{ return m_capacitorList; }
std::vector< Capacitor * > m_capacitorList
List of capacitor elements in the system.

◆ GetElementsFromList()

void ElectricCalculation::GetElementsFromList ( std::vector< Element * >  elementList)
virtual

Separate the power elements from a generic list.

Parameters
elementListList of generic elements.

Definition at line 27 of file ElectricCalculation.cpp.

28{
29 m_powerElementList.clear();
30 m_busList.clear();
31 m_capacitorList.clear();
32 m_indMotorList.clear();
33 m_inductorList.clear();
34 m_lineList.clear();
35 m_loadList.clear();
36 m_syncGeneratorList.clear();
37 m_syncMotorList.clear();
38 m_transformerList.clear();
39 m_harmCurrentList.clear();
40 m_emtElementList.clear();
41 // TODO: Bad design?
42 for (auto it = elementList.begin(); it != elementList.end(); it++) {
43 Element* element = *it;
44 m_powerElementList.push_back(static_cast<PowerElement*>(element));
45
46 if (Bus* bus = dynamic_cast<Bus*>(element))
47 m_busList.push_back(bus);
48 else if (Capacitor* capacitor = dynamic_cast<Capacitor*>(element))
49 m_capacitorList.push_back(capacitor);
50 else if (IndMotor* indMotor = dynamic_cast<IndMotor*>(element))
51 m_indMotorList.push_back(indMotor);
52 else if (Inductor* inductor = dynamic_cast<Inductor*>(element))
53 m_inductorList.push_back(inductor);
54 else if (Line* line = dynamic_cast<Line*>(element))
55 m_lineList.push_back(line);
56 else if (Load* load = dynamic_cast<Load*>(element))
57 m_loadList.push_back(load);
58 else if (SyncGenerator* syncGenerator = dynamic_cast<SyncGenerator*>(element))
59 m_syncGeneratorList.push_back(syncGenerator);
60 else if (SyncMotor* syncMotor = dynamic_cast<SyncMotor*>(element))
61 m_syncMotorList.push_back(syncMotor);
62 else if (Transformer* transformer = dynamic_cast<Transformer*>(element))
63 m_transformerList.push_back(transformer);
64 else if (HarmCurrent* harmCurrent = dynamic_cast<HarmCurrent*>(element))
65 m_harmCurrentList.push_back(harmCurrent);
66 else if (EMTElement* emtElement = dynamic_cast<EMTElement*>(element))
67 m_emtElementList.push_back(emtElement);
68 }
69
70 // Set buses numbers
71 int busNumber = 0;
72 for (auto itb = m_busList.begin(); itb != m_busList.end(); itb++) {
73 Bus* bus = *itb;
74 BusElectricalData data = bus->GetElectricalData();
75 data.number = busNumber;
76 bus->SetElectricalData(data);
77 busNumber++;
78 }
79}
Shunt capactior power element.
Definition Capacitor.h:39
std::vector< Line * > m_lineList
List of transmission lines in the system.
std::vector< PowerElement * > m_powerElementList
List of power elements in the system.
std::vector< Load * > m_loadList
List of load elements in the system.
std::vector< IndMotor * > m_indMotorList
List of induction motors in the system.
std::vector< Transformer * > m_transformerList
List of transformers in the system.
std::vector< SyncGenerator * > m_syncGeneratorList
List of synchronous generators in the system.
std::vector< SyncMotor * > m_syncMotorList
List of synchronous motors in the system.
std::vector< HarmCurrent * > m_harmCurrentList
List of harmonic current sources in the system.
std::vector< Inductor * > m_inductorList
List of inductors in the system.
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition Element.h:115
Shunt Harmonic Corrent Source.
Definition HarmCurrent.h:24
Induction motor power element.
Definition IndMotor.h:119
Inductor shunt power element.
Definition Inductor.h:39
Power line element.
Definition Line.h:64
Loas shunt power element.
Definition Load.h:74
Abstract class of power elements.
Synchronous generator power element.
Synchronous motor (synchronous compensator) power element.
Definition SyncMotor.h:135
Two-winding transformer power element with OLTC support.
Definition Transformer.h:96
Here is the caller graph for this function:

◆ GetEMTElementList()

const std::vector< EMTElement * > ElectricCalculation::GetEMTElementList ( ) const
inline

Get the electromagnetic element list of the system (use GetElementsFromList first).

Returns
A list of electromagnetic elements.

Definition at line 348 of file ElectricCalculation.h.

348{ return m_emtElementList; }

◆ GetHarmCurrentList()

const std::vector< HarmCurrent * > ElectricCalculation::GetHarmCurrentList ( ) const
inline

Get the harmonic current source of the system (use GetElementsFromList first).

Returns
A list of harmonic current sources elements.

Definition at line 343 of file ElectricCalculation.h.

343{ return m_harmCurrentList; }

◆ GetIndMotorList()

const std::vector< IndMotor * > ElectricCalculation::GetIndMotorList ( ) const
inline

Get the induction motors of the system (use GetElementsFromList first).

Returns
A list of induction motor elements.

Definition at line 308 of file ElectricCalculation.h.

308{ return m_indMotorList; }

◆ GetInductorList()

const std::vector< Inductor * > ElectricCalculation::GetInductorList ( ) const
inline

Get the inductors of the system (use GetElementsFromList first).

Returns
A list of inductor elements.

Definition at line 313 of file ElectricCalculation.h.

313{ return m_inductorList; }

◆ GetLineList()

const std::vector< Line * > ElectricCalculation::GetLineList ( ) const
inline

Get the lines of the system (use GetElementsFromList first).

Returns
A list of line elements.

Definition at line 318 of file ElectricCalculation.h.

318{ return m_lineList; }

◆ GetLoadList()

const std::vector< Load * > ElectricCalculation::GetLoadList ( ) const
inline

Get the loads of the system (use GetElementsFromList first).

Returns
A list of load elements.

Definition at line 323 of file ElectricCalculation.h.

323{ return m_loadList; }

◆ GetLUDecomposition()

void ElectricCalculation::GetLUDecomposition ( std::vector< std::vector< std::complex< double > > >  matrix,
std::vector< std::vector< std::complex< double > > > &  matrixL,
std::vector< std::vector< std::complex< double > > > &  matrixU 
)

Compute the LU decomposition of a matrix.

Parameters
matrixMatrix to be decomposed.
matrixLLower triangular matrix.
matrixUUpper triangular matrix.

Definition at line 992 of file ElectricCalculation.cpp.

995{
996 // Doolittle method
997 // [Ref] http://www3.nd.edu/~zxu2/acms40390F11/Alg-LU-Crout.pdf
998 // [Ref] http://www.engr.colostate.edu/~thompson/hPage/CourseMat/Tutorials/CompMethods/doolittle.pdf
999
1000 int size = static_cast<int>(matrix.size()); // Decomposed matrix size.
1001
1002 // Set upper and lower matrices sizes.
1003 matrixL.resize(size);
1004 matrixU.resize(size);
1005 for (int i = 0; i < size; i++) {
1006 matrixL[i].resize(size);
1007 matrixU[i].resize(size);
1008 }
1009
1010 // First row of upper matrix and first column of lower matrix.
1011 for (int i = 0; i < size; i++) {
1012 matrixU[0][i] = matrix[0][i];
1013 matrixL[i][0] = matrix[i][0] / matrixU[0][0];
1014 }
1015
1016 // Lower matrix main diagonal.
1017 for (int i = 1; i < size; i++) { matrixL[i][i] = std::complex<double>(1.0, 0.0); }
1018
1019 for (int i = 1; i < size - 1; i++) {
1020 // Upper matrix main diagonal.
1021 matrixU[i][i] = matrix[i][i];
1022 for (int k = 0; k < i; k++) { matrixU[i][i] -= matrixL[i][k] * matrixU[k][i]; }
1023
1024 // Others elements of upper matrix
1025 for (int j = i + 1; j < size; j++) {
1026 matrixU[i][j] = matrix[i][j];
1027 for (int k = 0; k < i; k++) { matrixU[i][j] -= matrixL[i][k] * matrixU[k][j]; }
1028 }
1029
1030 // Lower matrix elements
1031 for (int j = i + 1; j < size; j++) {
1032 matrixL[j][i] = matrix[j][i];
1033 for (int k = 0; k < i; k++) { matrixL[j][i] -= matrixL[j][k] * matrixU[k][i]; }
1034 matrixL[j][i] = matrixL[j][i] / matrixU[i][i];
1035 }
1036 }
1037
1038 // Last element of upper matrix.
1039 matrixU[size - 1][size - 1] = matrix[size - 1][size - 1];
1040 for (int k = 0; k < size - 1; k++) { matrixU[size - 1][size - 1] -= matrixL[size - 1][k] * matrixU[k][size - 1]; }
1041}

◆ GetMachineModel()

Machines::SyncMachineModel ElectricCalculation::GetMachineModel ( SyncGenerator *  generator)

Get the synchronous machine model used by the generator based on user-defined parameters.

Parameters
generatorPointer to the synchronous generator.
Returns
Enumeration indicating the synchronous machine model.

Definition at line 961 of file ElectricCalculation.cpp.

962{
963 auto data = generator->GetElectricalData();
964 if (data.transTd0 != 0.0) {
965 if (data.transTq0 != 0.0) {
966 if (data.subTd0 != 0.0 || data.subTq0 != 0.0) { return Machines::SM_MODEL_5; }
967 return Machines::SM_MODEL_3;
968 }
969 else {
970 if (data.subTd0 != 0.0 || data.subTq0 != 0.0) { return Machines::SM_MODEL_4; }
971 return Machines::SM_MODEL_2;
972 }
973 }
974
975 return Machines::SM_MODEL_1;
976}

◆ GetNextConnection()

void ElectricCalculation::GetNextConnection ( const unsigned int &  checkBusNumber,
const std::vector< std::vector< std::complex< double > > > &  yBus,
std::vector< bool > &  connToSlack 
)
protected

Recursively check if a bus is electrically connected to the slack bus.

Parameters
checkBusNumberIndex of the bus being checked.
yBusAdmittance matrix of the system.
connToSlackBoolean vector indicating if each bus is connected to the slack bus.

Definition at line 392 of file ElectricCalculation.cpp.

395{
396 for (unsigned int i = 0; i < yBus.size(); i++) {
397
398 if (i != checkBusNumber && !connToSlack[i]) {
399 if (std::abs(yBus[i][checkBusNumber]) > 1e-6)
400 {
401 connToSlack[i] = true;
402 GetNextConnection(i, yBus, connToSlack);
403 }
404 }
405 }
406}
void GetNextConnection(const unsigned int &checkBusNumber, const std::vector< std::vector< std::complex< double > > > &yBus, std::vector< bool > &connToSlack)
Recursively check if a bus is electrically connected to the slack bus.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetParentBus() [1/2]

bool ElectricCalculation::GetParentBus ( Element *  childElement,
Bus *&  parentBus 
)

Get the parent bus of a given shunt element.

Parameters
childElementPointer to the element.
parentBusPointer to the parent bus.
Returns
True if the parent bus was successfully found.

Definition at line 1068 of file ElectricCalculation.cpp.

1069{
1070 auto parentList = childElement->GetParentList();
1071 if (parentList.size() < 1) return false;
1072 parentBus = static_cast<Bus*>(parentList[0]);
1073 if (parentBus == nullptr) return false;
1074 if (parentBus->GetElectricalData().number < 0) return false;
1075 return true;
1076}
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition Element.h:567
Here is the call graph for this function:

◆ GetParentBus() [2/2]

bool ElectricCalculation::GetParentBus ( Element *  childElement,
Bus *&  parentBus1,
Bus *&  parentBus2 
)

Get the parent buses of a two-terminal element (branch).

Parameters
childElementPointer to the element.
parentBus1Pointer to the first parent bus.
parentBus2Pointer to the second parent bus.
Returns
True if both parent buses were successfully found.

Definition at line 1078 of file ElectricCalculation.cpp.

1079{
1080 auto parentList = childElement->GetParentList();
1081 if (parentList.size() < 2) return false;
1082 parentBus1 = static_cast<Bus*>(parentList[0]);
1083 parentBus2 = static_cast<Bus*>(parentList[1]);
1084 if (parentBus1 == nullptr || parentBus2 == nullptr) return false;
1085 if (parentBus1->GetElectricalData().number < 0 || parentBus2->GetElectricalData().number < 0) return false;
1086 return true;
1087}
Here is the call graph for this function:

◆ GetPowerElementList()

const std::vector< PowerElement * > ElectricCalculation::GetPowerElementList ( ) const
inline

Get the power elements of the system (use GetElementsFromList first).

Returns
A list of power elements.

Definition at line 293 of file ElectricCalculation.h.

293{ return m_powerElementList; }

◆ GetSyncGeneratorList()

const std::vector< SyncGenerator * > ElectricCalculation::GetSyncGeneratorList ( ) const
inline

Get the synchronous generators of the system (use GetElementsFromList first).

Returns
A list of synchronous generator elements.

Definition at line 328 of file ElectricCalculation.h.

328{ return m_syncGeneratorList; }

◆ GetSyncMotorList()

const std::vector< SyncMotor * > ElectricCalculation::GetSyncMotorList ( ) const
inline

Get the synchronous motors of the system (use GetElementsFromList first).

Returns
A list of synchronous motor elements.

Definition at line 333 of file ElectricCalculation.h.

333{ return m_syncMotorList; }

◆ GetTransformerList()

const std::vector< Transformer * > ElectricCalculation::GetTransformerList ( ) const
inline

Get the transformers of the system (use GetElementsFromList first).

Returns
A list of transformer elements.

Definition at line 338 of file ElectricCalculation.h.

338{ return m_transformerList; }

◆ GetYBus()

bool ElectricCalculation::GetYBus ( std::vector< std::vector< std::complex< double > > > &  yBus,
double  systemPowerBase,
YBusSequence  sequence = POSITIVE_SEQ,
bool  includeSyncMachines = false,
bool  allLoadsAsImpedances = false,
bool  usePowerFlowVoltagesOnImpedances = false 
)
virtual

Get the admittance matrix from the list of elements (use GetElementsFromList first).

Parameters
yBusAdmittance matrix. The previous content will be erased.
systemPowerBaseBase power of the system.
sequenceSequence of admittance matrix (positive, negative and zero).
includeSyncMachinesInclude the synchronous machines on calculation.
Returns
Return true if was possible to build the admittance matrix.

Definition at line 81 of file ElectricCalculation.cpp.

87{
88 if (m_busList.size() == 0) return false;
89
90 // Clear and fill with zeros the Ybus
91 yBus.clear();
92 for (int i = 0; i < (int)m_busList.size(); i++) {
93 std::vector<std::complex<double> > line;
94 for (int j = 0; j < (int)m_busList.size(); j++) { line.push_back(std::complex<double>(0.0, 0.0)); }
95 yBus.push_back(line);
96 }
97
98 // Set buses numbers and reset connection status
99 int busNumber = 0;
100 for (auto itb = m_busList.begin(); itb != m_busList.end(); itb++) {
101 Bus* bus = *itb;
102 BusElectricalData data = bus->GetElectricalData();
103 data.number = busNumber;
104 data.isConnected = true;
105 //data.voltage = std::complex<double>(1.0, 0.0);
106 bus->SetElectricalData(data);
107 busNumber++;
108 }
109
110 // Load
111 for (auto it = m_loadList.begin(), itEnd = m_loadList.end(); it != itEnd; ++it) {
112 Load* load = *it;
113 if (load->IsOnline()) {
114 int n = static_cast<Bus*>(load->GetParentList()[0])->GetElectricalData().number;
115 LoadElectricalData data = load->GetPUElectricalData(systemPowerBase);
116 if (data.loadType == CONST_IMPEDANCE || allLoadsAsImpedances) {
117 std::complex<double> yLoad = std::complex<double>(data.activePower, -data.reactivePower);
118 if (allLoadsAsImpedances && usePowerFlowVoltagesOnImpedances) {
119 std::complex<double> v = static_cast<Bus*>(load->GetParentList()[0])->GetElectricalData().voltage;
120 yLoad /= (std::abs(v) * std::abs(v));
121 }
122 yBus[n][n] += yLoad;
123 }
124 }
125 }
126
127 // Capacitor
128 for (auto it = m_capacitorList.begin(), itEnd = m_capacitorList.end(); it != itEnd; ++it) {
129 Capacitor* capacitor = *it;
130 if (capacitor->IsOnline()) {
131 int n = static_cast<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().number;
132 CapacitorElectricalData data = capacitor->GetPUElectricalData(systemPowerBase);
133 yBus[n][n] += std::complex<double>(0.0, data.reactivePower);
134 }
135 }
136
137 // Inductor
138 for (auto it = m_inductorList.begin(), itEnd = m_inductorList.end(); it != itEnd; ++it) {
139 Inductor* inductor = *it;
140 if (inductor->IsOnline()) {
141 int n = static_cast<Bus*>(inductor->GetParentList()[0])->GetElectricalData().number;
142 InductorElectricalData data = inductor->GetPUElectricalData(systemPowerBase);
143 yBus[n][n] += std::complex<double>(0.0, -data.reactivePower);
144 }
145 }
146
147 //EMT Elements
148 for (EMTElement* emtElement : m_emtElementList) {
149 if (emtElement->IsOnline()) {
150 auto data = emtElement->GetEMTElementData();
151 int n = static_cast<Bus*>(emtElement->GetParentList()[0])->GetElectricalData().number;
152 yBus[n][n] += data.y0;
153 //wxMessageBox(wxString::Format("%f +j %f", data.y0.real(), data.y0.imag()));
154 }
155 }
156
157 // Power line
158 for (auto it = m_lineList.begin(), itEnd = m_lineList.end(); it != itEnd; ++it) {
159 Line* line = *it;
160 if (line->IsOnline()) {
161 LineElectricalData data = line->GetPUElectricalData(systemPowerBase);
162
163 int n1 = static_cast<Bus*>(line->GetParentList()[0])->GetElectricalData().number;
164 int n2 = static_cast<Bus*>(line->GetParentList()[1])->GetElectricalData().number;
165
166 switch (sequence) {
167 case POSITIVE_SEQ:
168 case NEGATIVE_SEQ: {
169 yBus[n1][n2] -= 1.0 / std::complex<double>(data.resistance, data.indReactance);
170 yBus[n2][n1] -= 1.0 / std::complex<double>(data.resistance, data.indReactance);
171
172 yBus[n1][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
173 yBus[n2][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
174
175 yBus[n1][n1] += std::complex<double>(0.0, data.capSusceptance / 2.0);
176 yBus[n2][n2] += std::complex<double>(0.0, data.capSusceptance / 2.0);
177 } break;
178 case ZERO_SEQ: {
179 yBus[n1][n2] -= 1.0 / std::complex<double>(data.zeroResistance, data.zeroIndReactance);
180 yBus[n2][n1] -= 1.0 / std::complex<double>(data.zeroResistance, data.zeroIndReactance);
181
182 yBus[n1][n1] += 1.0 / std::complex<double>(data.zeroResistance, data.zeroIndReactance);
183 yBus[n2][n2] += 1.0 / std::complex<double>(data.zeroResistance, data.zeroIndReactance);
184
185 yBus[n1][n1] += std::complex<double>(0.0, data.zeroCapSusceptance / 2.0);
186 yBus[n2][n2] += std::complex<double>(0.0, data.zeroCapSusceptance / 2.0);
187 }
188 }
189 }
190 }
191
192 // Transformer
193 for (auto it = m_transformerList.begin(), itEnd = m_transformerList.end(); it != itEnd; ++it) {
194 Transformer* transformer = *it;
195
196 if (transformer->IsOnline()) {
197 TransformerElectricalData data = transformer->GetPUElectricalData(systemPowerBase);
198
199 int n1 = static_cast<Bus*>(transformer->GetParentList()[0])->GetElectricalData().number;
200 int n2 = static_cast<Bus*>(transformer->GetParentList()[1])->GetElectricalData().number;
201
202 // If the transformer have nominal turns ratio (1.0) and no phase shifting, it will be modelled as series
203 // impedance.
204 if (data.turnsRatio == 1.0 && data.phaseShift == 0.0 && sequence != ZERO_SEQ) {
205 yBus[n1][n2] += -1.0 / std::complex<double>(data.resistance, data.indReactance);
206 yBus[n2][n1] += -1.0 / std::complex<double>(data.resistance, data.indReactance);
207
208 yBus[n1][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
209 yBus[n2][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
210 }
211 // If the transformer have no-nominal turn ratio and/or phase shifting, it will be modelled in a different
212 // way (see references).
213 //[Ref. 1: Elementos de analise de sistemas de potencia - Stevenson - pg. 232]
214 //[Ref. 2: http://www.ee.washington.edu/research/real/Library/Reports/Tap_Adjustments_in_AC_Load_Flows.pdf]
215 //[Ref. 3: http://www.columbia.edu/~dano/courses/power/notes/power/andersson1.pdf]
216 else if (sequence != ZERO_SEQ) {
217 // Complex turns ratio
218 double radPhaseShift = wxDegToRad(data.phaseShift);
219 std::complex<double> a = std::complex<double>(data.turnsRatio * std::cos(radPhaseShift),
220 -data.turnsRatio * std::sin(radPhaseShift));
221
222 // Transformer admitance
223 std::complex<double> y = 1.0 / std::complex<double>(data.resistance, data.indReactance);
224
225 if (sequence == POSITIVE_SEQ) {
226 yBus[n1][n1] += y / std::pow(std::abs(a), 2.0);
227 yBus[n1][n2] += -(y / std::conj(a));
228 yBus[n2][n1] += -(y / a);
229 yBus[n2][n2] += y;
230 }
231 else if (sequence == NEGATIVE_SEQ) {
232 yBus[n1][n1] += y / std::pow(std::abs(a), 2.0);
233 yBus[n1][n2] += -(y / a);
234 yBus[n2][n1] += -(y / std::conj(a));
235 yBus[n2][n2] += y;
236 }
237 }
238 else if (sequence == ZERO_SEQ) {
239 switch (data.connection) {
240 case GWYE_GWYE: {
241 std::complex<double> y =
242 1.0 /
243 std::complex<double>(
244 data.zeroResistance + 3.0 * (data.primaryGrndResistance + data.secondaryGrndResistance),
245 data.zeroIndReactance +
246 3.0 * (data.primaryGrndReactance + data.secondaryGrndReactance));
247 std::complex<double> a = std::complex<double>(data.turnsRatio, 0.0);
248
249 yBus[n1][n1] += y / (a * a);
250 yBus[n1][n2] += -(y / a);
251 yBus[n2][n1] += -(y / a);
252 yBus[n2][n2] += y;
253 } break;
254 case DELTA_GWYE: {
255 std::complex<double> y =
256 1.0 / std::complex<double>(data.zeroResistance + 3.0 * (data.secondaryGrndResistance),
257 data.zeroIndReactance + 3.0 * (data.secondaryGrndReactance));
258 yBus[n2][n2] += y;
259 yBus[n1][n1] += 1e-4;
260 yBus[n1][n2] += 1e-4;
261 yBus[n2][n1] += 1e-4;
262 break;
263 }
264 case GWYE_DELTA: {
265 std::complex<double> y =
266 1.0 / std::complex<double>(data.zeroResistance + 3.0 * (data.primaryGrndResistance),
267 data.zeroIndReactance + 3.0 * (data.primaryGrndReactance));
268 yBus[n1][n1] += y;
269 yBus[n2][n2] += 1e-4;
270 yBus[n1][n2] += 1e-4;
271 yBus[n2][n1] += 1e-4;
272 break;
273 }
274 default:
275 break;
276 }
277 }
278 }
279 }
280
281 if (includeSyncMachines) {
282 // Synchronous generator
283 for (auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
284 SyncGenerator* syncGenerator = *it;
285 if (syncGenerator->IsOnline()) {
286 int n = static_cast<Bus*>(syncGenerator->GetParentList()[0])->GetElectricalData().number;
287 SyncGeneratorElectricalData data = syncGenerator->GetPUElectricalData(systemPowerBase);
288 switch (sequence) {
289 case POSITIVE_SEQ: {
290 yBus[n][n] += 1.0 / std::complex<double>(data.positiveResistance, data.positiveReactance);
291 } break;
292 case NEGATIVE_SEQ: {
293 yBus[n][n] += 1.0 / std::complex<double>(data.negativeResistance, data.negativeReactance);
294 } break;
295 case ZERO_SEQ: {
296 if (data.groundNeutral) {
297 yBus[n][n] += 1.0 / std::complex<double>(data.zeroResistance + 3.0 * data.groundResistance,
298 data.zeroReactance + 3.0 * data.groundReactance);
299 }
300 } break;
301 }
302 }
303 }
304 // Synchronous motor
305 for (auto it = m_syncMotorList.begin(), itEnd = m_syncMotorList.end(); it != itEnd; ++it) {
306 SyncMotor* syncMotor = *it;
307 if (syncMotor->IsOnline()) {
308 int n = static_cast<Bus*>(syncMotor->GetParentList()[0])->GetElectricalData().number;
309 SyncMotorElectricalData data = syncMotor->GetPUElectricalData(systemPowerBase);
310 switch (sequence) {
311 case POSITIVE_SEQ: {
312 yBus[n][n] += 1.0 / std::complex<double>(data.positiveResistance, data.positiveReactance);
313 } break;
314 case NEGATIVE_SEQ: {
315 yBus[n][n] += 1.0 / std::complex<double>(data.negativeResistance, data.negativeReactance);
316 } break;
317 case ZERO_SEQ: {
318 if (data.groundNeutral) {
319 yBus[n][n] += 1.0 / std::complex<double>(data.zeroResistance + 3.0 * data.groundResistance,
320 data.zeroReactance + 3.0 * data.groundReactance);
321 }
322 } break;
323 }
324 }
325 }
326 }
327
328 // Identify buses to slack bus (power flow)
329 //if (sequence != ZERO_SEQ) {
330 std::vector<bool> connectedToSlack(m_busList.size(), false);
331 busNumber = 0;
332 int slackBus = 0;
333 std::vector<int> checkBusVector;
334 for (auto* bus : m_busList)
335 {
336 if (bus->GetElectricalData().slackBus)
337 {
338 connectedToSlack[busNumber] = true;
339 slackBus = busNumber;
340 break;
341 }
342 busNumber++;
343 }
344 GetNextConnection(slackBus, yBus, connectedToSlack);
345
346 bool hasIsolatedBus = false;
347 for (auto isConnectedToSlack : connectedToSlack)
348 {
349 if (!isConnectedToSlack) hasIsolatedBus = true;
350 }
351
352 if (hasIsolatedBus) {
353 // Update isolated and connected buses status and numbers
354 busNumber = 0;
355 for (unsigned int i = 0; i < m_busList.size(); ++i)
356 {
357 auto data = m_busList[i]->GetElectricalData();
358 data.isConnected = connectedToSlack[i];
359 if (connectedToSlack[i])
360 {
361 data.number = busNumber;
362 busNumber++;
363 }
364 else {
365 data.number = -1;
366 }
367 m_busList[i]->SetElectricalData(data);
368 }
369
370 // Create new Ybus without isolated buses (remove rows and columns)
371 std::vector< std::vector< std::complex<double> > > newYBus;
372 for (unsigned int i = 0; i < yBus.size(); ++i) {
373 if (connectedToSlack[i]) {
374 std::vector< std::complex<double> > newLine;
375 for (unsigned int j = 0; j < yBus.size(); ++j) {
376 if (connectedToSlack[j]) {
377 newLine.push_back(yBus[i][j]);
378 }
379 }
380 newYBus.push_back(newLine);
381 }
382 }
383
384 yBus.clear();
385 yBus = newYBus;
386 }
387 //}
388
389 return true;
390}
@ POSITIVE_SEQ
@ NEGATIVE_SEQ
bool IsOnline() const
Checks if the element is online or offline.
Definition Element.h:229
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InvertMatrix()

bool ElectricCalculation::InvertMatrix ( std::vector< std::vector< std::complex< double > > >  matrix,
std::vector< std::vector< std::complex< double > > > &  inverse 
)
virtual

Invert a matrix.

Parameters
matrixMatrix to invert.
inverseInverted matrix. The previous content will be erased.
Returns
Return true if was possible to invert the matrix.

Definition at line 792 of file ElectricCalculation.cpp.

794{
795 int order = static_cast<int>(matrix.size());
796
797 inverse.clear();
798 // Fill the inverse matrix with identity.
799 for (int i = 0; i < order; ++i) {
800 std::vector<std::complex<double> > line;
801 for (int j = 0; j < order; ++j) {
802 line.push_back(i == j ? std::complex<double>(1.0, 0.0) : std::complex<double>(0.0, 0.0));
803 }
804 inverse.push_back(line);
805 }
806
807 // Check if a main diagonal value of the matrix is zero, if one is zero, try a linear combination to remove it.
808 for (int i = 0; i < order; ++i) {
809 for (int j = 0; j < order; ++j) {
810 if (i == j && matrix[i][j] == std::complex<double>(0.0, 0.0)) {
811 int row = 0;
812 while (row < order) {
813 if (matrix[row][j] != std::complex<double>(0.0, 0.0)) {
814 for (int k = 0; k < order; ++k) {
815 matrix[i][k] += matrix[row][k];
816 inverse[i][k] += inverse[row][k];
817 }
818 break;
819 }
820 row++;
821 }
822 // If all line values are zero, the matrix is singular and the solution is impossible.
823 if (row == order) return false;
824 }
825 }
826 }
827
828 // Linear combinations are made in both matrices, the goal is the input matrix become the identity. The final result
829 // have two matrices: the identity and the inverse of the input.
830 for (int i = 0; i < order; ++i) {
831 for (int j = 0; j < order; ++j) {
832 if (i != j) {
833 if (matrix[i][i] == std::complex<double>(0.0, 0.0)) return false;
834
835 std::complex<double> factor = matrix[j][i] / matrix[i][i];
836 for (int k = 0; k < order; ++k) {
837 matrix[j][k] -= factor * matrix[i][k];
838 inverse[j][k] -= factor * inverse[i][k];
839 }
840 }
841 }
842 }
843 // Main diagonal calculation.
844 for (int i = 0; i < order; ++i) {
845 for (int j = 0; j < order; ++j) {
846 if (i == j) {
847 if (matrix[i][j] == std::complex<double>(0.0, 0.0)) return false;
848
849 std::complex<double> factor = (matrix[i][j] - std::complex<double>(1.0, 0.0)) / matrix[i][j];
850 for (int k = 0; k < order; ++k) {
851 matrix[j][k] -= factor * matrix[i][k];
852 inverse[j][k] -= factor * inverse[i][k];
853 }
854 }
855 }
856 }
857
858 return true;
859}
Here is the caller graph for this function:

◆ LUEvaluate()

std::vector< std::complex< double > > ElectricCalculation::LUEvaluate ( std::vector< std::vector< std::complex< double > > >  u,
std::vector< std::vector< std::complex< double > > >  l,
std::vector< std::complex< double > >  b 
)

Solve a linear system using LU decomposition.

Parameters
uUpper triangular matrix.
lLower triangular matrix.
bRight-hand side vector.
Returns
Solution vector.

Definition at line 1043 of file ElectricCalculation.cpp.

1046{
1047 int size = static_cast<int>(b.size());
1048 std::vector<std::complex<double> > x;
1049 std::vector<std::complex<double> > y;
1050 x.resize(size);
1051 y.resize(size);
1052
1053 // Forward
1054 for (int i = 0; i < size; i++) {
1055 y[i] = b[i];
1056 for (int j = 0; j < i; j++) { y[i] -= l[i][j] * y[j]; }
1057 y[i] /= l[i][i];
1058 }
1059 // Backward
1060 for (int i = size - 1; i >= 0; i--) {
1061 x[i] = y[i];
1062 for (int j = i + 1; j < size; j++) { x[i] -= u[i][j] * x[j]; }
1063 x[i] /= u[i][i];
1064 }
1065 return x;
1066}

◆ UpdateElementsPowerFlow()

void ElectricCalculation::UpdateElementsPowerFlow ( std::vector< std::complex< double > >  voltage,
std::vector< std::complex< double > >  power,
std::vector< BusType >  busType,
std::vector< ReactiveLimits >  reactiveLimit,
double  systemPowerBase 
)
virtual

Update the elements after the power flow calculation.

Parameters
voltageArray with the buses voltages.
powerArray with the buses injected power.
busTypeArray with the buses type.
reactiveLimitArray with the reactive limit data.
systemPowerBaseBase power of the system.

Definition at line 453 of file ElectricCalculation.cpp.

458{
459 double zeroLimit = 1e-4;
460 for (unsigned int i = 0; i < reactiveLimit.size(); ++i) {
461 if (reactiveLimit[i].maxLimit > -zeroLimit && reactiveLimit[i].maxLimit < zeroLimit)
462 reactiveLimit[i].maxLimit = zeroLimit;
463 if (reactiveLimit[i].minLimit > -zeroLimit && reactiveLimit[i].minLimit < zeroLimit)
464 reactiveLimit[i].minLimit = zeroLimit;
465 }
466 for (unsigned int i = 0; i < power.size(); ++i) {
467 if (std::real(power[i]) > -zeroLimit && std::real(power[i]) < zeroLimit)
468 power[i] = std::complex<double>(0.0, std::imag(power[i]));
469 if (std::imag(power[i]) > -zeroLimit && std::imag(power[i]) < zeroLimit)
470 power[i] = std::complex<double>(std::real(power[i]), 0.0);
471 }
472 // Buses
473 for (int i = 0; i < (int)m_busList.size(); i++) {
474 Bus* bus = m_busList[i];
475 BusElectricalData data = bus->GetElectricalData();
476 if (data.isConnected) {
477 data.voltage = voltage[data.number];
478 data.power = power[data.number];
479 data.busType = busType[data.number];
480 }
481 else {
482 data.voltage = std::complex<double>(0.0, 0.0);
483 data.power = std::complex<double>(0.0, 0.0);
484 }
485 bus->SetElectricalData(data);
486 }
487
488 // Power line
489 for (int i = 0; i < (int)m_lineList.size(); i++) {
490 Line* line = m_lineList[i];
491 if (line->IsOnline()) {
492 auto dataBus1 = static_cast<Bus*>(line->GetParentList()[0])->GetElectricalData();
493 auto dataBus2 = static_cast<Bus*>(line->GetParentList()[1])->GetElectricalData();
494
495 if (dataBus1.isConnected && dataBus2.isConnected) {
496 int n1 = dataBus1.number;
497 int n2 = dataBus2.number;
498
499 LineElectricalData data = line->GetElectricalData();
500 LineElectricalData dataPU = line->GetPUElectricalData(systemPowerBase);
501 std::complex<double> v1 = voltage[n1];
502 std::complex<double> v2 = voltage[n2];
503
504 data.current[0] = (v1 - v2) / std::complex<double>(dataPU.resistance, dataPU.indReactance) +
505 v1 * std::complex<double>(0.0, dataPU.capSusceptance / 2.0);
506 data.current[1] = (v2 - v1) / std::complex<double>(dataPU.resistance, dataPU.indReactance) +
507 v2 * std::complex<double>(0.0, dataPU.capSusceptance / 2.0);
508
509 data.powerFlow[0] = v1 * std::conj(data.current[0]);
510 data.powerFlow[1] = v2 * std::conj(data.current[1]);
511
512 if (data.powerFlow[0].real() > data.powerFlow[1].real())
514 else
516
517 line->SetElectricalData(data);
518 }
519 }
520 }
521
522 // Transformer
523 for (int i = 0; i < (int)m_transformerList.size(); i++) {
524 Transformer* transformer = m_transformerList[i];
525 if (transformer->IsOnline()) {
526 auto dataBus1 = static_cast<Bus*>(transformer->GetParentList()[0])->GetElectricalData();
527 auto dataBus2 = static_cast<Bus*>(transformer->GetParentList()[1])->GetElectricalData();
528
529 if (dataBus1.isConnected && dataBus2.isConnected) {
530 TransformerElectricalData data = transformer->GetElectricalData();
531 TransformerElectricalData dataPU = transformer->GetPUElectricalData(systemPowerBase);
532
533 int n1 = dataBus1.number;
534 int n2 = dataBus2.number;
535
536 std::complex<double> v1 = voltage[n1]; // Primary voltage
537 std::complex<double> v2 = voltage[n2]; // Secondary voltage
538
539 // Transformer admitance
540 std::complex<double> y = 1.0 / std::complex<double>(dataPU.resistance, dataPU.indReactance);
541
542 if (dataPU.turnsRatio == 1.0 && dataPU.phaseShift == 0.0) {
543 data.current[0] = (v1 - v2) * y;
544 data.current[1] = (v2 - v1) * y;
545 }
546 else {
547 double radPS = wxDegToRad(dataPU.phaseShift);
548 std::complex<double> a =
549 std::complex<double>(dataPU.turnsRatio * std::cos(radPS), -dataPU.turnsRatio * std::sin(radPS));
550
551 data.current[0] = v1 * (y / std::pow(std::abs(a), 2)) - v2 * (y / std::conj(a));
552 data.current[1] = -v1 * (y / a) + v2 * y;
553 }
554
555 data.powerFlow[0] = v1 * std::conj(data.current[0]);
556 data.powerFlow[1] = v2 * std::conj(data.current[1]);
557
558 if (data.powerFlow[0].real() > data.powerFlow[1].real())
560 else
562
563 transformer->SetElectricaData(data);
564 }
565 }
566 }
567
568 // Ind motor
569 for (unsigned int i = 0; i < m_indMotorList.size(); i++) {
570 IndMotor* motor = m_indMotorList[i];
571 auto data = motor->GetElectricalData();
572 if (motor->IsOnline() && data.calcQInPowerFlow) {
573 double reactivePower = data.qValue * systemPowerBase;
574
575 switch (data.reactivePowerUnit) {
576 case ElectricalUnit::UNIT_PU: {
577 reactivePower /= systemPowerBase;
578 } break;
579 case ElectricalUnit::UNIT_kvar: {
580 reactivePower /= 1e3;
581 } break;
582 case ElectricalUnit::UNIT_Mvar: {
583 reactivePower /= 1e6;
584 } break;
585 default:
586 break;
587 }
588
589 data.reactivePower = reactivePower;
590
591 motor->SetElectricalData(data);
592 }
593 }
594
595 //EMT Elements
596 for (EMTElement* emtElement : m_emtElementList) {
597
598 if (!emtElement->IsOnline()) {
599 auto data = emtElement->GetEMTElementData();
600 data.power = std::complex<double>(0.0, 0.0);
601 data.currHarmonics[1] = std::complex<double>(0.0, 0.0);
602 emtElement->SetEMTElementData(data);
603 }
604 else {
605 emtElement->UpdateData();
606 auto data = emtElement->GetEMTElementData();
607 double baseCurrent = systemPowerBase / (sqrt(3.0) * data.baseVoltage);
608 std::complex<double> current = data.currHarmonics[1] / baseCurrent; // Fundamental frequency current
609 std::complex<double> power = data.puVoltage * std::conj(current);
610 data.power = power;
611 emtElement->SetEMTElementData(data);
612 }
613 }
614
615 // Handling other shunt elements
616 // Capacitor, Inductor, Load, SyncGenerator and SyncMotor
617 for (auto* bus : m_busList) {
618 BusElectricalData data = bus->GetElectricalData();
619 int i = data.number;
620
621 if (data.isConnected) {
622 // Get the synchronous machines connected and calculate the load power on the bus.
623 std::vector<SyncGenerator*> syncGeneratorsOnBus;
624 std::vector<SyncMotor*> syncMotorsOnBus;
625 std::complex<double> loadPower(0.0, 0.0);
626
627 for (auto itsg = m_syncGeneratorList.begin(); itsg != m_syncGeneratorList.end(); itsg++) {
628 SyncGenerator* syncGenerator = *itsg;
629 if (bus == syncGenerator->GetParentList()[0] && syncGenerator->IsOnline()) {
630 syncGeneratorsOnBus.push_back(syncGenerator);
631 auto cData = syncGenerator->GetPUElectricalData(systemPowerBase);
632 if (cData.activePower >= 0.0)
634 else
636 }
637 }
638 for (auto itsm = m_syncMotorList.begin(); itsm != m_syncMotorList.end(); itsm++) {
639 SyncMotor* syncMotor = *itsm;
640 if (bus == syncMotor->GetParentList()[0] && syncMotor->IsOnline()) {
641 syncMotorsOnBus.push_back(syncMotor);
642 SyncMotorElectricalData childData = syncMotor->GetPUElectricalData(systemPowerBase);
643 loadPower += std::complex<double>(childData.activePower, 0.0);
644 if (childData.activePower >= 0.0)
646 else
648 }
649 }
650 for (auto itlo = m_loadList.begin(); itlo != m_loadList.end(); itlo++) {
651 Load* load = *itlo;
652 if (bus == load->GetParentList()[0] && load->IsOnline()) {
653 LoadElectricalData childData = load->GetPUElectricalData(systemPowerBase);
654 if (childData.loadType == CONST_POWER)
655 loadPower += std::complex<double>(childData.activePower, childData.reactivePower);
656
657 if (childData.activePower >= 0.0)
659 else
661 }
662 }
663 for (auto itim = m_indMotorList.begin(); itim != m_indMotorList.end(); itim++) {
664 IndMotor* indMotor = *itim;
665 if (bus == indMotor->GetParentList()[0] && indMotor->IsOnline()) {
666 IndMotorElectricalData childData = indMotor->GetPUElectricalData(systemPowerBase);
667 loadPower += std::complex<double>(childData.activePower, childData.reactivePower);
668
669 if (childData.activePower >= 0.0)
671 else
673 }
674 }
675
676 // Setup the reactive machines vector for the distribution of reactive power
677 std::vector<ReactiveMachine> machines;
678 for (auto* gen : syncGeneratorsOnBus) {
679
680 if (data.slackBus) {
681 auto dataG = gen->GetElectricalData();
682 double activePower = (power[data.number].real() + loadPower.real()) * (systemPowerBase / static_cast<double>(syncGeneratorsOnBus.size()));
683 switch (dataG.activePowerUnit) {
684 case ElectricalUnit::UNIT_PU:
685 activePower /= systemPowerBase;
686 break;
687 case ElectricalUnit::UNIT_kW:
688 activePower /= 1e3;
689 break;
690 case ElectricalUnit::UNIT_MW:
691 activePower /= 1e6;
692 break;
693 default:
694 break;
695 }
696
697 dataG.activePower = activePower;
698 gen->SetElectricalData(dataG);
699 }
700
701 auto dataG = gen->GetPUElectricalData(systemPowerBase);
702
704 m.qMax = dataG.maxReactive;
705 m.qMin = dataG.minReactive;
706
707 m.hasMax = dataG.haveMaxReactive;
708 m.hasMin = dataG.haveMinReactive;
709
710 m.machine = gen;
711 m.isGenerator = true;
712
713 machines.push_back(m);
714 }
715 for (auto* mot : syncMotorsOnBus) {
716
717 auto data = mot->GetPUElectricalData(systemPowerBase);
718
720 m.qMax = data.maxReactive;
721 m.qMin = data.minReactive;
722
723 m.hasMax = data.haveMaxReactive;
724 m.hasMin = data.haveMinReactive;
725
726 m.machine = mot;
727 m.isGenerator = false;
728
729 machines.push_back(m);
730 }
731
732 // Distribute the reactive power among the synchronous machines and set their reactive power
733 double qTotal = power[i].imag() + loadPower.imag();
734 DistributeReactivePower(machines, qTotal);
735
736 // Set the reactive power on the machines
737 for (auto& m : machines) {
738
739 if (m.isGenerator) {
740
741 SyncGenerator* gen = static_cast<SyncGenerator*>(m.machine);
742 auto data = gen->GetElectricalData();
743
744 double reactivePower = m.q * systemPowerBase;
745
746 switch (data.reactivePowerUnit) {
747 case ElectricalUnit::UNIT_PU:
748 reactivePower /= systemPowerBase;
749 break;
750 case ElectricalUnit::UNIT_kvar:
751 reactivePower /= 1e3;
752 break;
753 case ElectricalUnit::UNIT_Mvar:
754 reactivePower /= 1e6;
755 break;
756 default:
757 break;
758 }
759
760 data.reactivePower = reactivePower;
761 gen->SetElectricalData(data);
762 }
763 else {
764
765 SyncMotor* mot = static_cast<SyncMotor*>(m.machine);
766 auto data = mot->GetElectricalData();
767
768 double reactivePower = m.q * systemPowerBase;
769
770 switch (data.reactivePowerUnit) {
771 case ElectricalUnit::UNIT_PU:
772 reactivePower /= systemPowerBase;
773 break;
774 case ElectricalUnit::UNIT_kvar:
775 reactivePower /= 1e3;
776 break;
777 case ElectricalUnit::UNIT_Mvar:
778 reactivePower /= 1e6;
779 break;
780 default:
781 break;
782 }
783
784 data.reactivePower = reactivePower;
785 mot->SetElectricalData(data);
786 }
787 }
788 }
789 }
790}
void DistributeReactivePower(std::vector< ReactiveMachine > &machines, double qTotal)
Distribute reactive power among synchronous machines connected to the same bus.
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
Definition Line.cpp:649
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
Definition Machines.cpp:553
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
Auxiliary structure used to distribute reactive power among machines connected to a bus.
Here is the call graph for this function:

Member Data Documentation

◆ m_busList

std::vector<Bus*> ElectricCalculation::m_busList
protected

List of buses in the system.

Definition at line 370 of file ElectricCalculation.h.

◆ m_capacitorList

std::vector<Capacitor*> ElectricCalculation::m_capacitorList
protected

List of capacitor elements in the system.

Definition at line 372 of file ElectricCalculation.h.

◆ m_emtElementList

std::vector<EMTElement*> ElectricCalculation::m_emtElementList
protected

List of electromagnetic transient (EMT) elements in the system.

Definition at line 390 of file ElectricCalculation.h.

◆ m_harmCurrentList

std::vector<HarmCurrent*> ElectricCalculation::m_harmCurrentList
protected

List of harmonic current sources in the system.

Definition at line 388 of file ElectricCalculation.h.

◆ m_indMotorList

std::vector<IndMotor*> ElectricCalculation::m_indMotorList
protected

List of induction motors in the system.

Definition at line 374 of file ElectricCalculation.h.

◆ m_inductorList

std::vector<Inductor*> ElectricCalculation::m_inductorList
protected

List of inductors in the system.

Definition at line 376 of file ElectricCalculation.h.

◆ m_lineList

std::vector<Line*> ElectricCalculation::m_lineList
protected

List of transmission lines in the system.

Definition at line 378 of file ElectricCalculation.h.

◆ m_loadList

std::vector<Load*> ElectricCalculation::m_loadList
protected

List of load elements in the system.

Definition at line 380 of file ElectricCalculation.h.

◆ m_powerElementList

std::vector<PowerElement*> ElectricCalculation::m_powerElementList
protected

List of power elements in the system.

Definition at line 368 of file ElectricCalculation.h.

◆ m_syncGeneratorList

std::vector<SyncGenerator*> ElectricCalculation::m_syncGeneratorList
protected

List of synchronous generators in the system.

Definition at line 382 of file ElectricCalculation.h.

◆ m_syncMotorList

std::vector<SyncMotor*> ElectricCalculation::m_syncMotorList
protected

List of synchronous motors in the system.

Definition at line 384 of file ElectricCalculation.h.

◆ m_transformerList

std::vector<Transformer*> ElectricCalculation::m_transformerList
protected

List of transformers in the system.

Definition at line 386 of file ElectricCalculation.h.


The documentation for this class was generated from the following files: