Power System Platform  2026w11a-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 850 of file ElectricCalculation.cpp.

851{
852 dValue = -std::real(complexValue) * std::sin(angle) + std::imag(complexValue) * std::cos(angle);
853 qValue = std::real(complexValue) * std::cos(angle) + std::imag(complexValue) * std::sin(angle);
854}

◆ 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 1078 of file ElectricCalculation.cpp.

1079{
1080 for (EMTElement* emtElement : m_emtElementList) {
1081 if (!emtElement->IsOnline()) continue;
1082
1083 emtElement->UpdateData();
1084 if (!emtElement->CalculateCurrent(errorMsg)) return false;
1085 auto data = emtElement->GetEMTElementData();
1086 double baseCurrent = basePower / (sqrt(3.0) * data.baseVoltage);
1087 std::complex<double> current = data.currHarmonics[1] / baseCurrent; // Fundamental frequency current
1088 std::complex<double> y0 = current / data.puVoltage;
1089 data.y0 = y0;
1090 data.power = std::complex<double>(0.0, 0.0);
1091 emtElement->SetEMTElementData(data);
1092 }
1093 return true;
1094}
Element to connect ATP-EMTP.
Definition EMTElement.h:65
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 1096 of file ElectricCalculation.cpp.

1097{
1098 for (EMTElement* emtElement : m_emtElementList) {
1099 if (!emtElement->IsOnline()) continue;
1100
1101 emtElement->UpdateData();
1102 if (updateCurrent) {
1103 if (!emtElement->CalculateCurrent(errorMsg)) return false;
1104 }
1105 auto data = emtElement->GetEMTElementData();
1106 double baseCurrent = basePower / (sqrt(3.0) * data.baseVoltage);
1107 //std::complex<double> current = data.currHarmonics[1];
1108 std::complex<double> current = data.currHarmonics[1] / baseCurrent; // Fundamental frequency current
1109
1110 std::complex<double> i0 = data.y0 * data.puVoltage; // Current already injected via admittance matrix
1111 //std::complex<double> voltage = data.baseVoltage * data.puVoltage;
1112 //std::complex<double> power = (sqrt(3.0) * voltage * std::conj(current)) / basePower;
1113 std::complex<double> power = data.puVoltage * std::conj(current - i0);
1114 data.powerDiff = power - data.power;
1115 data.power = power;
1116 emtElement->SetEMTElementData(data);
1117
1118 //wxString currentStr = data.name + ":\n";
1119 //for (auto const& [harm, current] : data.currHarmonics)
1120 //{
1121 // currentStr += wxString::Format("I(%dh) = %f p.u.\n", harm, abs(current) / baseCurrent);
1122 //}
1123 //currentStr += wxString::Format("S = %e + j%e p.u.\n", data.power.real(), data.power.imag());
1124 //currentStr += wxString::Format("SDiff = %e p.u.\n", abs(data.powerDiff));
1125 //wxMessageBox(currentStr);
1126 }
1127 return true;
1128}
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 1130 of file ElectricCalculation.cpp.

1131{
1132 // Update buses voltages
1133 for (Bus* bus : m_busList) {
1134 auto data = bus->GetElectricalData();
1135 if (data.isConnected) {
1136 data.voltage = voltage[data.number];
1137 bus->SetElectricalData(data);
1138 }
1139 }
1140
1141 CalculateEMTElementsPower(basePower, errorMsg);
1142 // Update power array and calculate error
1143 double error = 0.0;
1144 for (EMTElement* emtElement : m_emtElementList) {
1145 if (!emtElement->IsOnline()) continue;
1146
1147 if (!emtElement->GetParentList().empty()) {
1148 if (emtElement->GetParentList()[0] != nullptr) {
1149 int numBus = static_cast<Bus*>(emtElement->GetParentList()[0])->GetElectricalData().number;
1150 auto data = emtElement->GetEMTElementData();
1151 power[numBus] += data.powerDiff;
1152 if (error < std::abs(data.powerDiff))
1153 error = std::abs(data.powerDiff);
1154 }
1155 }
1156 }
1157
1158 return error;
1159}
Node for power elements. All others power elements are connected through this.
Definition Bus.h:86
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 967 of file ElectricCalculation.cpp.

