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

830{
831 dValue = -std::real(complexValue) * std::sin(angle) + std::imag(complexValue) * std::cos(angle);
832 qValue = std::real(complexValue) * std::cos(angle) + std::imag(complexValue) * std::sin(angle);
833}

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

1058{
1059 for (EMTElement* emtElement : m_emtElementList) {
1060 if (!emtElement->IsOnline()) continue;
1061
1062 emtElement->UpdateData();
1063 if (!emtElement->CalculateCurrent(errorMsg)) return false;
1064 auto data = emtElement->GetEMTElementData();
1065 double baseCurrent = basePower / (sqrt(3.0) * data.baseVoltage);
1066 std::complex<double> current = data.currHarmonics[1] / baseCurrent; // Fundamental frequency current
1067 std::complex<double> y0 = current / data.puVoltage;
1068 data.y0 = y0;
1069 data.power = std::complex<double>(0.0, 0.0);
1070 emtElement->SetEMTElementData(data);
1071 }
1072 return true;
1073}
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 1075 of file ElectricCalculation.cpp.

1076{
1077 for (EMTElement* emtElement : m_emtElementList) {
1078 if (!emtElement->IsOnline()) continue;
1079
1080 emtElement->UpdateData();
1081 if (updateCurrent) {
1082 if (!emtElement->CalculateCurrent(errorMsg)) return false;
1083 }
1084 auto data = emtElement->GetEMTElementData();
1085 double baseCurrent = basePower / (sqrt(3.0) * data.baseVoltage);
1086 //std::complex<double> current = data.currHarmonics[1];
1087 std::complex<double> current = data.currHarmonics[1] / baseCurrent; // Fundamental frequency current
1088
1089 std::complex<double> i0 = data.y0 * data.puVoltage; // Current already injected via admittance matrix
1090 //std::complex<double> voltage = data.baseVoltage * data.puVoltage;
1091 //std::complex<double> power = (sqrt(3.0) * voltage * std::conj(current)) / basePower;
1092 std::complex<double> power = data.puVoltage * std::conj(current - i0);
1093 data.powerDiff = power - data.power;
1094 data.power = power;
1095 emtElement->SetEMTElementData(data);
1096
1097 //wxString currentStr = data.name + ":\n";
1098 //for (auto const& [harm, current] : data.currHarmonics)
1099 //{
1100 // currentStr += wxString::Format("I(%dh) = %f p.u.\n", harm, abs(current) / baseCurrent);
1101 //}
1102 //currentStr += wxString::Format("S = %e + j%e p.u.\n", data.power.real(), data.power.imag());
1103 //currentStr += wxString::Format("SDiff = %e p.u.\n", abs(data.powerDiff));
1104 //wxMessageBox(currentStr);
1105 }
1106 return true;
1107}
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 1109 of file ElectricCalculation.cpp.

1110{
1111 // Update buses voltages
1112 for (Bus* bus : m_busList) {
1113 auto data = bus->GetElectricalData();
1114 if (data.isConnected) {
1115 data.voltage = voltage[data.number];
1116 bus->SetElectricalData(data);
1117 }
1118 }
1119
1120 CalculateEMTElementsPower(basePower, errorMsg);
1121 // Update power array and calculate error
1122 double error = 0.0;
1123 for (EMTElement* emtElement : m_emtElementList) {
1124 if (!emtElement->IsOnline()) continue;
1125
1126 if (!emtElement->GetParentList().empty()) {
1127 if (emtElement->GetParentList()[0] != nullptr) {
1128 int numBus = static_cast<Bus*>(emtElement->GetParentList()[0])->GetElectricalData().number;
1129 auto data = emtElement->GetEMTElementData();
1130 power[numBus] += data.powerDiff;
1131 if (error < std::abs(data.powerDiff))
1132 error = std::abs(data.powerDiff);
1133 }
1134 }
1135 }
1136
1137 return error;
1138}
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 946 of file ElectricCalculation.cpp.

949{
950 std::vector<std::complex<double> > solution;
951 for (unsigned int i = 0; i < matrix.size(); i++) {
952 solution.push_back(std::complex<double>(0.0, 0.0));
953
954 for (unsigned int j = 0; j < matrix.size(); j++) { solution[i] += matrix[i][j] * vector[j]; }
955 }
956
957 return solution;
958}

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

