com.powsybl.openloadflow.ac.equations.asym.LoadFortescuePowerEquationTerm Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of powsybl-open-loadflow Show documentation
Show all versions of powsybl-open-loadflow Show documentation
An open source loadflow based on PowSyBl
The newest version!
/**
* Copyright (c) 2023, Jean-Baptiste Heyberger
* Copyright (c) 2023, Geoffroy Jamgotchian
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.openloadflow.ac.equations.asym;
import com.powsybl.math.matrix.DenseMatrix;
import com.powsybl.openloadflow.ac.equations.AcEquationType;
import com.powsybl.openloadflow.ac.equations.AcVariableType;
import com.powsybl.openloadflow.equations.AbstractElementEquationTerm;
import com.powsybl.openloadflow.equations.Variable;
import com.powsybl.openloadflow.equations.VariableSet;
import com.powsybl.openloadflow.network.LfBus;
import com.powsybl.openloadflow.network.LfAsymBus;
import com.powsybl.openloadflow.util.ComplexPart;
import com.powsybl.openloadflow.util.Fortescue;
import net.jafama.FastMath;
import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* @author Jean-Baptiste Heyberger {@literal }
*/
public class LoadFortescuePowerEquationTerm extends AbstractElementEquationTerm {
// positive
protected final Variable vVar;
protected final Variable phVar;
// negative
protected final Variable vVarNegative;
protected final Variable phVarNegative;
// zero
protected final Variable vVarZero;
protected final Variable phVarZero;
protected final List> variables = new ArrayList<>();
private final ComplexPart complexPart;
private final Fortescue.SequenceType sequenceType;
public LoadFortescuePowerEquationTerm(LfBus bus, VariableSet variableSet, ComplexPart complexPart, Fortescue.SequenceType sequenceType) {
super(bus);
Objects.requireNonNull(variableSet);
this.complexPart = Objects.requireNonNull(complexPart);
this.sequenceType = Objects.requireNonNull(sequenceType);
vVar = variableSet.getVariable(bus.getNum(), AcVariableType.BUS_V);
phVar = variableSet.getVariable(bus.getNum(), AcVariableType.BUS_PHI);
vVarNegative = variableSet.getVariable(bus.getNum(), AcVariableType.BUS_V_NEGATIVE);
phVarNegative = variableSet.getVariable(bus.getNum(), AcVariableType.BUS_PHI_NEGATIVE);
vVarZero = variableSet.getVariable(bus.getNum(), AcVariableType.BUS_V_ZERO);
phVarZero = variableSet.getVariable(bus.getNum(), AcVariableType.BUS_PHI_ZERO);
variables.add(vVar);
variables.add(phVar);
variables.add(vVarNegative);
variables.add(phVarNegative);
variables.add(vVarZero);
variables.add(phVarZero);
}
public double ph(Fortescue.SequenceType g) {
return switch (g) {
case ZERO -> sv.get(phVarZero.getRow());
case POSITIVE -> sv.get(phVar.getRow());
case NEGATIVE -> sv.get(phVarNegative.getRow());
};
}
public double v(Fortescue.SequenceType g) {
return switch (g) {
case ZERO -> sv.get(vVarZero.getRow());
case POSITIVE -> sv.get(vVar.getRow());
case NEGATIVE -> sv.get(vVarNegative.getRow());
};
}
/**
* We use the formula with complex matrices:
* {@literal
*
* [So] [Vo 0 0] [1/Va 0 0] [Sa]
* [Sd] = [0 Vd 0]. 1/3 . [F] . [0 1/Vb 0] . [Sb]
* [Si] [0 0 Vi] [0 0 1/Vc] [Sc]
* <------------------------------>
* term (Ifortescue)*
* <------------------------------------------->
* term Sfortescue
* }
*/
public static double pq(LfBus bus, ComplexPart complexPart, Fortescue.SequenceType sequenceType, double vZero, double phZero, double vPositive, double phPositive, double vNegative, double phNegative) {
LfAsymBus asymBus = bus.getAsym();
if (asymBus == null) {
throw new IllegalStateException("unexpected null pointer for an asymmetric bus " + bus.getId());
}
// Build of Sabc/3 vector
DenseMatrix mSabc3 = createCartesianMatrix(asymBus.getPa() / 3, asymBus.getQa() / 3, asymBus.getPb() / 3, asymBus.getQb() / 3, asymBus.getPc() / 3, asymBus.getQc() / 3, true);
Vector2D positiveSequence = Fortescue.getCartesianFromPolar(vPositive, phPositive);
Vector2D zeroSequence = Fortescue.getCartesianFromPolar(vZero, phZero);
Vector2D negativeSequence = Fortescue.getCartesianFromPolar(vNegative, phNegative);
DenseMatrix mVfortescue = createCartesianMatrix(zeroSequence.getX(), zeroSequence.getY(), positiveSequence.getX(), positiveSequence.getY(), negativeSequence.getX(), negativeSequence.getY(), true); // vector build with cartesian values (Vx,Vy) of complex fortescue voltages
DenseMatrix mVabc = Fortescue.createMatrix().times(mVfortescue).toDense(); // vector build with cartesian values of complex abc voltages
// build 1/Vabc square matrix
DenseMatrix mInvVabc = createInvVabcSquare(bus, mVabc.get(0, 0), mVabc.get(1, 0), mVabc.get(2, 0), mVabc.get(3, 0), mVabc.get(4, 0), mVabc.get(5, 0));
// build Vfortescue square matrix
DenseMatrix mSquareVFortescue = createCartesianMatrix(mVfortescue.get(0, 0), mVfortescue.get(1, 0), mVfortescue.get(2, 0), mVfortescue.get(3, 0), mVfortescue.get(4, 0), mVfortescue.get(5, 0), false);
DenseMatrix m0T0 = mInvVabc.times(mSabc3);
DenseMatrix mIfortescueConjugate = Fortescue.createMatrix().times(m0T0);
DenseMatrix mSfortescue = mSquareVFortescue.times(mIfortescueConjugate); // term T0 = Sfortescue
return switch (sequenceType) {
case ZERO ->
complexPart == ComplexPart.REAL ? mIfortescueConjugate.get(0, 0) : -mIfortescueConjugate.get(1, 0); // IxZero or IyZero
case POSITIVE ->
complexPart == ComplexPart.REAL ? mSfortescue.get(2, 0) : mSfortescue.get(3, 0); // Ppositive or Qpositive
case NEGATIVE ->
complexPart == ComplexPart.REAL ? mIfortescueConjugate.get(4, 0) : -mIfortescueConjugate.get(5, 0); // IxNegative or IyNegative
};
}
/**
* We derivate the PQ formula with complex matrices:
* {@literal
* [So] [dVo/dx 0 0] [1/Va 0 0] [Sa] [Vo 0 0] [Sa 0 0] [1/Va 0 0] [1/Va 0 0] [dV0/dx]
* d( [Sd] )/dx = 1/3 . [0 dVd/dx 0] . [F] . [0 1/Vb 0] . [Sb] + [0 Vd 0] . [F] .(-1/3). [0 Sb 0] . [0 1/Vb 0] . [0 1/Vb 0] . [F] . [dVd/dx]
* [Si] [0 0 dVi/dx] [0 0 1/Vc] [Sc] [0 0 Vi] [0 0 Sc] [0 0 1/Vc] [0 0 1/Vc] [dVi/dx]
* <--------------------------------------------> <----------------------------------------------------------------------->
* term T1 term (dIfortescue)*
* <----------------------------------------------------------------------------------->
* term T2
* }
*/
public static double dpq(LfBus bus, ComplexPart complexPart, Fortescue.SequenceType sequenceType, Variable derVariable, double vo, double pho, double vd, double phd, double vi, double phi) {
LfAsymBus asymBus = bus.getAsym();
if (asymBus == null) {
throw new IllegalStateException("unexpected null pointer for an asymmetric bus " + bus.getId());
}
// computation of dV0/dx , dV1/dx, dV2/dx
double dV0x = 0;
double dV0y = 0;
double dV1x = 0;
double dV1y = 0;
double dV2x = 0;
double dV2y = 0;
if (derVariable.getType() == AcVariableType.BUS_V) {
dV1x = FastMath.cos(phd);
dV1y = FastMath.sin(phd);
} else if (derVariable.getType() == AcVariableType.BUS_V_ZERO) {
dV0x = FastMath.cos(pho);
dV0y = FastMath.sin(pho);
} else if (derVariable.getType() == AcVariableType.BUS_V_NEGATIVE) {
dV2x = FastMath.cos(phi);
dV2y = FastMath.sin(phi);
} else if (derVariable.getType() == AcVariableType.BUS_PHI) {
dV1x = vd * -FastMath.sin(phd);
dV1y = vd * FastMath.cos(phd);
} else if (derVariable.getType() == AcVariableType.BUS_PHI_ZERO) {
dV0x = vo * -FastMath.sin(pho);
dV0y = vo * FastMath.cos(pho);
} else if (derVariable.getType() == AcVariableType.BUS_PHI_NEGATIVE) {
dV2x = vi * -FastMath.sin(phi);
dV2y = vi * FastMath.cos(phi);
} else {
throw new IllegalStateException("Unknown derivation variable: " + derVariable + " at bus : " + bus.getId());
}
// build of voltage vectors
Vector2D positiveComponent = Fortescue.getCartesianFromPolar(vd, phd);
Vector2D zeroComponent = Fortescue.getCartesianFromPolar(vo, pho);
Vector2D negativeComponent = Fortescue.getCartesianFromPolar(vi, phi);
DenseMatrix mVfortescue = createCartesianMatrix(zeroComponent.getX(), zeroComponent.getY(), positiveComponent.getX(), positiveComponent.getY(), negativeComponent.getX(), negativeComponent.getY(), true); // vector build with cartesian values of complex fortescue voltages
DenseMatrix mVabc = Fortescue.createMatrix().times(mVfortescue).toDense(); // vector build with cartesian values of complex abc voltages
// build of Sabc vector
DenseMatrix mSabc3 = createCartesianMatrix(asymBus.getPa() / 3, asymBus.getQa() / 3, asymBus.getPb() / 3, asymBus.getQb() / 3, asymBus.getPc() / 3, asymBus.getQc() / 3, true);
// build of 1/Vabc square matrix
DenseMatrix mInvVabc = createInvVabcSquare(bus, mVabc.get(0, 0), mVabc.get(1, 0), mVabc.get(2, 0), mVabc.get(3, 0), mVabc.get(4, 0), mVabc.get(5, 0));
// build of derivative fortescue voltage square matrix
DenseMatrix mdVSquare = createCartesianMatrix(dV0x, dV0y, dV1x, dV1y, dV2x, dV2y, false);
// computation of vector = term T1:
DenseMatrix m0T1 = mInvVabc.times(mSabc3);
DenseMatrix m1T1 = Fortescue.createMatrix().times(m0T1);
DenseMatrix mT1 = mdVSquare.times(m1T1);
// build Vfortescue square matrix
DenseMatrix mSquareVFortescue = createCartesianMatrix(mVfortescue.get(0, 0), mVfortescue.get(1, 0), mVfortescue.get(2, 0), mVfortescue.get(3, 0), mVfortescue.get(4, 0), mVfortescue.get(5, 0), false);
// build of -1/3.Sabc square matrix
DenseMatrix mMinusSabc3Square = createCartesianMatrix(-asymBus.getPa() / 3, -asymBus.getQa() / 3, -asymBus.getPb() / 3, -asymBus.getQb() / 3, -asymBus.getPc() / 3, -asymBus.getQc() / 3, false);
// buils of fortescue derivative vector
DenseMatrix mdV = createCartesianMatrix(dV0x, dV0y, dV1x, dV1y, dV2x, dV2y, true);
// computation of vector = term T2:
DenseMatrix m0T2 = Fortescue.createMatrix().times(mdV);
DenseMatrix m1T2 = mInvVabc.times(m0T2);
DenseMatrix m2T2 = mInvVabc.times(m1T2);
DenseMatrix m3T2 = mMinusSabc3Square.times(m2T2);
DenseMatrix mdIFortescueConjugate = Fortescue.createMatrix().times(m3T2);
DenseMatrix mT2 = mSquareVFortescue.times(mdIFortescueConjugate);
return switch (sequenceType) {
case ZERO ->
complexPart == ComplexPart.REAL ? mdIFortescueConjugate.get(0, 0) : -mdIFortescueConjugate.get(1, 0); // dIxZero or dIyZero
case POSITIVE ->
complexPart == ComplexPart.REAL ? mT1.get(2, 0) + mT2.get(2, 0) : mT1.get(3, 0) + mT2.get(3, 0); // dPpositive or dQpositive
case NEGATIVE ->
complexPart == ComplexPart.REAL ? mdIFortescueConjugate.get(4, 0) : -mdIFortescueConjugate.get(5, 0); // dIxNegative or dIyNegative
};
}
@Override
public double eval() {
return pq(element, complexPart, sequenceType,
v(Fortescue.SequenceType.ZERO), ph(Fortescue.SequenceType.ZERO),
v(Fortescue.SequenceType.POSITIVE), ph(Fortescue.SequenceType.POSITIVE),
v(Fortescue.SequenceType.NEGATIVE), ph(Fortescue.SequenceType.NEGATIVE));
}
@Override
public double der(Variable variable) {
return dpq(element, complexPart, sequenceType, variable,
v(Fortescue.SequenceType.ZERO), ph(Fortescue.SequenceType.ZERO),
v(Fortescue.SequenceType.POSITIVE), ph(Fortescue.SequenceType.POSITIVE),
v(Fortescue.SequenceType.NEGATIVE), ph(Fortescue.SequenceType.NEGATIVE));
}
@Override
public String getName() {
return "ac_pq_fortescue_load";
}
@Override
public List> getVariables() {
return variables;
}
public static DenseMatrix createInvVabcSquare(LfBus bus, double vAx, double vAy, double vBx, double vBy, double vCx, double vCy) {
double epsilon = 0.00000001;
double vAcongVa = vAx * vAx + vAy * vAy;
String cantBuildLoad = " is null at bus : " + bus.getId() + " : cannot build load model";
if (vAcongVa < epsilon) {
throw new IllegalStateException("Va" + cantBuildLoad);
}
double vBcongVb = vBx * vBx + vBy * vBy;
if (vBcongVb < epsilon) {
throw new IllegalStateException("Vb" + cantBuildLoad);
}
double vCcongVc = vCx * vCx + vCy * vCy;
if (vCcongVc < epsilon) {
throw new IllegalStateException("Vc" + cantBuildLoad);
}
double invVax = vAx / vAcongVa;
double invVay = -vAy / vAcongVa;
double invVbx = vBx / vBcongVb;
double invVby = -vBy / vBcongVb;
double invVcx = vCx / vCcongVc;
double invVcy = -vCy / vCcongVc;
return createCartesianMatrix(invVax, invVay, invVbx, invVby, invVcx, invVcy, false);
}
/**
* if this is a vector we build: m = [m1x;m1y;m2x;m2y;m3x;m3y] equivalent in complex to [m1;m2;m3]
* if not, this is a 6x6 square matrix expected:
*
* [m1x -m1y 0 0 0 0 ]
* [m1y m1x 0 0 0 0 ]
* [ 0 0 m2x -m2y 0 0 ] [m1 0 0]
* m = [ 0 0 m2y m2x 0 0 ] equivalent in complex to [ 0 m2 0]
* [ 0 0 0 0 m3x -m3y] [ 0 0 m3]
* [ 0 0 0 0 m3y m3x]
*
*/
public static DenseMatrix createCartesianMatrix(double m1x, double m1y, double m2x, double m2y, double m3x, double m3y, boolean isVector) {
DenseMatrix mCartesian;
if (isVector) {
mCartesian = new DenseMatrix(6, 1);
mCartesian.add(0, 0, m1x);
mCartesian.add(1, 0, m1y);
mCartesian.add(2, 0, m2x);
mCartesian.add(3, 0, m2y);
mCartesian.add(4, 0, m3x);
mCartesian.add(5, 0, m3y);
} else {
mCartesian = new DenseMatrix(6, 6);
mCartesian.add(0, 0, m1x);
mCartesian.add(1, 1, m1x);
mCartesian.add(0, 1, -m1y);
mCartesian.add(1, 0, m1y);
mCartesian.add(2, 2, m2x);
mCartesian.add(3, 3, m2x);
mCartesian.add(2, 3, -m2y);
mCartesian.add(3, 2, m2y);
mCartesian.add(4, 4, m3x);
mCartesian.add(5, 5, m3x);
mCartesian.add(4, 5, -m3y);
mCartesian.add(5, 4, m3y);
}
return mCartesian;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy