Skip to content

Commit

Permalink
Implement sensi of a target voltage to a reactive power flow and curr…
Browse files Browse the repository at this point in the history
…ent (#830)

Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@rte-france.com>
  • Loading branch information
geofjamg authored Sep 11, 2023
1 parent d06748d commit 8f82ccf
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -192,28 +192,33 @@ public ContingencyContext getContingencyContext() {
}

@Override
@SuppressWarnings("unchecked")
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>) switch (functionType) {
case BRANCH_ACTIVE_POWER, BRANCH_ACTIVE_POWER_1, BRANCH_ACTIVE_POWER_3
-> ((LfBranch) functionElement).getP1();
case BRANCH_ACTIVE_POWER_2 -> {
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:
yield branch instanceof LfLegBranch ? ((LfBranch) functionElement).getP1()
: ((LfBranch) functionElement).getP2();
}
case BRANCH_REACTIVE_POWER_1, BRANCH_REACTIVE_POWER_3
-> ((LfBranch) functionElement).getQ1();
case BRANCH_REACTIVE_POWER_2 -> {
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:
throw createFunctionTypeNotSupportedException(functionType);
}
yield branch instanceof LfLegBranch ? ((LfBranch) functionElement).getQ1()
: ((LfBranch) functionElement).getQ2();
}
case BRANCH_CURRENT, BRANCH_CURRENT_1, BRANCH_CURRENT_3
-> ((LfBranch) functionElement).getI1();
case BRANCH_CURRENT_2 -> {
branch = (LfBranch) functionElement;
yield branch instanceof LfLegBranch ? ((LfBranch) functionElement).getI1()
: ((LfBranch) functionElement).getI2();
}
case BUS_VOLTAGE -> ((LfBus) functionElement).getCalculatedV();
};
}

@Override
Expand Down Expand Up @@ -1056,7 +1061,7 @@ protected SensitivityFactorHolder<V, E> readAndCheckFactors(Network network, Map
functionId, functionElement, functionType, injectionLfBuses, variableType, contingencyContext, originalVariableSetIds));
} else {
LfElement functionElement;
LfElement variableElement = null;
LfElement variableElement;
if (isActivePowerFunctionType(functionType) || isCurrentFunctionType(functionType)) {
LfBranch branch = checkAndGetBranchOrLeg(network, functionId, functionType, lfNetwork);
functionElement = branch != null && branch.getBus1() != null && branch.getBus2() != null ? branch : null;
Expand All @@ -1077,19 +1082,25 @@ protected SensitivityFactorHolder<V, E> readAndCheckFactors(Network network, Map
LfBranch leg = lfNetwork.getBranchById(LfLegBranch.getId(variableId, getLegNumber(variableType)));
variableElement = leg != null && leg.getBus1() != null && leg.getBus2() != null ? leg : null;
break;
case BUS_TARGET_VOLTAGE:
variableElement = findBusTargetVoltageVariableElement(network, variableId, breakers, lfNetwork);
break;
default:
throw createVariableTypeNotSupportedWithFunctionTypeException(variableType, functionType);
}
} else if (functionType == SensitivityFunctionType.BUS_VOLTAGE) {
checkBus(network, functionId, busCache, breakers);
functionElement = lfNetwork.getBusById(functionId);
if (variableType == SensitivityVariableType.BUS_TARGET_VOLTAGE) {
checkRegulatingTerminal(network, variableId);
Optional<Terminal> regulatingTerminal = Networks.getEquipmentRegulatingTerminal(network, variableId);
if (regulatingTerminal.isPresent()) { // this cannot fail because it is checked in checkRegulatingTerminal
Bus regulatedBus = breakers ? regulatingTerminal.get().getBusBreakerView().getBus() : regulatingTerminal.get().getBusView().getBus();
variableElement = regulatedBus != null ? lfNetwork.getBusById(regulatedBus.getId()) : null;
}
variableElement = findBusTargetVoltageVariableElement(network, variableId, breakers, lfNetwork);
} else {
throw createVariableTypeNotSupportedWithFunctionTypeException(variableType, functionType);
}
} else if (isReactivePowerFunctionType(functionType)) {
LfBranch branch = checkAndGetBranchOrLeg(network, functionId, functionType, lfNetwork);
functionElement = branch != null && branch.getBus1() != null && branch.getBus2() != null ? branch : null;
if (variableType == SensitivityVariableType.BUS_TARGET_VOLTAGE) {
variableElement = findBusTargetVoltageVariableElement(network, variableId, breakers, lfNetwork);
} else {
throw createVariableTypeNotSupportedWithFunctionTypeException(variableType, functionType);
}
Expand All @@ -1105,13 +1116,27 @@ protected SensitivityFactorHolder<V, E> readAndCheckFactors(Network network, Map
return factorHolder;
}

protected static LfElement findBusTargetVoltageVariableElement(Network network, String variableId, boolean breakers,
LfNetwork lfNetwork) {
checkRegulatingTerminal(network, variableId);
Terminal regulatingTerminal = Networks.getEquipmentRegulatingTerminal(network, variableId).orElseThrow(); // this cannot fail because it is checked in checkRegulatingTerminal
Bus regulatedBus = breakers ? regulatingTerminal.getBusBreakerView().getBus() : regulatingTerminal.getBusView().getBus();
return regulatedBus != null ? lfNetwork.getBusById(regulatedBus.getId()) : null;
}

private 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;
}

private static boolean isReactivePowerFunctionType(SensitivityFunctionType functionType) {
return functionType == SensitivityFunctionType.BRANCH_REACTIVE_POWER_1
|| functionType == SensitivityFunctionType.BRANCH_REACTIVE_POWER_2
|| functionType == SensitivityFunctionType.BRANCH_REACTIVE_POWER_3;
}

private static boolean isCurrentFunctionType(SensitivityFunctionType functionType) {
return functionType == SensitivityFunctionType.BRANCH_CURRENT
|| functionType == SensitivityFunctionType.BRANCH_CURRENT_1
Expand Down Expand Up @@ -1151,26 +1176,21 @@ protected static boolean isDistributedSlackOnLoads(DcLoadFlowParameters lfParame
* Base value for per-uniting, depending on the function type
*/
private static <V extends Enum<V> & Quantity, E extends Enum<E> & Quantity> double getFunctionBaseValue(LfSensitivityFactor<V, E> factor) {
switch (factor.getFunctionType()) {
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:
return switch (factor.getFunctionType()) {
case BRANCH_ACTIVE_POWER, BRANCH_ACTIVE_POWER_1, BRANCH_ACTIVE_POWER_2, BRANCH_ACTIVE_POWER_3,
BRANCH_REACTIVE_POWER_1, BRANCH_REACTIVE_POWER_2, BRANCH_REACTIVE_POWER_3
-> PerUnit.SB;
case BRANCH_CURRENT, BRANCH_CURRENT_1, BRANCH_CURRENT_3 -> {
LfBranch branch = (LfBranch) factor.getFunctionElement();
return PerUnit.ib(branch.getBus1().getNominalV());
case BRANCH_CURRENT_2:
yield PerUnit.ib(branch.getBus1().getNominalV());
}
case BRANCH_CURRENT_2 -> {
LfBranch branch2 = (LfBranch) factor.getFunctionElement();
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();
default:
throw new IllegalArgumentException("Unknown function type " + factor.getFunctionType());
}
yield branch2 instanceof LfLegBranch ? PerUnit.ib(branch2.getBus1().getNominalV()) :
PerUnit.ib(branch2.getBus2().getNominalV());
}
case BUS_VOLTAGE -> ((LfBus) factor.getFunctionElement()).getNominalV();
};
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.powsybl.openloadflow.util.LoadFlowAssert.assertCurrentEquals;
import static com.powsybl.openloadflow.util.LoadFlowAssert.assertReactivePowerEquals;
import static org.junit.jupiter.api.Assertions.*;

/**
Expand Down Expand Up @@ -1295,4 +1297,104 @@ void testWithTieLines() {
assertEquals(1, result.getValues().size());
assertEquals(35.000, result.getBranchFlow1FunctionReferenceValue("t12"), LoadFlowAssert.DELTA_POWER);
}

@Test
void testReactivePowerAndCurrentPerTargetVSensi() {
Network network = EurostagTutorialExample1Factory.create();

SensitivityAnalysisParameters sensiParameters = createParameters(false, "NLOAD");

List<SensitivityFactor> factors = List.of(
new SensitivityFactor(SensitivityFunctionType.BRANCH_REACTIVE_POWER_1,
"NHV2_NLOAD",
SensitivityVariableType.BUS_TARGET_VOLTAGE,
"GEN",
false,
ContingencyContext.all()),
new SensitivityFactor(SensitivityFunctionType.BRANCH_REACTIVE_POWER_2,
"NHV2_NLOAD",
SensitivityVariableType.BUS_TARGET_VOLTAGE,
"GEN",
false,
ContingencyContext.all()),
new SensitivityFactor(SensitivityFunctionType.BRANCH_CURRENT_1,
"NHV2_NLOAD",
SensitivityVariableType.BUS_TARGET_VOLTAGE,
"GEN",
false,
ContingencyContext.all()),
new SensitivityFactor(SensitivityFunctionType.BRANCH_CURRENT_2,
"NHV2_NLOAD",
SensitivityVariableType.BUS_TARGET_VOLTAGE,
"GEN",
false,
ContingencyContext.all())
);

SensitivityAnalysisResult result = sensiRunner.run(network, factors, Collections.emptyList(), Collections.emptyList(), sensiParameters);

assertEquals(4, result.getValues().size());
assertEquals(-7.959, result.getSensitivityValue("GEN", "NHV2_NLOAD", SensitivityFunctionType.BRANCH_REACTIVE_POWER_1, SensitivityVariableType.BUS_TARGET_VOLTAGE), LoadFlowAssert.DELTA_POWER);
assertEquals(0.0, result.getSensitivityValue("GEN", "NHV2_NLOAD", SensitivityFunctionType.BRANCH_REACTIVE_POWER_2, SensitivityVariableType.BUS_TARGET_VOLTAGE), LoadFlowAssert.DELTA_POWER);
assertEquals(-52.329, result.getSensitivityValue("GEN", "NHV2_NLOAD", SensitivityFunctionType.BRANCH_CURRENT_1, SensitivityVariableType.BUS_TARGET_VOLTAGE), LoadFlowAssert.DELTA_POWER);
assertEquals(-132.392, result.getSensitivityValue("GEN", "NHV2_NLOAD", SensitivityFunctionType.BRANCH_CURRENT_2, SensitivityVariableType.BUS_TARGET_VOLTAGE), LoadFlowAssert.DELTA_POWER);

runAcLf(network);

// check reference flows are consistents with LF ones
var twt = network.getTwoWindingsTransformer("NHV2_NLOAD");
assertReactivePowerEquals(result.getFunctionReferenceValue("NHV2_NLOAD", SensitivityFunctionType.BRANCH_REACTIVE_POWER_1),
twt.getTerminal1());
assertReactivePowerEquals(result.getFunctionReferenceValue("NHV2_NLOAD", SensitivityFunctionType.BRANCH_REACTIVE_POWER_2),
twt.getTerminal2());
assertCurrentEquals(result.getFunctionReferenceValue("NHV2_NLOAD", SensitivityFunctionType.BRANCH_CURRENT_1),
twt.getTerminal1());
assertCurrentEquals(result.getFunctionReferenceValue("NHV2_NLOAD", SensitivityFunctionType.BRANCH_CURRENT_2),
twt.getTerminal2());

// check sensi values looks consistent with 2 LF diff
double q1Before = twt.getTerminal1().getQ();
double q2Before = twt.getTerminal2().getQ();
double i1Before = twt.getTerminal1().getI();
double i2Before = twt.getTerminal2().getI();

Generator gen = network.getGenerator("GEN");
gen.setTargetV(gen.getTargetV() + 1);

runAcLf(network);

assertEquals(-7.2817, twt.getTerminal1().getQ() - q1Before, LoadFlowAssert.DELTA_SENSITIVITY_VALUE); // looks ok vs -7.959
assertEquals(0.0007, twt.getTerminal2().getQ() - q2Before, LoadFlowAssert.DELTA_SENSITIVITY_VALUE); // looks ok vs 0
assertEquals(-49.1009, twt.getTerminal1().getI() - i1Before, LoadFlowAssert.DELTA_SENSITIVITY_VALUE); // looks ok vs -52.329
assertEquals(-124.2233, twt.getTerminal2().getI() - i2Before, LoadFlowAssert.DELTA_SENSITIVITY_VALUE); // looks ok vs -132.392
}

@Test
void testUnsupportedVariablesSensiV() {
Network network = EurostagTutorialExample1Factory.create();

SensitivityAnalysisParameters sensiParameters = createParameters(false, "NLOAD");
List<Contingency> contingencies = Collections.emptyList();
List<SensitivityVariableSet> variableSets = Collections.emptyList();

List<SensitivityFactor> factors = List.of(new SensitivityFactor(SensitivityFunctionType.BRANCH_REACTIVE_POWER_1,
"NHV2_NLOAD",
SensitivityVariableType.INJECTION_ACTIVE_POWER,
"GEN",
false,
ContingencyContext.all()));

CompletionException e = assertThrows(CompletionException.class, () -> sensiRunner.run(network, factors, contingencies, variableSets, sensiParameters));
assertEquals("Variable type INJECTION_ACTIVE_POWER not supported with function type BRANCH_REACTIVE_POWER_1", e.getCause().getMessage());

List<SensitivityFactor> factors2 = List.of(new SensitivityFactor(SensitivityFunctionType.BUS_VOLTAGE,
"NLOAD",
SensitivityVariableType.INJECTION_ACTIVE_POWER,
"GEN",
false,
ContingencyContext.all()));

e = assertThrows(CompletionException.class, () -> sensiRunner.run(network, factors2, contingencies, variableSets, sensiParameters));
assertEquals("Variable type INJECTION_ACTIVE_POWER not supported with function type BUS_VOLTAGE", e.getCause().getMessage());
}
}

0 comments on commit 8f82ccf

Please sign in to comment.