970{
971 std::vector<std::complex<double> > solution;
972 for (unsigned int i = 0; i < matrix.size(); i++) {
973 solution.push_back(std::complex<double>(0.0, 0.0));
974
975 for (unsigned int j = 0; j < matrix.size(); j++) { solution[i] += matrix[i][j] * vector[j]; }
976 }
977
978 return solution;
979}

◆ 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 856 of file ElectricCalculation.cpp.

857{
858 double real = qValue * std::cos(angle) - dValue * std::sin(angle);
859 double imag = qValue * std::sin(angle) + dValue * std::cos(angle);
860 complexValue = std::complex<double>(real, imag);
861}

◆ 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 907 of file ElectricCalculation.cpp.

909{
910 //[Ref] https://en.wikipedia.org/wiki/Gaussian_elimination
911
912 std::vector<double> solution;
913
914 std::vector<std::vector<double> > triangMatrix;
915 triangMatrix.resize(matrix.size());
916 for (unsigned int i = 0; i < matrix.size(); i++) { triangMatrix[i].resize(matrix.size()); }
917
918 for (unsigned int i = 0; i < matrix.size(); i++) { solution.push_back(array[i]); }
919
920 for (unsigned int i = 0; i < matrix.size(); i++) {
921 for (unsigned int j = 0; j < matrix.size(); j++) { triangMatrix[i][j] = matrix[i][j]; }
922 }
923
924 for (unsigned int k = 0; k < matrix.size(); k++) {
925 unsigned int k1 = k + 1;
926 for (unsigned int i = k; i < matrix.size(); i++) {
927 if (triangMatrix[i][k] != 0.0) {
928 for (unsigned int j = k1; j < matrix.size(); j++) {
929 triangMatrix[i][j] = triangMatrix[i][j] / triangMatrix[i][k];
930 }
931 solution[i] = solution[i] / triangMatrix[i][k];
932 }
933 }
934 for (unsigned int i = k1; i < matrix.size(); i++) {
935 if (triangMatrix[i][k] != 0.0) {
936 for (unsigned int j = k1; j < matrix.size(); j++) { triangMatrix[i][j] -= triangMatrix[k][j]; }
937 solution[i] -= solution[k];
938 }
939 }
940 }
941 for (int i = static_cast<int>(matrix.size()) - 2; i >= 0; i--) {
942 for (int j = static_cast<int>(matrix.size()) - 1; j >= i + 1; j--) {
943 solution[i] -= triangMatrix[i][j] * solution[j];
944 }
945 }
946
947 return solution;
948}

◆ 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 863 of file ElectricCalculation.cpp.

866{
867 //[Ref] https://en.wikipedia.org/wiki/Gaussian_elimination
868
869 std::vector<std::complex<double> > solution;
870
871 std::vector<std::vector<std::complex<double> > > triangMatrix;
872 triangMatrix.resize(matrix.size());
873 for (unsigned int i = 0; i < matrix.size(); i++) { triangMatrix[i].resize(matrix.size()); }
874
875 for (unsigned int i = 0; i < matrix.size(); i++) { solution.push_back(array[i]); }
876
877 for (unsigned int i = 0; i < matrix.size(); i++) {
878 for (unsigned int j = 0; j < matrix.size(); j++) { triangMatrix[i][j] = matrix[i][j]; }
879 }
880
881 for (unsigned int k = 0; k < matrix.size(); k++) {
882 unsigned int k1 = k + 1;
883 for (unsigned int i = k; i < matrix.size(); i++) {
884 if (triangMatrix[i][k] != std::complex<double>(0.0, 0.0)) {
885 for (unsigned int j = k1; j < matrix.size(); j++) {
886 triangMatrix[i][j] = triangMatrix[i][j] / triangMatrix[i][k];
887 }
888 solution[i] = solution[i] / triangMatrix[i][k];
889 }
890 }
891 for (unsigned int i = k1; i < matrix.size(); i++) {
892 if (triangMatrix[i][k] != std::complex<double>(0.0, 0.0)) {
893 for (unsigned int j = k1; j < matrix.size(); j++) { triangMatrix[i][j] -= triangMatrix[k][j]; }
894 solution[i] -= solution[k];
895 }
896 }
897 }
898 for (int i = static_cast<int>(matrix.size()) - 2; i >= 0; i--) {
899 for (int j = static_cast<int>(matrix.size()) - 1; j >= i + 1; j--) {
900 solution[i] -= triangMatrix[i][j] * solution[j];
901 }
902 }
903
904 return solution;
905}

