From 61381e5ec3feda7e6f2aebb989889a816332f70e Mon Sep 17 00:00:00 2001 From: vmouradian Date: Thu, 5 Dec 2024 16:07:54 +0100 Subject: [PATCH 1/6] refactor dc outerloops creation + add active boolean to outerloops Signed-off-by: vmouradian --- .../AbstractAcOuterLoopConfig.java | 16 +++--- .../openloadflow/OpenLoadFlowParameters.java | 23 ++++++++- .../openloadflow/ac/AcloadFlowEngine.java | 1 + ...=> DcAreaInterchangeControlOuterLoop.java} | 6 +-- .../openloadflow/dc/DcLoadFlowEngine.java | 51 ++++++++++++------- .../openloadflow/dc/DcLoadFlowParameters.java | 12 +++++ ...tractActivePowerDistributionOuterLoop.java | 11 ++++ ...stractAreaInterchangeControlOuterLoop.java | 2 +- .../openloadflow/lf/outerloop/OuterLoop.java | 4 ++ .../OpenLoadFlowParametersTest.java | 24 ++++++--- 10 files changed, 111 insertions(+), 39 deletions(-) rename src/main/java/com/powsybl/openloadflow/dc/{DcAreaInterchangeControlControlOuterLoop.java => DcAreaInterchangeControlOuterLoop.java} (75%) diff --git a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java index 54a3814117..3632e29bc1 100644 --- a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java +++ b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java @@ -138,14 +138,14 @@ protected static Optional createAutomationSystemOuterLoop(OpenLoadF static List filterInconsistentOuterLoops(List outerLoops) { if (outerLoops.stream().anyMatch(AcAreaInterchangeControlOuterLoop.class::isInstance)) { - return outerLoops.stream().filter(o -> { - if (o instanceof DistributedSlackOuterLoop) { - LOGGER.warn("Distributed slack and area interchange control are both enabled. " + - "Distributed slack outer loop will be disabled, slack will be distributed by the area interchange control."); - return false; - } - return true; - }).toList(); + outerLoops.stream() + .filter(DistributedSlackOuterLoop.class::isInstance) + .map(DistributedSlackOuterLoop.class::cast) + .forEach(distributedSlackOuterLoop -> { + LOGGER.warn("Distributed slack and area interchange control are both enabled. " + + "Distributed slack outer loop will be disabled, slack will be distributed by the area interchange control."); + distributedSlackOuterLoop.setActive(false); + }); } return outerLoops; } diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java index 9b6bf588e8..6b28189bf8 100644 --- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java +++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java @@ -24,13 +24,17 @@ import com.powsybl.openloadflow.ac.solver.*; import com.powsybl.openloadflow.ac.outerloop.AcOuterLoop; import com.powsybl.openloadflow.ac.outerloop.ReactiveLimitsOuterLoop; +import com.powsybl.openloadflow.dc.DcAreaInterchangeControlOuterLoop; +import com.powsybl.openloadflow.dc.DcIncrementalPhaseControlOuterLoop; import com.powsybl.openloadflow.dc.DcLoadFlowParameters; +import com.powsybl.openloadflow.dc.DcOuterLoop; import com.powsybl.openloadflow.dc.DcValueVoltageInitializer; import com.powsybl.openloadflow.dc.equations.DcApproximationType; import com.powsybl.openloadflow.dc.equations.DcEquationSystemCreationParameters; import com.powsybl.openloadflow.graph.GraphConnectivityFactory; import com.powsybl.openloadflow.lf.AbstractLoadFlowParameters; import com.powsybl.openloadflow.network.*; +import com.powsybl.openloadflow.network.util.ActivePowerDistribution; import com.powsybl.openloadflow.network.util.PreviousValueVoltageInitializer; import com.powsybl.openloadflow.network.util.UniformValueVoltageInitializer; import com.powsybl.openloadflow.network.util.VoltageInitializer; @@ -1816,7 +1820,7 @@ public static AcLoadFlowParameters createAcParameters(Network network, LoadFlowP return acParameters; } - static List createOuterLoops(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) { + static List createAcOuterLoops(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) { AcOuterLoopConfig outerLoopConfig = AcOuterLoopConfig.findOuterLoopConfig() .orElseGet(() -> parametersExt.getOuterLoopNames() != null ? new ExplicitAcOuterLoopConfig() : new DefaultAcOuterLoopConfig()); @@ -1835,7 +1839,7 @@ public static AcLoadFlowParameters createAcParameters(LoadFlowParameters paramet VoltageInitializer voltageInitializer = getExtendedVoltageInitializer(parameters, parametersExt, networkParameters, matrixFactory); - List outerLoops = createOuterLoops(parameters, parametersExt); + List outerLoops = createAcOuterLoops(parameters, parametersExt); AcSolverFactory solverFactory = AcSolverFactory.find(parametersExt.getAcSolverType()); @@ -1851,6 +1855,20 @@ public static AcLoadFlowParameters createAcParameters(LoadFlowParameters paramet .setSolverFactory(solverFactory, parameters); } + static List createDcOuterLoops(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) { + List outerLoops = new ArrayList<>(); + if (parameters.isPhaseShifterRegulationOn()) { + DcIncrementalPhaseControlOuterLoop phaseShifterControlOuterLoop = new DcIncrementalPhaseControlOuterLoop(); + outerLoops.add(phaseShifterControlOuterLoop); + } + if (parametersExt.isAreaInterchangeControl()) { + ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(parameters.getBalanceType(), false, parametersExt.isUseActiveLimits()); + DcAreaInterchangeControlOuterLoop areaInterchangeControlOuterLoop = new DcAreaInterchangeControlOuterLoop(activePowerDistribution, parametersExt.getSlackBusPMaxMismatch(), parametersExt.getAreaInterchangePMaxMismatch()); + outerLoops.add(areaInterchangeControlOuterLoop); + } + return outerLoops; + } + public static DcLoadFlowParameters createDcParameters(Network network, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt, MatrixFactory matrixFactory, GraphConnectivityFactory connectivityFactory, boolean forcePhaseControlOffAndAddAngle1Var) { @@ -1914,6 +1932,7 @@ public static DcLoadFlowParameters createDcParameters(LoadFlowParameters paramet .setAreaInterchangeControl(parametersExt.isAreaInterchangeControl()) .setBalanceType(parameters.getBalanceType()) .setSetVToNan(true) + .setOuterLoops(createDcOuterLoops(parameters, parametersExt)) .setMaxOuterLoopIterations(parametersExt.getMaxOuterLoopIterations()) .setSlackBusPMaxMismatch(parametersExt.getSlackBusPMaxMismatch()) .setAreaInterchangePMaxMismatch(parametersExt.getAreaInterchangePMaxMismatch()); diff --git a/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java index 2afcd6f13b..660097bfdd 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java @@ -150,6 +150,7 @@ public AcLoadFlowResult run() { List outerLoops = context.getParameters().getOuterLoops(); List> outerLoopsAndContexts = outerLoops.stream() + .filter(AcOuterLoop::isActive) .map(outerLoop -> Pair.of(outerLoop, new AcOuterLoopContext(context.getNetwork()))) .toList(); diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcAreaInterchangeControlControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/dc/DcAreaInterchangeControlOuterLoop.java similarity index 75% rename from src/main/java/com/powsybl/openloadflow/dc/DcAreaInterchangeControlControlOuterLoop.java rename to src/main/java/com/powsybl/openloadflow/dc/DcAreaInterchangeControlOuterLoop.java index cbba0cfd8d..46e4b149e6 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcAreaInterchangeControlControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcAreaInterchangeControlOuterLoop.java @@ -20,11 +20,11 @@ /** * @author Valentin Mouradian {@literal } */ -public class DcAreaInterchangeControlControlOuterLoop extends AbstractAreaInterchangeControlOuterLoop implements DcOuterLoop { +public class DcAreaInterchangeControlOuterLoop extends AbstractAreaInterchangeControlOuterLoop implements DcOuterLoop { - private static final Logger LOGGER = LoggerFactory.getLogger(DcAreaInterchangeControlControlOuterLoop.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DcAreaInterchangeControlOuterLoop.class); - protected DcAreaInterchangeControlControlOuterLoop(ActivePowerDistribution activePowerDistribution, double slackBusPMaxMismatch, double areaInterchangePMaxMismatch) { + public DcAreaInterchangeControlOuterLoop(ActivePowerDistribution activePowerDistribution, double slackBusPMaxMismatch, double areaInterchangePMaxMismatch) { super(activePowerDistribution, null, slackBusPMaxMismatch, areaInterchangePMaxMismatch, LOGGER); } diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java index da3c9fc7b4..0b6b70f53a 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java @@ -16,6 +16,7 @@ import com.powsybl.openloadflow.dc.equations.DcVariableType; import com.powsybl.openloadflow.equations.*; import com.powsybl.openloadflow.lf.LoadFlowEngine; +import com.powsybl.openloadflow.lf.outerloop.OuterLoop; import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult; import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus; import com.powsybl.openloadflow.network.LfBus; @@ -31,10 +32,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.Optional; /** * @author Geoffroy Jamgotchian {@literal } @@ -184,30 +185,29 @@ public DcLoadFlowResult run() { DcLoadFlowParameters parameters = context.getParameters(); TargetVector targetVector = context.getTargetVector(); RunningContext runningContext = new RunningContext(); + List outerLoops = parameters.getOuterLoops(); - // outer loop initialization - List> outerLoopsAndContexts = new ArrayList<>(); + boolean distributedSlack = parameters.isDistributedSlack() || areaInterchangeControlFallback(); - if (parameters.getNetworkParameters().isPhaseControl()) { - DcIncrementalPhaseControlOuterLoop phaseShifterControlOuterLoop = new DcIncrementalPhaseControlOuterLoop(); - DcOuterLoopContext phaseShifterControlOuterLoopContext = new DcOuterLoopContext(network); - outerLoopsAndContexts.add(Pair.of(phaseShifterControlOuterLoop, phaseShifterControlOuterLoopContext)); - phaseShifterControlOuterLoop.initialize(phaseShifterControlOuterLoopContext); - } + List activeOuterLoops = outerLoops.stream() + .filter(DcOuterLoop::isActive) + .toList(); + List> outerLoopsAndContexts = activeOuterLoops.stream() + .map(outerLoop -> Pair.of(outerLoop, new DcOuterLoopContext(context.getNetwork()))) + .toList(); - if (parameters.isAreaInterchangeControl() && network.hasArea()) { - ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(parameters.getBalanceType(), false, parameters.getNetworkParameters().isUseActiveLimits()); - DcAreaInterchangeControlControlOuterLoop areaInterchangeControlOuterLoop = new DcAreaInterchangeControlControlOuterLoop(activePowerDistribution, parameters.getSlackBusPMaxMismatch(), parameters.getAreaInterchangePMaxMismatch()); - DcOuterLoopContext areaInterchangeControlOuterLoopContext = new DcOuterLoopContext(network); - outerLoopsAndContexts.add(Pair.of(areaInterchangeControlOuterLoop, areaInterchangeControlOuterLoopContext)); - areaInterchangeControlOuterLoop.initialize(areaInterchangeControlOuterLoopContext); + // outer loops initialization + for (var outerLoopAndContext : outerLoopsAndContexts) { + var outerLoop = outerLoopAndContext.getLeft(); + var outerLoopContext = outerLoopAndContext.getRight(); + outerLoop.initialize(outerLoopContext); } initStateVector(network, equationSystem, new UniformValueVoltageInitializer()); double initialSlackBusActivePowerMismatch = getActivePowerMismatch(network.getBuses()); double distributedActivePower = 0.0; - if (parameters.isDistributedSlack() || parameters.isAreaInterchangeControl()) { + if (distributedSlack) { LoadFlowParameters.BalanceType balanceType = parameters.getBalanceType(); boolean useActiveLimits = parameters.getNetworkParameters().isUseActiveLimits(); ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(balanceType, false, useActiveLimits); @@ -284,7 +284,7 @@ public DcLoadFlowResult run() { for (var outerLoopAndContext : Lists.reverse(outerLoopsAndContexts)) { var outerLoop = outerLoopAndContext.getLeft(); var outerLoopContext = outerLoopAndContext.getRight(); - if (outerLoop instanceof DcAreaInterchangeControlControlOuterLoop activePowerDistributionOuterLoop) { + if (outerLoop instanceof DcAreaInterchangeControlOuterLoop activePowerDistributionOuterLoop) { distributedActivePower += activePowerDistributionOuterLoop.getDistributedActivePower(outerLoopContext); } outerLoop.cleanup(outerLoopContext); @@ -333,4 +333,21 @@ public static List run(T network, LfNetworkLoader netwo .toList(); } + /** + * If Area Interchange Control is activated but the network has no area, we fall back to distributed slack + */ + boolean areaInterchangeControlFallback() { + List outerLoops = context.getParameters().getOuterLoops(); + Optional aicOuterLoop = outerLoops.stream() + .filter(DcAreaInterchangeControlOuterLoop.class::isInstance) + .filter(OuterLoop::isActive) + .map(DcAreaInterchangeControlOuterLoop.class::cast) + .findFirst(); + if (aicOuterLoop.isPresent() && !context.getNetwork().hasArea()) { + aicOuterLoop.get().setActive(false); + return true; + } + return false; + } + } diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java index 550769c64d..c275c07d0b 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java @@ -12,6 +12,8 @@ import com.powsybl.openloadflow.dc.equations.DcEquationSystemCreationParameters; import com.powsybl.openloadflow.lf.AbstractLoadFlowParameters; +import java.util.Collections; +import java.util.List; import java.util.Objects; /** @@ -28,6 +30,7 @@ public class DcLoadFlowParameters extends AbstractLoadFlowParameters outerLoops = Collections.emptyList(); private int maxOuterLoopIterations = DEFAULT_MAX_OUTER_LOOP_ITERATIONS; @@ -89,6 +92,15 @@ public DcLoadFlowParameters setSetVToNan(boolean setVToNan) { return this; } + public List getOuterLoops() { + return outerLoops; + } + + public DcLoadFlowParameters setOuterLoops(List outerLoops) { + this.outerLoops = Objects.requireNonNull(outerLoops); + return this; + } + public double getSlackBusPMaxMismatch() { return slackBusPMaxMismatch; } diff --git a/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractActivePowerDistributionOuterLoop.java b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractActivePowerDistributionOuterLoop.java index 81e6ca2556..574871d320 100644 --- a/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractActivePowerDistributionOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractActivePowerDistributionOuterLoop.java @@ -21,6 +21,17 @@ public abstract class AbstractActivePowerDistributionOuterLoop O extends OuterLoopContext> implements ActivePowerDistributionOuterLoop { + boolean active = true; + + @Override + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + @Override public double getDistributedActivePower(O context) { var contextData = context.getData(); diff --git a/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAreaInterchangeControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAreaInterchangeControlOuterLoop.java index 83a65b9019..fd0a479ee2 100644 --- a/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAreaInterchangeControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAreaInterchangeControlOuterLoop.java @@ -42,7 +42,7 @@ public abstract class AbstractAreaInterchangeControlOuterLoop< C extends LoadFlowContext, O extends AbstractOuterLoopContext> extends AbstractActivePowerDistributionOuterLoop - implements OuterLoop, ActivePowerDistributionOuterLoop { + implements ActivePowerDistributionOuterLoop { private final Logger logger; diff --git a/src/main/java/com/powsybl/openloadflow/lf/outerloop/OuterLoop.java b/src/main/java/com/powsybl/openloadflow/lf/outerloop/OuterLoop.java index 6e8281b825..7d8d120644 100644 --- a/src/main/java/com/powsybl/openloadflow/lf/outerloop/OuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/lf/outerloop/OuterLoop.java @@ -34,4 +34,8 @@ default void initialize(O context) { default void cleanup(O context) { } + + default boolean isActive() { + return true; + } } diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java index e0743a0126..60a11900af 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java @@ -23,6 +23,8 @@ import com.powsybl.loadflow.LoadFlowParameters; import com.powsybl.loadflow.LoadFlowResult; import com.powsybl.math.matrix.DenseMatrixFactory; +import com.powsybl.openloadflow.ac.outerloop.AcAreaInterchangeControlOuterLoop; +import com.powsybl.openloadflow.ac.outerloop.DistributedSlackOuterLoop; import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory; import com.powsybl.openloadflow.lf.outerloop.OuterLoop; import com.powsybl.openloadflow.network.*; @@ -407,17 +409,17 @@ void testExplicitOuterLoopsParameter() { OpenLoadFlowParameters parametersExt = new OpenLoadFlowParameters() .setSecondaryVoltageControl(true); - assertEquals(List.of("DistributedSlack", "SecondaryVoltageControl", "VoltageMonitoring", "ReactiveLimits", "ShuntVoltageControl"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); + assertEquals(List.of("DistributedSlack", "SecondaryVoltageControl", "VoltageMonitoring", "ReactiveLimits", "ShuntVoltageControl"), OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); parametersExt.setOuterLoopNames(List.of("ReactiveLimits", "SecondaryVoltageControl")); - assertEquals(List.of("ReactiveLimits", "SecondaryVoltageControl"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); + assertEquals(List.of("ReactiveLimits", "SecondaryVoltageControl"), OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); parametersExt.setOuterLoopNames(ExplicitAcOuterLoopConfig.NAMES); - PowsyblException e = assertThrows(PowsyblException.class, () -> OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt)); + PowsyblException e = assertThrows(PowsyblException.class, () -> OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt)); assertEquals("Multiple (2) outer loops with same type: ShuntVoltageControl", e.getMessage()); parametersExt.setOuterLoopNames(List.of("ReactiveLimits", "Foo")); - e = assertThrows(PowsyblException.class, () -> OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt)); + e = assertThrows(PowsyblException.class, () -> OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt)); assertEquals("Unknown outer loop 'Foo'", e.getMessage()); assertEquals("Ordered explicit list of outer loop names, supported outer loops are IncrementalPhaseControl, DistributedSlack, IncrementalShuntVoltageControl, IncrementalTransformerVoltageControl, VoltageMonitoring, PhaseControl, ReactiveLimits, SecondaryVoltageControl, ShuntVoltageControl, SimpleTransformerVoltageControl, TransformerVoltageControl, AutomationSystem, IncrementalTransformerReactivePowerControl, AreaInterchangeControl", @@ -430,16 +432,22 @@ void testSlackDistributionOuterLoops() { .setDistributedSlack(true); OpenLoadFlowParameters parametersExt = new OpenLoadFlowParameters(); - assertEquals(List.of("DistributedSlack", "VoltageMonitoring", "ReactiveLimits"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); + assertEquals(List.of("DistributedSlack", "VoltageMonitoring", "ReactiveLimits"), OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); parametersExt.setAreaInterchangeControl(true); - assertEquals(List.of("AreaInterchangeControl", "VoltageMonitoring", "ReactiveLimits"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); + var outerLoops = OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt); + assertEquals(List.of("DistributedSlack", "AreaInterchangeControl", "VoltageMonitoring", "ReactiveLimits"), outerLoops.stream().map(OuterLoop::getType).toList()); + assertTrue(outerLoops.stream().anyMatch(ol -> ol instanceof AcAreaInterchangeControlOuterLoop && ol.isActive())); + assertFalse(outerLoops.stream().anyMatch(ol -> ol instanceof DistributedSlackOuterLoop && ol.isActive())); parametersExt.setOuterLoopNames(List.of("DistributedSlack", "AreaInterchangeControl")); - assertEquals(List.of("AreaInterchangeControl"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); + outerLoops = OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt); + assertEquals(List.of("DistributedSlack", "AreaInterchangeControl"), outerLoops.stream().map(OuterLoop::getType).toList()); + assertTrue(outerLoops.stream().anyMatch(ol -> ol instanceof AcAreaInterchangeControlOuterLoop && ol.isActive())); + assertFalse(outerLoops.stream().anyMatch(ol -> ol instanceof DistributedSlackOuterLoop && ol.isActive())); parametersExt.setOuterLoopNames(List.of("DistributedSlack")); - assertEquals(List.of("DistributedSlack"), OpenLoadFlowParameters.createOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); + assertEquals(List.of("DistributedSlack"), OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); } From 246cd64caace0ce25e71bcc734098fa616415e24 Mon Sep 17 00:00:00 2001 From: vmouradian Date: Fri, 6 Dec 2024 15:13:21 +0100 Subject: [PATCH 2/6] remove active parameter from outer loop Signed-off-by: vmouradian --- .../openloadflow/AbstractAcOuterLoopConfig.java | 16 ++++++++-------- .../openloadflow/OpenLoadFlowParameters.java | 1 - .../openloadflow/ac/AcloadFlowEngine.java | 1 - .../openloadflow/dc/DcLoadFlowEngine.java | 17 ++++++----------- .../openloadflow/dc/DcLoadFlowParameters.java | 11 ----------- ...bstractActivePowerDistributionOuterLoop.java | 11 ----------- .../openloadflow/lf/outerloop/OuterLoop.java | 4 ---- .../OpenLoadFlowParametersTest.java | 13 ++----------- 8 files changed, 16 insertions(+), 58 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java index 3632e29bc1..54a3814117 100644 --- a/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java +++ b/src/main/java/com/powsybl/openloadflow/AbstractAcOuterLoopConfig.java @@ -138,14 +138,14 @@ protected static Optional createAutomationSystemOuterLoop(OpenLoadF static List filterInconsistentOuterLoops(List outerLoops) { if (outerLoops.stream().anyMatch(AcAreaInterchangeControlOuterLoop.class::isInstance)) { - outerLoops.stream() - .filter(DistributedSlackOuterLoop.class::isInstance) - .map(DistributedSlackOuterLoop.class::cast) - .forEach(distributedSlackOuterLoop -> { - LOGGER.warn("Distributed slack and area interchange control are both enabled. " + - "Distributed slack outer loop will be disabled, slack will be distributed by the area interchange control."); - distributedSlackOuterLoop.setActive(false); - }); + return outerLoops.stream().filter(o -> { + if (o instanceof DistributedSlackOuterLoop) { + LOGGER.warn("Distributed slack and area interchange control are both enabled. " + + "Distributed slack outer loop will be disabled, slack will be distributed by the area interchange control."); + return false; + } + return true; + }).toList(); } return outerLoops; } diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java index 6b28189bf8..dff70922ee 100644 --- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java +++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java @@ -1929,7 +1929,6 @@ public static DcLoadFlowParameters createDcParameters(LoadFlowParameters paramet .setSlackDistributionFailureBehavior(parametersExt.getSlackDistributionFailureBehavior()) .setMatrixFactory(matrixFactory) .setDistributedSlack(parameters.isDistributedSlack()) - .setAreaInterchangeControl(parametersExt.isAreaInterchangeControl()) .setBalanceType(parameters.getBalanceType()) .setSetVToNan(true) .setOuterLoops(createDcOuterLoops(parameters, parametersExt)) diff --git a/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java index 660097bfdd..2afcd6f13b 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java @@ -150,7 +150,6 @@ public AcLoadFlowResult run() { List outerLoops = context.getParameters().getOuterLoops(); List> outerLoopsAndContexts = outerLoops.stream() - .filter(AcOuterLoop::isActive) .map(outerLoop -> Pair.of(outerLoop, new AcOuterLoopContext(context.getNetwork()))) .toList(); diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java index 0b6b70f53a..47ecd57229 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java @@ -16,7 +16,6 @@ import com.powsybl.openloadflow.dc.equations.DcVariableType; import com.powsybl.openloadflow.equations.*; import com.powsybl.openloadflow.lf.LoadFlowEngine; -import com.powsybl.openloadflow.lf.outerloop.OuterLoop; import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult; import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus; import com.powsybl.openloadflow.network.LfBus; @@ -35,7 +34,6 @@ import java.util.Collection; import java.util.List; import java.util.Objects; -import java.util.Optional; /** * @author Geoffroy Jamgotchian {@literal } @@ -190,7 +188,6 @@ public DcLoadFlowResult run() { boolean distributedSlack = parameters.isDistributedSlack() || areaInterchangeControlFallback(); List activeOuterLoops = outerLoops.stream() - .filter(DcOuterLoop::isActive) .toList(); List> outerLoopsAndContexts = activeOuterLoops.stream() .map(outerLoop -> Pair.of(outerLoop, new DcOuterLoopContext(context.getNetwork()))) @@ -334,17 +331,15 @@ public static List run(T network, LfNetworkLoader netwo } /** - * If Area Interchange Control is activated but the network has no area, we fall back to distributed slack + * If Area Interchange Control is activated but the network has no area, we remove the AIC outer loop and fall back to distributed slack */ boolean areaInterchangeControlFallback() { List outerLoops = context.getParameters().getOuterLoops(); - Optional aicOuterLoop = outerLoops.stream() - .filter(DcAreaInterchangeControlOuterLoop.class::isInstance) - .filter(OuterLoop::isActive) - .map(DcAreaInterchangeControlOuterLoop.class::cast) - .findFirst(); - if (aicOuterLoop.isPresent() && !context.getNetwork().hasArea()) { - aicOuterLoop.get().setActive(false); + boolean aicOuterLoop = outerLoops.stream().anyMatch(DcAreaInterchangeControlOuterLoop.class::isInstance); + if (aicOuterLoop && !context.getNetwork().hasArea()) { + context.getParameters().setOuterLoops(outerLoops.stream() + .filter(ol -> !(ol instanceof DcAreaInterchangeControlOuterLoop)) + .toList()); return true; } return false; diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java index c275c07d0b..a9b31dc86f 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java @@ -25,8 +25,6 @@ public class DcLoadFlowParameters extends AbstractLoadFlowParameters O extends OuterLoopContext> implements ActivePowerDistributionOuterLoop { - boolean active = true; - - @Override - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - } - @Override public double getDistributedActivePower(O context) { var contextData = context.getData(); diff --git a/src/main/java/com/powsybl/openloadflow/lf/outerloop/OuterLoop.java b/src/main/java/com/powsybl/openloadflow/lf/outerloop/OuterLoop.java index 7d8d120644..6e8281b825 100644 --- a/src/main/java/com/powsybl/openloadflow/lf/outerloop/OuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/lf/outerloop/OuterLoop.java @@ -34,8 +34,4 @@ default void initialize(O context) { default void cleanup(O context) { } - - default boolean isActive() { - return true; - } } diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java index 60a11900af..326c6bbaf6 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java @@ -23,8 +23,6 @@ import com.powsybl.loadflow.LoadFlowParameters; import com.powsybl.loadflow.LoadFlowResult; import com.powsybl.math.matrix.DenseMatrixFactory; -import com.powsybl.openloadflow.ac.outerloop.AcAreaInterchangeControlOuterLoop; -import com.powsybl.openloadflow.ac.outerloop.DistributedSlackOuterLoop; import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory; import com.powsybl.openloadflow.lf.outerloop.OuterLoop; import com.powsybl.openloadflow.network.*; @@ -435,20 +433,13 @@ void testSlackDistributionOuterLoops() { assertEquals(List.of("DistributedSlack", "VoltageMonitoring", "ReactiveLimits"), OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); parametersExt.setAreaInterchangeControl(true); - var outerLoops = OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt); - assertEquals(List.of("DistributedSlack", "AreaInterchangeControl", "VoltageMonitoring", "ReactiveLimits"), outerLoops.stream().map(OuterLoop::getType).toList()); - assertTrue(outerLoops.stream().anyMatch(ol -> ol instanceof AcAreaInterchangeControlOuterLoop && ol.isActive())); - assertFalse(outerLoops.stream().anyMatch(ol -> ol instanceof DistributedSlackOuterLoop && ol.isActive())); + assertEquals(List.of("AreaInterchangeControl", "VoltageMonitoring", "ReactiveLimits"), OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); parametersExt.setOuterLoopNames(List.of("DistributedSlack", "AreaInterchangeControl")); - outerLoops = OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt); - assertEquals(List.of("DistributedSlack", "AreaInterchangeControl"), outerLoops.stream().map(OuterLoop::getType).toList()); - assertTrue(outerLoops.stream().anyMatch(ol -> ol instanceof AcAreaInterchangeControlOuterLoop && ol.isActive())); - assertFalse(outerLoops.stream().anyMatch(ol -> ol instanceof DistributedSlackOuterLoop && ol.isActive())); + assertEquals(List.of("AreaInterchangeControl"), OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); parametersExt.setOuterLoopNames(List.of("DistributedSlack")); assertEquals(List.of("DistributedSlack"), OpenLoadFlowParameters.createAcOuterLoops(parameters, parametersExt).stream().map(OuterLoop::getType).toList()); - } @Test From 3ffc89a6655375f8adc15577aad0c4543e6c18a7 Mon Sep 17 00:00:00 2001 From: vmouradian Date: Fri, 6 Dec 2024 15:16:18 +0100 Subject: [PATCH 3/6] clean Signed-off-by: vmouradian --- .../java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java index a9b31dc86f..9320521cf8 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowParameters.java @@ -28,6 +28,7 @@ public class DcLoadFlowParameters extends AbstractLoadFlowParameters outerLoops = Collections.emptyList(); private int maxOuterLoopIterations = DEFAULT_MAX_OUTER_LOOP_ITERATIONS; From 1a417ae3bd4b81b50a9f5e9925732a6c4f0a8f5c Mon Sep 17 00:00:00 2001 From: vmouradian Date: Wed, 18 Dec 2024 16:05:53 +0100 Subject: [PATCH 4/6] change DC slack distribution usage conditions Signed-off-by: vmouradian --- .../openloadflow/dc/DcLoadFlowEngine.java | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java index 47ecd57229..ace913cd7c 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java @@ -185,7 +185,7 @@ public DcLoadFlowResult run() { RunningContext runningContext = new RunningContext(); List outerLoops = parameters.getOuterLoops(); - boolean distributedSlack = parameters.isDistributedSlack() || areaInterchangeControlFallback(); + boolean distributedSlack = isDistributedSlack(); List activeOuterLoops = outerLoops.stream() .toList(); @@ -209,16 +209,9 @@ public DcLoadFlowResult run() { boolean useActiveLimits = parameters.getNetworkParameters().isUseActiveLimits(); ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(balanceType, false, useActiveLimits); var result = activePowerDistribution.run(network, initialSlackBusActivePowerMismatch); - final LfGenerator referenceGenerator; - final OpenLoadFlowParameters.SlackDistributionFailureBehavior behavior; - if (parameters.isAreaInterchangeControl()) { - // actual behavior will be handled by the outerloop itself, just leave on slack bus here - behavior = OpenLoadFlowParameters.SlackDistributionFailureBehavior.LEAVE_ON_SLACK_BUS; - referenceGenerator = null; - } else { - behavior = parameters.getSlackDistributionFailureBehavior(); - referenceGenerator = context.getNetwork().getReferenceGenerator(); - } + final LfGenerator referenceGenerator = context.getNetwork().getReferenceGenerator(); + final OpenLoadFlowParameters.SlackDistributionFailureBehavior behavior = parameters.getSlackDistributionFailureBehavior(); + ActivePowerDistribution.ResultWithFailureBehaviorHandling resultWbh = ActivePowerDistribution.handleDistributionFailureBehavior( behavior, referenceGenerator, @@ -331,18 +324,16 @@ public static List run(T network, LfNetworkLoader netwo } /** - * If Area Interchange Control is activated but the network has no area, we remove the AIC outer loop and fall back to distributed slack + * If Area Interchange Control is activated, slack distribution is used only if the network has no Area. Otherwise, it will be entirely handled by the AIC outer loop + * If Area Interchange Control is not activated, slack distribution is used according to the parameter */ - boolean areaInterchangeControlFallback() { - List outerLoops = context.getParameters().getOuterLoops(); - boolean aicOuterLoop = outerLoops.stream().anyMatch(DcAreaInterchangeControlOuterLoop.class::isInstance); - if (aicOuterLoop && !context.getNetwork().hasArea()) { - context.getParameters().setOuterLoops(outerLoops.stream() - .filter(ol -> !(ol instanceof DcAreaInterchangeControlOuterLoop)) - .toList()); - return true; + boolean isDistributedSlack() { + boolean hasAicOuterLoop = context.getParameters().getOuterLoops().stream().anyMatch(DcAreaInterchangeControlOuterLoop.class::isInstance); + if (hasAicOuterLoop) { + return !context.getNetwork().hasArea(); + } else { + return context.getParameters().isDistributedSlack(); } - return false; } } From 5a49f85bbdc130ea49aff44feccbd59cbbfe72bd Mon Sep 17 00:00:00 2001 From: vmouradian Date: Wed, 18 Dec 2024 16:56:43 +0100 Subject: [PATCH 5/6] ensure keeping the previous behaviour Signed-off-by: vmouradian --- .../openloadflow/dc/DcLoadFlowEngine.java | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java index ace913cd7c..29d1c1ddc6 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java @@ -185,12 +185,14 @@ public DcLoadFlowResult run() { RunningContext runningContext = new RunningContext(); List outerLoops = parameters.getOuterLoops(); - boolean distributedSlack = isDistributedSlack(); + // remove area interchange control outer loop if no area in the network, active power will be distributed with classical slack distribution + boolean areaInterchangeControl = outerLoops.stream().anyMatch(DcAreaInterchangeControlOuterLoop.class::isInstance); + if (!network.hasArea()) { + outerLoops.removeIf(DcAreaInterchangeControlOuterLoop.class::isInstance); + } - List activeOuterLoops = outerLoops.stream() - .toList(); - List> outerLoopsAndContexts = activeOuterLoops.stream() - .map(outerLoop -> Pair.of(outerLoop, new DcOuterLoopContext(context.getNetwork()))) + List> outerLoopsAndContexts = outerLoops.stream() + .map(outerLoop -> Pair.of(outerLoop, new DcOuterLoopContext(network))) .toList(); // outer loops initialization @@ -204,14 +206,21 @@ public DcLoadFlowResult run() { double initialSlackBusActivePowerMismatch = getActivePowerMismatch(network.getBuses()); double distributedActivePower = 0.0; - if (distributedSlack) { + if (parameters.isDistributedSlack() || areaInterchangeControl) { LoadFlowParameters.BalanceType balanceType = parameters.getBalanceType(); boolean useActiveLimits = parameters.getNetworkParameters().isUseActiveLimits(); ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(balanceType, false, useActiveLimits); var result = activePowerDistribution.run(network, initialSlackBusActivePowerMismatch); - final LfGenerator referenceGenerator = context.getNetwork().getReferenceGenerator(); - final OpenLoadFlowParameters.SlackDistributionFailureBehavior behavior = parameters.getSlackDistributionFailureBehavior(); - + final LfGenerator referenceGenerator; + final OpenLoadFlowParameters.SlackDistributionFailureBehavior behavior; + if (areaInterchangeControl) { + // actual behavior will be handled by the outerloop itself, just leave on slack bus here + behavior = OpenLoadFlowParameters.SlackDistributionFailureBehavior.LEAVE_ON_SLACK_BUS; + referenceGenerator = null; + } else { + behavior = parameters.getSlackDistributionFailureBehavior(); + referenceGenerator = context.getNetwork().getReferenceGenerator(); + } ActivePowerDistribution.ResultWithFailureBehaviorHandling resultWbh = ActivePowerDistribution.handleDistributionFailureBehavior( behavior, referenceGenerator, @@ -323,17 +332,4 @@ public static List run(T network, LfNetworkLoader netwo .toList(); } - /** - * If Area Interchange Control is activated, slack distribution is used only if the network has no Area. Otherwise, it will be entirely handled by the AIC outer loop - * If Area Interchange Control is not activated, slack distribution is used according to the parameter - */ - boolean isDistributedSlack() { - boolean hasAicOuterLoop = context.getParameters().getOuterLoops().stream().anyMatch(DcAreaInterchangeControlOuterLoop.class::isInstance); - if (hasAicOuterLoop) { - return !context.getNetwork().hasArea(); - } else { - return context.getParameters().isDistributedSlack(); - } - } - } From 929a5b85adca901e5823c81ae5eaffb28280f374 Mon Sep 17 00:00:00 2001 From: vmouradian Date: Mon, 6 Jan 2025 17:34:19 +0100 Subject: [PATCH 6/6] clean Signed-off-by: vmouradian --- .../lf/outerloop/AbstractAreaInterchangeControlOuterLoop.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAreaInterchangeControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAreaInterchangeControlOuterLoop.java index fd0a479ee2..1615f00946 100644 --- a/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAreaInterchangeControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/lf/outerloop/AbstractAreaInterchangeControlOuterLoop.java @@ -41,8 +41,7 @@ public abstract class AbstractAreaInterchangeControlOuterLoop< P extends AbstractLoadFlowParameters

, C extends LoadFlowContext, O extends AbstractOuterLoopContext> - extends AbstractActivePowerDistributionOuterLoop - implements ActivePowerDistributionOuterLoop { + extends AbstractActivePowerDistributionOuterLoop { private final Logger logger;