836{
837 double real = qValue * std::cos(angle) - dValue * std::sin(angle);
838 double imag = qValue * std::sin(angle) + dValue * std::cos(angle);
839 complexValue = std::complex<double>(real, imag);
840}

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

888{
889 //[Ref] https://en.wikipedia.org/wiki/Gaussian_elimination
890
891 std::vector<double> solution;
892
893 std::vector<std::vector<double> > triangMatrix;
894 triangMatrix.resize(matrix.size());
895 for (unsigned int i = 0; i < matrix.size(); i++) { triangMatrix[i].resize(matrix.size()); }
896
897 for (unsigned int i = 0; i < matrix.size(); i++) { solution.push_back(array[i]); }
898
899 for (unsigned int i = 0; i < matrix.size(); i++) {
900 for (unsigned int j = 0; j < matrix.size(); j++) { triangMatrix[i][j] = matrix[i][j]; }
901 }
902
903 for (unsigned int k = 0; k < matrix.size(); k++) {
904 unsigned int k1 = k + 1;
905 for (unsigned int i = k; i < matrix.size(); i++) {
906 if (triangMatrix[i][k] != 0.0) {
907 for (unsigned int j = k1; j < matrix.size(); j++) {
908 triangMatrix[i][j] = triangMatrix[i][j] / triangMatrix[i][k];
909 }
910 solution[i] = solution[i] / triangMatrix[i][k];
911 }
912 }
913 for (unsigned int i = k1; i < matrix.size(); i++) {
914 if (triangMatrix[i][k] != 0.0) {
915 for (unsigned int j = k1; j < matrix.size(); j++) { triangMatrix[i][j] -= triangMatrix[k][j]; }
916 solution[i] -= solution[k];
917 }
918 }
919 }
920 for (int i = static_cast<int>(matrix.size()) - 2; i >= 0; i--) {
921 for (int j = static_cast<int>(matrix.size()) - 1; j >= i + 1; j--) {
922 solution[i] -= triangMatrix[i][j] * solution[j];
923 }
924 }
925
926 return solution;
927}

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

845{
846 //[Ref] https://en.wikipedia.org/wiki/Gaussian_elimination
847
848 std::vector<std::complex<double> > solution;
849
850 std::vector<std::vector<std::complex<double> > > triangMatrix;
851 triangMatrix.resize(matrix.size());
852 for (unsigned int i = 0; i < matrix.size(); i++) { triangMatrix[i].resize(matrix.size()); }
853
854 for (unsigned int i = 0; i < matrix.size(); i++) { solution.push_back(array[i]); }
855
856 for (unsigned int i = 0; i < matrix.size(); i++) {
857 for (unsigned int j = 0; j < matrix.size(); j++) { triangMatrix[i][j] = matrix[i][j]; }
858 }
859
860 for (unsigned int k = 0; k < matrix.size(); k++) {
861 unsigned int k1 = k + 1;
862 for (unsigned int i = k; i < matrix.size(); i++) {
863 if (triangMatrix[i][k] != std::complex<double>(0.0, 0.0)) {
864 for (unsigned int j = k1; j < matrix.size(); j++) {
865 triangMatrix[i][j] = triangMatrix[i][j] / triangMatrix[i][k];
866 }
867 solution[i] = solution[i] / triangMatrix[i][k];
868 }
869 }
870 for (unsigned int i = k1; i < matrix.size(); i++) {
871 if (triangMatrix[i][k] != std::complex<double>(0.0, 0.0)) {
872 for (unsigned int j = k1; j < matrix.size(); j++) { triangMatrix[i][j] -= triangMatrix[k][j]; }
873 solution[i] -= solution[k];
874 }
875 }
876 }
877 for (int i = static_cast<int>(matrix.size()) - 2; i >= 0; i--) {
878 for (int j = static_cast<int>(matrix.size()) - 1; j >= i + 1; j--) {
879 solution[i] -= triangMatrix[i][j] * solution[j];
880 }
881 }
882
883 return solution;
884}

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