◆ 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:112
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.
Definition Transformer.h:84
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 981 of file ElectricCalculation.cpp.

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

◆ 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 950 of file ElectricCalculation.cpp.

951{
952 auto data = generator->GetElectricalData();
953 if (data.transTd0 != 0.0) {
954 if (data.transTq0 != 0.0) {
955 if (data.subTd0 != 0.0 || data.subTq0 != 0.0) { return Machines::SM_MODEL_5; }
956 return Machines::SM_MODEL_3;
957 }
958 else {
959 if (data.subTd0 != 0.0 || data.subTq0 != 0.0) { return Machines::SM_MODEL_4; }
960 return Machines::SM_MODEL_2;
961 }
962 }
963
964 return Machines::SM_MODEL_1;
965}

◆ 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 1057 of file ElectricCalculation.cpp.

1058{
1059 auto parentList = childElement->GetParentList();
1060 if (parentList.size() < 1) return false;
1061 parentBus = static_cast<Bus*>(parentList[0]);
1062 if (parentBus == nullptr) return false;
1063 if (parentBus->GetElectricalData().number < 0) return false;
1064 return true;
1065}
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition Element.h:559
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 1067 of file ElectricCalculation.cpp.

1068{
1069 auto parentList = childElement->GetParentList();
1070 if (parentList.size() < 2) return false;
1071 parentBus1 = static_cast<Bus*>(parentList[0]);
1072 parentBus2 = static_cast<Bus*>(parentList[1]);
1073 if (parentBus1 == nullptr || parentBus2 == nullptr) return false;
1074 if (parentBus1->GetElectricalData().number < 0 || parentBus2->GetElectricalData().number < 0) return false;
1075 return true;
1076}
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:226
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 781 of file ElectricCalculation.cpp.

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

1035{
1036 int size = static_cast<int>(b.size());
1037 std::vector<std::complex<double> > x;
1038 std::vector<std::complex<double> > y;
1039 x.resize(size);
1040 y.resize(size);
1041
1042 // Forward
1043 for (int i = 0; i < size; i++) {
1044 y[i] = b[i];
1045 for (int j = 0; j < i; j++) { y[i] -= l[i][j] * y[j]; }
1046 y[i] /= l[i][i];
1047 }
1048 // Backward
1049 for (int i = size - 1; i >= 0; i--) {
1050 x[i] = y[i];
1051 for (int j = i + 1; j < size; j++) { x[i] -= u[i][j] * x[j]; }
1052 x[i] /= u[i][i];
1053 }
1054 return x;
1055}

