From 3cecabf207b65dd03c56338ff8eff5cae4e7e12f Mon Sep 17 00:00:00 2001 From: Sylvestre Prabakaran <38729191+SylvestreSakti@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:45:24 +0100 Subject: [PATCH] Fix injections ignored on first slack bus when using multiple slacks (#1160) Signed-off-by: PRABAKARAN Sylvestre <sylvestre.prabakaran@rte-france.com> Co-authored-by: Didier Vidal <didier.vidal_externe@rte-france.com> --- .../openloadflow/ac/AcTargetVector.java | 6 ++- .../ac/equations/AcEquationSystemCreator.java | 4 +- .../ac/MultipleSlackBusesTest.java | 48 +++++++++++++++++-- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/ac/AcTargetVector.java b/src/main/java/com/powsybl/openloadflow/ac/AcTargetVector.java index 67cbfffac8..df2af8fe4a 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/AcTargetVector.java +++ b/src/main/java/com/powsybl/openloadflow/ac/AcTargetVector.java @@ -66,10 +66,14 @@ private static double getReactivePowerControlTarget(LfBranch branch) { public static void init(Equation<AcVariableType, AcEquationType> equation, LfNetwork network, double[] targets) { switch (equation.getType()) { - case BUS_TARGET_P, BUS_DISTR_SLACK_P: + case BUS_TARGET_P : targets[equation.getColumn()] = network.getBus(equation.getElementNum()).getTargetP(); break; + case BUS_DISTR_SLACK_P : + targets[equation.getColumn()] = network.getBus(equation.getElementNum()).getTargetP() - network.getSlackBuses().get(0).getTargetP(); + break; + case BUS_TARGET_Q: targets[equation.getColumn()] = network.getBus(equation.getElementNum()).getTargetQ(); break; diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemCreator.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemCreator.java index bd8e36c279..afef8792a9 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemCreator.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemCreator.java @@ -1037,8 +1037,8 @@ private void createMultipleSlackBusesEquations(EquationSystem<AcVariableType, Ac for (int i = 1; i < slackBuses.size(); i++) { LfBus slackBus = slackBuses.get(i); // example for 3 slack buses - // target_p2 = slack_p2 - slack_p1 - // target_p3 = slack_p3 - slack_p1 + // target_p2 - target_p1 = slack_p2 - slack_p1 + // target_p3 - target_p1 = slack_p3 - slack_p1 equationSystem.createEquation(slackBus, AcEquationType.BUS_DISTR_SLACK_P) .addTerms(createActiveInjectionTerms(firstSlackBus, equationSystem.getVariableSet()).stream() .map(EquationTerm::minus) diff --git a/src/test/java/com/powsybl/openloadflow/ac/MultipleSlackBusesTest.java b/src/test/java/com/powsybl/openloadflow/ac/MultipleSlackBusesTest.java index ee57d97d40..bb06f12447 100644 --- a/src/test/java/com/powsybl/openloadflow/ac/MultipleSlackBusesTest.java +++ b/src/test/java/com/powsybl/openloadflow/ac/MultipleSlackBusesTest.java @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac; +import com.powsybl.ieeecdf.converter.IeeeCdfNetworkFactory; import com.powsybl.iidm.network.Bus; import com.powsybl.iidm.network.Generator; import com.powsybl.iidm.network.Line; @@ -31,6 +32,7 @@ import java.util.Arrays; import java.util.List; +import java.util.stream.IntStream; import java.util.stream.Stream; import static com.powsybl.openloadflow.util.LoadFlowAssert.assertActivePowerEquals; @@ -79,6 +81,20 @@ static Stream<Arguments> allModelAndStoppingCriteriaTypes() { return Stream.concat(acStream, dcStream); } + static Stream<Arguments> allModelAndSwitchingTypes() { + return Stream.of( + Arguments.of(true, true), + Arguments.of(true, false), + Arguments.of(false, true), + Arguments.of(false, false) + ); + } + + static Stream<Arguments> allModelTypesAndNbSlackbuses() { + return Stream.concat(IntStream.range(1, 5).mapToObj(i -> Arguments.of(true, i)), + IntStream.range(1, 5).mapToObj(i -> Arguments.of(false, i))); + } + static Stream<Arguments> allModelTypes() { return Stream.of(Arguments.of(true), Arguments.of(false)); } @@ -148,12 +164,33 @@ void nonImpedantBranchTest(boolean ac) { assertSlackBusResults(slackBusResults, expectedSlackBusMismatch, 2); } - @ParameterizedTest(name = "ac : {0}") - @MethodSource("allModelTypes") - void loadOnSlackBusTest(boolean ac) { + @ParameterizedTest(name = "ac : {0}, nbSlackbuses : {1}") + @MethodSource("allModelTypesAndNbSlackbuses") + void differentNbSlackbusesTest(boolean ac, int nbSlackbuses) { + network = IeeeCdfNetworkFactory.create14(); + parameters.setDc(!ac).setReadSlackBus(false).setDistributedSlack(true); + parametersExt.setMaxSlackBusCount(nbSlackbuses) // Testing from 1 to 4 slack buses and expecting same global mismatch + .setSlackBusPMaxMismatch(0.001) + .setPlausibleActivePowerLimit(10000); // IEEE14 Network has generators with maxP = 9999 we want to keep for distribution + LoadFlowResult result = loadFlowRunner.run(network, parameters); + double distributedActivePower = result.getComponentResults().get(0).getDistributedActivePower(); + assertEquals(ac ? -0.006 : -13.4, distributedActivePower, 0.001); + assertActivePowerEquals(ac ? -39.996 : -33.300, network.getGenerator("B2-G").getTerminal()); + assertActivePowerEquals(ac ? 156.886 : 153.453, network.getLine("L1-2-1").getTerminal1()); + assertActivePowerEquals(ac ? 56.131 : 54.768, network.getLine("L2-4-1").getTerminal1()); + } + + @ParameterizedTest(name = "ac : {0}, switchSlacks : {1}") + @MethodSource("allModelAndSwitchingTypes") + void loadOnSlackBusTest(boolean ac, boolean switchSlacks) { parameters.setDc(!ac); parametersExt.setSlackBusSelectionMode(SlackBusSelectionMode.NAME); - parametersExt.setSlackBusesIds(List.of("VLHV2", "VLLOAD")); + if (switchSlacks) { //switching slack buses order (expecting the same result) + parametersExt.setSlackBusesIds(List.of("VLHV2", "VLLOAD")); + } else { + parametersExt.setSlackBusesIds(List.of("VLLOAD", "VLHV2")); + } + LoadFlowResult result = loadFlowRunner.run(network, parameters); assertTrue(result.isFullyConverged()); LoadFlowResult.ComponentResult componentResult = result.getComponentResults().get(0); @@ -161,7 +198,8 @@ void loadOnSlackBusTest(boolean ac) { assertEquals(expectedIterationCount, componentResult.getIterationCount()); List<LoadFlowResult.SlackBusResult> slackBusResults = componentResult.getSlackBusResults(); - assertEquals(List.of("VLHV2_0", "VLLOAD_0"), slackBusResults.stream().map(LoadFlowResult.SlackBusResult::getId).toList()); + assertEquals(switchSlacks ? List.of("VLHV2_0", "VLLOAD_0") : List.of("VLLOAD_0", "VLHV2_0"), + slackBusResults.stream().map(LoadFlowResult.SlackBusResult::getId).toList()); double expectedSlackBusMismatch = ac ? -0.711 : -3.5; assertSlackBusResults(slackBusResults, expectedSlackBusMismatch, 2);