963{
964 // Doolittle method
965 // [Ref] http://www3.nd.edu/~zxu2/acms40390F11/Alg-LU-Crout.pdf
966 // [Ref] http://www.engr.colostate.edu/~thompson/hPage/CourseMat/Tutorials/CompMethods/doolittle.pdf
967
968 int size = static_cast<int>(matrix.size()); // Decomposed matrix size.
969
970 // Set upper and lower matrices sizes.
971 matrixL.resize(size);
972 matrixU.resize(size);
973 for (int i = 0; i < size; i++) {
974 matrixL[i].resize(size);
975 matrixU[i].resize(size);
976 }
977
978 // First row of upper matrix and first column of lower matrix.
979 for (int i = 0; i < size; i++) {
980 matrixU[0][i] = matrix[0][i];
981 matrixL[i][0] = matrix[i][0] / matrixU[0][0];
982 }
983
984 // Lower matrix main diagonal.
985 for (int i = 1; i < size; i++) { matrixL[i][i] = std::complex<double>(1.0, 0.0); }
986
987 for (int i = 1; i < size - 1; i++) {
988 // Upper matrix main diagonal.
989 matrixU[i][i] = matrix[i][i];
990 for (int k = 0; k < i; k++) { matrixU[i][i] -= matrixL[i][k] * matrixU[k][i]; }
991
992 // Others elements of upper matrix
993 for (int j = i + 1; j < size; j++) {
994 matrixU[i][j] = matrix[i][j];
995 for (int k = 0; k < i; k++) { matrixU[i][j] -= matrixL[i][k] * matrixU[k][j]; }
996 }
997
998 // Lower matrix elements
999 for (int j = i + 1; j < size; j++) {
1000 matrixL[j][i] = matrix[j][i];
1001 for (int k = 0; k < i; k++) { matrixL[j][i] -= matrixL[j][k] * matrixU[k][i]; }
1002 matrixL[j][i] = matrixL[j][i] / matrixU[i][i];
1003 }
1004 }
1005
1006 // Last element of upper matrix.
1007 matrixU[size - 1][size - 1] = matrix[size - 1][size - 1];
1008 for (int k = 0; k < size - 1; k++) { matrixU[size - 1][size - 1] -= matrixL[size - 1][k] * matrixU[k][size - 1]; }
1009}

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

930{
931 auto data = generator->GetElectricalData();
932 if (data.transTd0 != 0.0) {
933 if (data.transTq0 != 0.0) {
934 if (data.subTd0 != 0.0 || data.subTq0 != 0.0) { return Machines::SM_MODEL_5; }
935 return Machines::SM_MODEL_3;
936 }
937 else {
938 if (data.subTd0 != 0.0 || data.subTq0 != 0.0) { return Machines::SM_MODEL_4; }
939 return Machines::SM_MODEL_2;
940 }
941 }
942
943 return Machines::SM_MODEL_1;
944}

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

1037{
1038 auto parentList = childElement->GetParentList();
1039 if (parentList.size() < 1) return false;
1040 parentBus = static_cast<Bus*>(parentList[0]);
1041 if (parentBus == nullptr) return false;
1042 if (parentBus->GetElectricalData().number < 0) return false;
1043 return true;
1044}
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 1046 of file ElectricCalculation.cpp.

1047{
1048 auto parentList = childElement->GetParentList();
1049 if (parentList.size() < 2) return false;
1050 parentBus1 = static_cast<Bus*>(parentList[0]);
1051 parentBus2 = static_cast<Bus*>(parentList[1]);
1052 if (parentBus1 == nullptr || parentBus2 == nullptr) return false;
1053 if (parentBus1->GetElectricalData().number < 0 || parentBus2->GetElectricalData().number < 0) return false;
1054 return true;
1055}
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 760 of file ElectricCalculation.cpp.