◆ 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) {
577 reactivePower /= systemPowerBase;
578 } break;
580 reactivePower /= 1e3;
581 } break;
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 // Synchronous machines
616 for (auto* bus : m_busList) {
617 BusElectricalData data = bus->GetElectricalData();
618 int i = data.number;
619
620 if (data.isConnected) {
621 // Get the synchronous machines connected and calculate the load power on the bus.
622 std::vector<SyncGenerator*> syncGeneratorsOnBus;
623 std::vector<SyncMotor*> syncMotorsOnBus;
624 std::complex<double> loadPower(0.0, 0.0);
625
626 for (auto itsg = m_syncGeneratorList.begin(); itsg != m_syncGeneratorList.end(); itsg++) {
627 SyncGenerator* syncGenerator = *itsg;
628 if (bus == syncGenerator->GetParentList()[0] && syncGenerator->IsOnline())
629 syncGeneratorsOnBus.push_back(syncGenerator);
630 }
631 for (auto itsm = m_syncMotorList.begin(); itsm != m_syncMotorList.end(); itsm++) {
632 SyncMotor* syncMotor = *itsm;
633 if (bus == syncMotor->GetParentList()[0] && syncMotor->IsOnline()) {
634 syncMotorsOnBus.push_back(syncMotor);
635 SyncMotorElectricalData childData = syncMotor->GetPUElectricalData(systemPowerBase);
636 loadPower += std::complex<double>(childData.activePower, 0.0);
637 }
638 }
639 for (auto itlo = m_loadList.begin(); itlo != m_loadList.end(); itlo++) {
640 Load* load = *itlo;
641 if (bus == load->GetParentList()[0] && load->IsOnline()) {
642 LoadElectricalData childData = load->GetPUElectricalData(systemPowerBase);
643 if (childData.loadType == CONST_POWER)
644 loadPower += std::complex<double>(childData.activePower, childData.reactivePower);
645
646 if (childData.activePower >= 0.0)
648 else
650 }
651 }
652 for (auto itim = m_indMotorList.begin(); itim != m_indMotorList.end(); itim++) {
653 IndMotor* indMotor = *itim;
654 if (bus == indMotor->GetParentList()[0] && indMotor->IsOnline()) {
655 IndMotorElectricalData childData = indMotor->GetPUElectricalData(systemPowerBase);
656 loadPower += std::complex<double>(childData.activePower, childData.reactivePower);
657
658 if (childData.activePower >= 0.0)
660 else
662 }
663 }
664
665 // Setup the reactive machines vector for the distribution of reactive power
666 std::vector<ReactiveMachine> machines;
667 for (auto* gen : syncGeneratorsOnBus) {
668
669 if (data.slackBus) {
670 auto dataG = gen->GetElectricalData();
671 double activePower = (power[data.number].real() + loadPower.real()) * (systemPowerBase / static_cast<double>(syncGeneratorsOnBus.size()));
672 switch (dataG.activePowerUnit) {
674 activePower /= systemPowerBase;
675 break;
677 activePower /= 1e3;
678 break;
680 activePower /= 1e6;
681 break;
682 default:
683 break;
684 }
685
686 dataG.activePower = activePower;
687 gen->SetElectricalData(dataG);
688 }
689
690 auto dataG = gen->GetPUElectricalData(systemPowerBase);
691
693 m.qMax = dataG.maxReactive;
694 m.qMin = dataG.minReactive;
695
696 m.hasMax = dataG.haveMaxReactive;
697 m.hasMin = dataG.haveMinReactive;
698
699 m.machine = gen;
700 m.isGenerator = true;
701
702 machines.push_back(m);
703 }
704 for (auto* mot : syncMotorsOnBus) {
705
706 auto data = mot->GetPUElectricalData(systemPowerBase);
707
709 m.qMax = data.maxReactive;
710 m.qMin = data.minReactive;
711
712 m.hasMax = data.haveMaxReactive;
713 m.hasMin = data.haveMinReactive;
714
715 m.machine = mot;
716 m.isGenerator = false;
717
718 machines.push_back(m);
719 }
720
721 // Distribute the reactive power among the synchronous machines and set their reactive power
722 double qTotal = power[i].imag() + loadPower.imag();
723 DistributeReactivePower(machines, qTotal);
724
725 // Set the reactive power on the machines
726 for (auto& m : machines) {
727
728 if (m.isGenerator) {
729
730 SyncGenerator* gen = static_cast<SyncGenerator*>(m.machine);
731 auto data = gen->GetElectricalData();
732
733 double reactivePower = m.q * systemPowerBase;
734
735 switch (data.reactivePowerUnit) {
737 reactivePower /= systemPowerBase;
738 break;
740 reactivePower /= 1e3;
741 break;
743 reactivePower /= 1e6;
744 break;
745 default:
746 break;
747 }
748
749 data.reactivePower = reactivePower;
750 gen->SetElectricalData(data);
751 }
752 else {
753
754 SyncMotor* mot = static_cast<SyncMotor*>(m.machine);
755 auto data = mot->GetElectricalData();
756
757 double reactivePower = m.q * systemPowerBase;
758
759 switch (data.reactivePowerUnit) {
761 reactivePower /= systemPowerBase;
762 break;
764 reactivePower /= 1e3;
765 break;
767 reactivePower /= 1e6;
768 break;
769 default:
770 break;
771 }
772
773 data.reactivePower = reactivePower;
774 mot->SetElectricalData(data);
775 }
776 }
777 }
778 }
779}
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:619
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
Definition Machines.cpp:379
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: