Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support of three windings transformers as variable or function in sensitivity analysis #654

Merged
merged 30 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
387db41
Update.
annetill Dec 12, 2022
347de8c
Merge branch 'main' into integration-core-5.1.0-SNAPSHOT
geofjamg Jan 10, 2023
de95802
Update
geofjamg Jan 10, 2023
13e71d0
Wip
geofjamg Jan 16, 2023
ffc9959
Merge branch 'main' into integration-core-5.1.0-SNAPSHOT
geofjamg Jan 16, 2023
aeae3fa
Merge branch 'main' into integration-core-5.1.0-SNAPSHOT
annetill Jan 17, 2023
009eb1b
Bump to 5.1.0-RC1.
annetill Jan 17, 2023
8412409
Try supporting three windings transformers in sensitivity analysis.
obrix Nov 16, 2022
25531af
Update value count.
obrix Nov 16, 2022
969f2bc
More tests.
obrix Nov 17, 2022
b50c560
Test current function types.
obrix Nov 17, 2022
b50e3e8
Add test for phase variable with no phase shifter.
obrix Nov 17, 2022
f8cbd67
Small clean.
annetill Nov 18, 2022
8312772
Some quick adjustments.
obrix Nov 18, 2022
ee65374
fix testThreeWindingsTransformerNoPhaseShifter.
obrix Nov 18, 2022
fbc67df
Save.
annetill Nov 19, 2022
b4d73b3
Fix code smell.
annetill Nov 20, 2022
13e674c
Proposal.
annetill Nov 20, 2022
72d4a29
Set core branch to sensi_indexing_by_variable_type and adapt.
obrix Nov 23, 2022
d2f9a93
Revert CI
flo-dup Jan 17, 2023
f0c493d
Adapt to ContingencyContext
flo-dup Jan 17, 2023
055ff67
Fix unit test
flo-dup Jan 17, 2023
07df711
Clean and add a unit test.
annetill Jan 17, 2023
af324d4
Clean.
annetill Jan 17, 2023
72e1bdc
Merge branch 'main' into 3windingsTranformersInSensi
geofjamg Jan 17, 2023
7e66967
Merge branch 'main' into 3windingsTranformersInSensi
annetill Jan 18, 2023
2d5be0c
Fix code smells
flo-dup Jan 18, 2023
631805d
Clean
geofjamg Jan 18, 2023
50b3ec0
Clean
geofjamg Jan 18, 2023
3611fc1
Small clean.
annetill Jan 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@
import com.powsybl.openloadflow.network.LfBus;
import com.powsybl.openloadflow.network.LfElement;
import com.powsybl.openloadflow.network.LfNetwork;
import com.powsybl.openloadflow.network.impl.HvdcConverterStations;
import com.powsybl.openloadflow.network.impl.LfDanglingLineBus;
import com.powsybl.openloadflow.network.impl.Networks;
import com.powsybl.openloadflow.network.impl.PropagatedContingency;
import com.powsybl.openloadflow.network.impl.*;
import com.powsybl.openloadflow.network.util.ActivePowerDistribution;
import com.powsybl.openloadflow.network.util.ParticipatingElement;
import com.powsybl.openloadflow.util.PerUnit;
Expand Down Expand Up @@ -231,17 +228,22 @@ public ContingencyContext getContingencyContext() {

@Override
public EquationTerm<V, E> getFunctionEquationTerm() {
LfBranch branch;
switch (functionType) {
case BRANCH_ACTIVE_POWER:
case BRANCH_ACTIVE_POWER_1:
case BRANCH_ACTIVE_POWER_3:
return (EquationTerm<V, E>) ((LfBranch) functionElement).getP1();
case BRANCH_ACTIVE_POWER_2:
return (EquationTerm<V, E>) ((LfBranch) functionElement).getP2();
branch = (LfBranch) functionElement;
return branch instanceof LfLegBranch ? (EquationTerm<V, E>) ((LfBranch) functionElement).getP1() : (EquationTerm<V, E>) ((LfBranch) functionElement).getP2();
case BRANCH_CURRENT:
case BRANCH_CURRENT_1:
case BRANCH_CURRENT_3:
return (EquationTerm<V, E>) ((LfBranch) functionElement).getI1();
case BRANCH_CURRENT_2:
return (EquationTerm<V, E>) ((LfBranch) functionElement).getI2();
branch = (LfBranch) functionElement;
return branch instanceof LfLegBranch ? (EquationTerm<V, E>) ((LfBranch) functionElement).getI1() : (EquationTerm<V, E>) ((LfBranch) functionElement).getI2();
case BUS_VOLTAGE:
return (EquationTerm<V, E>) ((LfBus) functionElement).getCalculatedV();
default:
Expand Down Expand Up @@ -341,6 +343,9 @@ public LfElement getVariableElement() {
public Equation<V, E> getVariableEquation() {
switch (variableType) {
case TRANSFORMER_PHASE:
case TRANSFORMER_PHASE_1:
case TRANSFORMER_PHASE_2:
case TRANSFORMER_PHASE_3:
LfBranch lfBranch = (LfBranch) variableElement;
return ((EquationTerm<V, E>) lfBranch.getA1()).getEquation();
case BUS_TARGET_VOLTAGE:
Expand Down Expand Up @@ -372,7 +377,7 @@ public boolean isVariableInContingency(PropagatedContingency contingency) {
case BUS_TARGET_VOLTAGE:
// a generator or a two windings transformer.
// shunt contingency not supported yet.
// phase shifter in a three windings transformer not supported yet.
// ratio tap changer in a three windings transformer not supported yet.
return contingency.getGeneratorIdsToLose().contains(variableId) || contingency.getBranchIdsToOpen().contains(variableId);
case TRANSFORMER_PHASE:
// a phase shifter on a two windings transformer.
Expand Down Expand Up @@ -516,6 +521,9 @@ static class SingleVariableFactorGroup<V extends Enum<V> & Quantity, E extends E
public void fillRhs(Matrix rhs, Map<LfBus, Double> participationByBus) {
switch (variableType) {
case TRANSFORMER_PHASE:
case TRANSFORMER_PHASE_1:
case TRANSFORMER_PHASE_2:
case TRANSFORMER_PHASE_3:
if (variableEquation.isActive()) {
rhs.set(variableEquation.getColumn(), getIndex(), Math.toRadians(1d));
}
Expand Down Expand Up @@ -859,14 +867,20 @@ public void visitTerminal(Terminal terminal) {
throw new PowsyblException("Injection '" + injectionId + "' not found");
}

private static void checkBranch(Network network, String branchId) {
private static LfBranch checkAndGetBranchOrLeg(Network network, String branchId, SensitivityFunctionType fType, LfNetwork lfNetwork) {
Branch<?> branch = network.getBranch(branchId);
if (branch == null) {
DanglingLine danglingLine = network.getDanglingLine(branchId);
if (danglingLine == null) {
throw new PowsyblException("Branch '" + branchId + "' not found");
}
if (branch != null) {
return lfNetwork.getBranchById(branchId);
}
DanglingLine danglingLine = network.getDanglingLine(branchId);
if (danglingLine != null) {
return lfNetwork.getBranchById(branchId);
}
ThreeWindingsTransformer twt = network.getThreeWindingsTransformer(branchId);
if (twt != null) {
return lfNetwork.getBranchById(LfLegBranch.getId(branchId, getLegNumber(fType)));
}
throw new PowsyblException("Branch, dangling line or leg of '" + branchId + "' not found");
}

private static void checkBus(Network network, String busId, Map<String, Bus> busCache, boolean breakers) {
Expand All @@ -889,6 +903,30 @@ private static void checkPhaseShifter(Network network, String transformerId) {
}
}

private static void checkThreeWindingsTransformerPhaseShifter(Network network, String transformerId, SensitivityVariableType type) {
ThreeWindingsTransformer twt = network.getThreeWindingsTransformer(transformerId);
if (twt == null) {
throw new PowsyblException("Three windings transformer '" + transformerId + "' not found");
}
ThreeWindingsTransformer.Leg l;
switch (type) {
case TRANSFORMER_PHASE_1:
l = twt.getLeg1();
break;
case TRANSFORMER_PHASE_2:
l = twt.getLeg2();
break;
case TRANSFORMER_PHASE_3:
l = twt.getLeg3();
break;
default:
throw new PowsyblException("Three transformer variable type " + type + " cannot be converted to a leg");
}
if (l.getPhaseTapChanger() == null) {
throw new PowsyblException("Three windings transformer '" + transformerId + "' leg on side '" + type + "' has no phase tap changer");
}
}

private static void checkRegulatingTerminal(Network network, String equipmentId) {
Terminal terminal = getEquipmentRegulatingTerminal(network, equipmentId);
if (terminal == null) {
Expand Down Expand Up @@ -958,13 +996,10 @@ public SensitivityFactorHolder<V, E> readAndCheckFactors(Network network, Map<St
int[] factorIndex = new int[1];
factorReader.read((functionType, functionId, variableType, variableId, variableSet, contingencyContext) -> {
if (variableSet) {
if (functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER
|| functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER_1
|| functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER_2) {
checkBranch(network, functionId);
LfBranch branch = lfNetwork.getBranchById(functionId);
LfElement functionElement = branch != null && branch.getBus1() != null && branch.getBus2() != null ? branch : null;
if (isActivePowerFunctionType(functionType)) {
if (variableType == SensitivityVariableType.INJECTION_ACTIVE_POWER) {
LfBranch branch = checkAndGetBranchOrLeg(network, functionId, functionType, lfNetwork);
LfElement functionElement = branch != null && branch.getBus1() != null && branch.getBus2() != null ? branch : null;
Map<LfElement, Double> injectionLfBuses = injectionBusesByVariableId.get(variableId);
Set<String> originalVariableSetIds = originalVariableSetIdsByVariableId.get(variableId);
if (injectionLfBuses == null && originalVariableSetIds == null) {
Expand Down Expand Up @@ -1001,12 +1036,8 @@ public SensitivityFactorHolder<V, E> readAndCheckFactors(Network network, Map<St
throw createFunctionTypeNotSupportedException(functionType);
}
} else {
if ((functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER ||
functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER_1 ||
functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER_2)
&& variableType == SensitivityVariableType.HVDC_LINE_ACTIVE_POWER) {
checkBranch(network, functionId);
LfBranch branch = lfNetwork.getBranchById(functionId);
if (isActivePowerFunctionType(functionType) && variableType == SensitivityVariableType.HVDC_LINE_ACTIVE_POWER) {
LfBranch branch = checkAndGetBranchOrLeg(network, functionId, functionType, lfNetwork);
LfElement functionElement = branch != null && branch.getBus1() != null && branch.getBus2() != null ? branch : null;

HvdcLine hvdcLine = network.getHvdcLine(variableId);
Expand Down Expand Up @@ -1038,37 +1069,28 @@ public SensitivityFactorHolder<V, E> readAndCheckFactors(Network network, Map<St
} else {
LfElement functionElement;
LfElement variableElement;
if (functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER
|| functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER_1
|| functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER_2) {
checkBranch(network, functionId);
LfBranch branch = lfNetwork.getBranchById(functionId);
functionElement = branch != null && branch.getBus1() != null && branch.getBus2() != null ? branch : null;
if (variableType == SensitivityVariableType.INJECTION_ACTIVE_POWER) {
String injectionBusId = getInjectionBusId(network, variableId, breakers);
variableElement = injectionBusId != null ? lfNetwork.getBusById(injectionBusId) : null;
} else if (variableType == SensitivityVariableType.TRANSFORMER_PHASE) {
checkPhaseShifter(network, variableId);
LfBranch twt = lfNetwork.getBranchById(variableId);
variableElement = twt != null && twt.getBus1() != null && twt.getBus2() != null ? twt : null;
} else {
throw createVariableTypeNotSupportedWithFunctionTypeException(variableType, functionType);
}
} else if (functionType == SensitivityFunctionType.BRANCH_CURRENT
|| functionType == SensitivityFunctionType.BRANCH_CURRENT_1
|| functionType == SensitivityFunctionType.BRANCH_CURRENT_2) {
checkBranch(network, functionId);
LfBranch branch = lfNetwork.getBranchById(functionId);
if (isActivePowerFunctionType(functionType) || isCurrentFunctionType(functionType)) {
LfBranch branch = checkAndGetBranchOrLeg(network, functionId, functionType, lfNetwork);
functionElement = branch != null && branch.getBus1() != null && branch.getBus2() != null ? branch : null;
if (variableType == SensitivityVariableType.TRANSFORMER_PHASE) {
checkPhaseShifter(network, variableId);
LfBranch twt = lfNetwork.getBranchById(variableId);
variableElement = twt != null && twt.getBus1() != null && twt.getBus2() != null ? twt : null;
} else if (variableType == SensitivityVariableType.INJECTION_ACTIVE_POWER) {
String injectionBusId = getInjectionBusId(network, variableId, breakers);
variableElement = injectionBusId != null ? lfNetwork.getBusById(injectionBusId) : null;
} else {
throw createVariableTypeNotSupportedWithFunctionTypeException(variableType, functionType);
switch (variableType) {
case INJECTION_ACTIVE_POWER:
String injectionBusId = getInjectionBusId(network, variableId, breakers);
variableElement = injectionBusId != null ? lfNetwork.getBusById(injectionBusId) : null;
break;
case TRANSFORMER_PHASE:
checkPhaseShifter(network, variableId);
LfBranch twt = lfNetwork.getBranchById(variableId);
variableElement = twt != null && twt.getBus1() != null && twt.getBus2() != null ? twt : null;
break;
case TRANSFORMER_PHASE_1:
case TRANSFORMER_PHASE_2:
case TRANSFORMER_PHASE_3:
checkThreeWindingsTransformerPhaseShifter(network, variableId, variableType);
LfBranch leg = lfNetwork.getBranchById(LfLegBranch.getId(variableId, getLegNumber(variableType)));
variableElement = leg != null && leg.getBus1() != null && leg.getBus2() != null ? leg : null;
break;
default:
throw createVariableTypeNotSupportedWithFunctionTypeException(variableType, functionType);
}
} else if (functionType == SensitivityFunctionType.BUS_VOLTAGE) {
checkBus(network, functionId, busCache, breakers);
Expand All @@ -1094,6 +1116,20 @@ public SensitivityFactorHolder<V, E> readAndCheckFactors(Network network, Map<St
return factorHolder;
}

public static boolean isActivePowerFunctionType(SensitivityFunctionType functionType) {
return functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER
|| functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER_1
|| functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER_2
|| functionType == SensitivityFunctionType.BRANCH_ACTIVE_POWER_3;
}

public static boolean isCurrentFunctionType(SensitivityFunctionType functionType) {
return functionType == SensitivityFunctionType.BRANCH_CURRENT
|| functionType == SensitivityFunctionType.BRANCH_CURRENT_1
|| functionType == SensitivityFunctionType.BRANCH_CURRENT_2
|| functionType == SensitivityFunctionType.BRANCH_CURRENT_3;
}

public Pair<Boolean, Boolean> hasBusTargetVoltage(SensitivityFactorReader factorReader, Network network) {
// Left value if we find a BUS_TARGET_VOLTAGE factor and right value if it is linked to a transformer.
AtomicBoolean hasBusTargetVoltage = new AtomicBoolean(false);
Expand Down Expand Up @@ -1130,14 +1166,16 @@ private static <V extends Enum<V> & Quantity, E extends Enum<E> & Quantity> doub
case BRANCH_ACTIVE_POWER:
case BRANCH_ACTIVE_POWER_1:
case BRANCH_ACTIVE_POWER_2:
case BRANCH_ACTIVE_POWER_3:
return PerUnit.SB;
case BRANCH_CURRENT:
case BRANCH_CURRENT_1:
case BRANCH_CURRENT_3:
LfBranch branch = (LfBranch) factor.getFunctionElement();
return PerUnit.ib(branch.getBus1().getNominalV());
case BRANCH_CURRENT_2:
LfBranch branch2 = (LfBranch) factor.getFunctionElement();
return PerUnit.ib(branch2.getBus2().getNominalV());
return branch2 instanceof LfLegBranch ? PerUnit.ib(branch2.getBus1().getNominalV()) : PerUnit.ib(branch2.getBus2().getNominalV());
case BUS_VOLTAGE:
LfBus bus = (LfBus) factor.getFunctionElement();
return bus.getNominalV();
Expand All @@ -1155,12 +1193,15 @@ private static <V extends Enum<V> & Quantity, E extends Enum<E> & Quantity> doub
case INJECTION_ACTIVE_POWER:
return PerUnit.SB;
case TRANSFORMER_PHASE:
case TRANSFORMER_PHASE_1:
case TRANSFORMER_PHASE_2:
case TRANSFORMER_PHASE_3:
return 1; //TODO: radians ?
case BUS_TARGET_VOLTAGE:
LfBus bus = (LfBus) ((SingleVariableLfSensitivityFactor<V, E>) factor).getVariableElement();
return bus.getNominalV();
default:
throw new IllegalArgumentException("Unknown function type " + factor.getFunctionType());
throw new IllegalArgumentException("Unknown variable type " + factor.getVariableType());
}
}

Expand All @@ -1177,4 +1218,33 @@ protected static <V extends Enum<V> & Quantity, E extends Enum<E> & Quantity> do
protected static <V extends Enum<V> & Quantity, E extends Enum<E> & Quantity> double unscaleFunction(LfSensitivityFactor<V, E> factor, double value) {
return value * getFunctionBaseValue(factor);
}

protected static int getLegNumber(SensitivityFunctionType type) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would make sense to put that int (or Integer) inside the enum, don't you think?

switch (type) {
case BRANCH_ACTIVE_POWER_1:
case BRANCH_CURRENT_1:
return 1;
case BRANCH_ACTIVE_POWER_2:
case BRANCH_CURRENT_2:
return 2;
case BRANCH_ACTIVE_POWER_3:
case BRANCH_CURRENT_3:
return 3;
default:
throw new PowsyblException("Cannot convert function type " + type + " to a leg number");
}
}

protected static int getLegNumber(SensitivityVariableType type) {
switch (type) {
case TRANSFORMER_PHASE_1:
return 1;
case TRANSFORMER_PHASE_2:
return 2;
case TRANSFORMER_PHASE_3:
return 3;
default:
throw new PowsyblException("Cannot convert variable type " + type + " to a leg number");
}
}
}
Loading