762{
763 int order = static_cast<int>(matrix.size());
764
765 inverse.clear();
766 // Fill the inverse matrix with identity.
767 for (int i = 0; i < order; ++i) {
768 std::vector<std::complex<double> > line;
769 for (int j = 0; j < order; ++j) {
770 line.push_back(i == j ? std::complex<double>(1.0, 0.0) : std::complex<double>(0.0, 0.0));
771 }
772 inverse.push_back(line);
773 }
774
775 // Check if a main diagonal value of the matrix is zero, if one is zero, try a linear combination to remove it.
776 for (int i = 0; i < order; ++i) {
777 for (int j = 0; j < order; ++j) {
778 if (i == j && matrix[i][j] == std::complex<double>(0.0, 0.0)) {
779 int row = 0;
780 while (row < order) {
781 if (matrix[row][j] != std::complex<double>(0.0, 0.0)) {
782 for (int k = 0; k < order; ++k) {
783 matrix[i][k] += matrix[row][k];
784 inverse[i][k] += inverse[row][k];
785 }
786 break;
787 }
788 row++;
789 }
790 // If all line values are zero, the matrix is singular and the solution is impossible.
791 if (row == order) return false;
792 }
793 }
794 }
795
796 // Linear combinations are made in both matrices, the goal is the input matrix become the identity. The final result
797 // have two matrices: the identity and the inverse of the input.
798 for (int i = 0; i < order; ++i) {
799 for (int j = 0; j < order; ++j) {
800 if (i != j) {
801 if (matrix[i][i] == std::complex<double>(0.0, 0.0)) return false;
802
803 std::complex<double> factor = matrix[j][i] / matrix[i][i];
804 for (int k = 0; k < order; ++k) {
805 matrix[j][k] -= factor * matrix[i][k];
806 inverse[j][k] -= factor * inverse[i][k];
807 }
808 }
809 }
810 }
811 // Main diagonal calculation.
812 for (int i = 0; i < order; ++i) {
813 for (int j = 0; j < order; ++j) {
814 if (i == j) {
815 if (matrix[i][j] == std::complex<double>(0.0, 0.0)) return false;
816
817 std::complex<double> factor = (matrix[i][j] - std::complex<double>(1.0, 0.0)) / matrix[i][j];
818 for (int k = 0; k < order; ++k) {
819 matrix[j][k] -= factor * matrix[i][k];
820 inverse[j][k] -= factor * inverse[i][k];
821 }
822 }
823 }
824 }
825
826 return true;
827}
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 1011 of file ElectricCalculation.cpp.

1014{
1015 int size = static_cast<int>(b.size());
1016 std::vector<std::complex<double> > x;
1017 std::vector<std::complex<double> > y;
1018 x.resize(size);
1019 y.resize(size);
1020
1021 // Forward
1022 for (int i = 0; i < size; i++) {
1023 y[i] = b[i];
1024 for (int j = 0; j < i; j++) { y[i] -= l[i][j] * y[j]; }
1025 y[i] /= l[i][i];
1026 }
1027 // Backward
1028 for (int i = size - 1; i >= 0; i--) {
1029 x[i] = y[i];
1030 for (int j = i + 1; j < size; j++) { x[i] -= u[i][j] * x[j]; }
1031 x[i] /= u[i][i];
1032 }
1033 return x;
1034}

◆ 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 auto data = gen->GetPUElectricalData(systemPowerBase);
670
672 m.qMax = data.maxReactive;
673 m.qMin = data.minReactive;
674
675 m.hasMax = data.haveMaxReactive;
676 m.hasMin = data.haveMinReactive;
677
678 m.machine = gen;
679 m.isGenerator = true;
680
681 machines.push_back(m);
682 }
683 for (auto* mot : syncMotorsOnBus) {
684
685 auto data = mot->GetPUElectricalData(systemPowerBase);
686
688 m.qMax = data.maxReactive;
689 m.qMin = data.minReactive;
690
691 m.hasMax = data.haveMaxReactive;
692 m.hasMin = data.haveMinReactive;
693
694 m.machine = mot;
695 m.isGenerator = false;
696
697 machines.push_back(m);
698 }
699
700 // Distribute the reactive power among the synchronous machines and set their reactive power
701 double qTotal = power[i].imag() + loadPower.imag();
702 DistributeReactivePower(machines, qTotal);
703
704 // Set the reactive power on the machines
705 for (auto& m : machines) {
706
707 if (m.isGenerator) {
708
709 SyncGenerator* gen = static_cast<SyncGenerator*>(m.machine);
710 auto data = gen->GetElectricalData();
711
712 double reactivePower = m.q * systemPowerBase;
713
714 switch (data.reactivePowerUnit) {
716 reactivePower /= systemPowerBase;
717 break;
719 reactivePower /= 1e3;
720 break;
722 reactivePower /= 1e6;
723 break;
724 default:
725 break;
726 }
727
728 data.reactivePower = reactivePower;
729 gen->SetElectricalData(data);
730 }
731 else {
732
733 SyncMotor* mot = static_cast<SyncMotor*>(m.machine);
734 auto data = mot->GetElectricalData();
735
736 double reactivePower = m.q * systemPowerBase;
737
738 switch (data.reactivePowerUnit) {
740 reactivePower /= systemPowerBase;
741 break;
743 reactivePower /= 1e3;
744 break;
746 reactivePower /= 1e6;
747 break;
748 default:
749 break;
750 }
751
752 data.reactivePower = reactivePower;
753 mot->SetElectricalData(data);
754 }
755 }
756 }
757 }
758}
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:621
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: