From 2af86c2a30af9b1719a8525ec20d7fb9ad827d2c Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Wed, 4 May 2022 20:46:31 +0200 Subject: [PATCH] Outer loops persistent context (#530) Signed-off-by: Geoffroy Jamgotchian --- ...actTransformerVoltageControlOuterLoop.java | 5 +- .../ac/PhaseControlOuterLoop.java | 7 ++- .../ac/ReactiveLimitsOuterLoop.java | 7 +-- .../ac/ShuntVoltageControlOuterLoop.java | 5 +- .../TransformerVoltageControlOuterLoop.java | 23 +++++-- .../ac/outerloop/AcloadFlowEngine.java | 31 ++++++--- .../openloadflow/ac/outerloop/OuterLoop.java | 5 +- .../ac/outerloop/OuterLoopContext.java | 28 ++------- .../ac/outerloop/OuterLoopContextImpl.java | 63 +++++++++++++++++++ 9 files changed, 122 insertions(+), 52 deletions(-) create mode 100644 src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContextImpl.java diff --git a/src/main/java/com/powsybl/openloadflow/ac/AbstractTransformerVoltageControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/AbstractTransformerVoltageControlOuterLoop.java index b3faa273ba..942b98d98c 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/AbstractTransformerVoltageControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/AbstractTransformerVoltageControlOuterLoop.java @@ -7,6 +7,7 @@ package com.powsybl.openloadflow.ac; import com.powsybl.openloadflow.ac.outerloop.OuterLoop; +import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext; import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus; import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.LfNetwork; @@ -43,8 +44,8 @@ protected OuterLoopStatus roundVoltageRatios(LfNetwork network) { } @Override - public void cleanup(LfNetwork network) { - for (LfBranch branch : network.getBranches()) { + public void cleanup(OuterLoopContext context) { + for (LfBranch branch : context.getNetwork().getBranches()) { branch.getVoltageControl().ifPresent(voltageControl -> branch.setVoltageControlEnabled(true)); } } diff --git a/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java index f661b36ecc..9ddfad9926 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/PhaseControlOuterLoop.java @@ -38,9 +38,10 @@ public String getType() { } @Override - public void initialize(LfNetwork network) { + public void initialize(OuterLoopContext context) { List controllerBranches = new ArrayList<>(1); List disabledBranches = new ArrayList<>(1); + LfNetwork network = context.getNetwork(); for (LfBranch branch : network.getBranches()) { if (!branch.isDisabled() && branch.isPhaseController() && branch.isPhaseControlEnabled()) { controllerBranches.add(branch); @@ -163,8 +164,8 @@ boolean isSensitivityCurrentPerA1Positive(LfBranch controllerBranch, DiscretePha } @Override - public void cleanup(LfNetwork network) { - for (LfBranch branch : network.getBranches()) { + public void cleanup(OuterLoopContext context) { + for (LfBranch branch : context.getNetwork().getBranches()) { if (branch.isPhaseController()) { branch.setPhaseControlEnabled(true); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/ReactiveLimitsOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/ReactiveLimitsOuterLoop.java index a1200d8e47..9e9f637ff2 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/ReactiveLimitsOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/ReactiveLimitsOuterLoop.java @@ -13,9 +13,8 @@ import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext; import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus; import com.powsybl.openloadflow.network.LfBus; -import com.powsybl.openloadflow.network.LfNetwork; -import com.powsybl.openloadflow.util.PerUnit; import com.powsybl.openloadflow.network.VoltageControl; +import com.powsybl.openloadflow.util.PerUnit; import org.apache.commons.lang3.mutable.MutableInt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -240,8 +239,8 @@ public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) { } @Override - public void cleanup(LfNetwork network) { - for (LfBus bus : network.getBuses()) { + public void cleanup(OuterLoopContext context) { + for (LfBus bus : context.getNetwork().getBuses()) { bus.setVoltageControlSwitchOffCount(0); } } diff --git a/src/main/java/com/powsybl/openloadflow/ac/ShuntVoltageControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/ShuntVoltageControlOuterLoop.java index c0b680e457..bddc80893c 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/ShuntVoltageControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/ShuntVoltageControlOuterLoop.java @@ -11,7 +11,6 @@ import com.powsybl.openloadflow.ac.outerloop.OuterLoopContext; import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus; import com.powsybl.openloadflow.network.LfBus; -import com.powsybl.openloadflow.network.LfNetwork; import com.powsybl.openloadflow.network.LfShunt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,8 +50,8 @@ public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) { } @Override - public void cleanup(LfNetwork network) { - for (LfBus bus : network.getBuses()) { + public void cleanup(OuterLoopContext context) { + for (LfBus bus : context.getNetwork().getBuses()) { bus.getShuntVoltageControl().ifPresent(b -> b.getControllers().forEach(controllerShunt -> controllerShunt.setVoltageControlEnabled(true))); } } diff --git a/src/main/java/com/powsybl/openloadflow/ac/TransformerVoltageControlOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/TransformerVoltageControlOuterLoop.java index 481a1bda37..24315a12bb 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/TransformerVoltageControlOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/TransformerVoltageControlOuterLoop.java @@ -11,7 +11,6 @@ import com.powsybl.openloadflow.ac.outerloop.OuterLoopStatus; import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.LfBus; -import com.powsybl.openloadflow.network.LfNetwork; import com.powsybl.openloadflow.network.TransformerVoltageControl; /** @@ -19,20 +18,32 @@ */ public class TransformerVoltageControlOuterLoop extends AbstractTransformerVoltageControlOuterLoop { - public static final String MAX_CONTROLLED_NOMINAL_VOLTAGE = "maxControlledNominalVoltage"; + private static final class ContextData { + + private final double maxControlledNominalVoltage; + + private ContextData(double maxControlledNominalVoltage) { + this.maxControlledNominalVoltage = maxControlledNominalVoltage; + } + + private double getMaxControlledNominalVoltage() { + return maxControlledNominalVoltage; + } + } @Override - public void initialize(LfNetwork network) { + public void initialize(OuterLoopContext context) { // All transformer voltage control are disabled for the first equation system resolution. double[] maxControlledNominalVoltage = new double[1]; maxControlledNominalVoltage[0] = Double.MIN_VALUE; - for (LfBranch branch : network.getBranches()) { + for (LfBranch branch : context.getNetwork().getBranches()) { branch.getVoltageControl().ifPresent(voltageControl -> { branch.setVoltageControlEnabled(false); maxControlledNominalVoltage[0] = Math.max(maxControlledNominalVoltage[0], voltageControl.getControlled().getNominalV()); }); } - network.setProperty(MAX_CONTROLLED_NOMINAL_VOLTAGE, maxControlledNominalVoltage[0]); + + context.setData(new ContextData(maxControlledNominalVoltage[0])); } @Override @@ -44,7 +55,7 @@ public String getType() { public OuterLoopStatus check(OuterLoopContext context, Reporter reporter) { OuterLoopStatus status = OuterLoopStatus.STABLE; - double maxControlledNominalVoltage = (Double) context.getNetwork().getProperty(MAX_CONTROLLED_NOMINAL_VOLTAGE); + double maxControlledNominalVoltage = ((ContextData) context.getData()).getMaxControlledNominalVoltage(); // At first outer loop iteration, the voltage control of generators that controlled at nominal voltage of // the set controlledNominalVoltages are disabled. diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java index 64fd795349..4caf2d7a80 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcloadFlowEngine.java @@ -6,6 +6,7 @@ */ package com.powsybl.openloadflow.ac.outerloop; +import com.google.common.collect.Lists; import com.powsybl.commons.reporter.Reporter; import com.powsybl.openloadflow.ac.nr.NewtonRaphson; import com.powsybl.openloadflow.ac.nr.NewtonRaphsonResult; @@ -15,6 +16,7 @@ import com.powsybl.openloadflow.network.util.PreviousValueVoltageInitializer; import com.powsybl.openloadflow.network.util.VoltageInitializer; import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,7 +50,7 @@ private static class RunningContext { private final Map outerLoopIterationByType = new HashMap<>(); } - private void runOuterLoop(OuterLoop outerLoop, LfNetwork network, NewtonRaphson newtonRaphson, RunningContext runningContext, + private void runOuterLoop(OuterLoop outerLoop, OuterLoopContextImpl outerLoopContext, NewtonRaphson newtonRaphson, RunningContext runningContext, Reporter reporter) { Reporter olReporter = reporter.createSubReporter("OuterLoop", "Outer loop ${outerLoopType}", "outerLoopType", outerLoop.getType()); @@ -58,7 +60,9 @@ private void runOuterLoop(OuterLoop outerLoop, LfNetwork network, NewtonRaphson MutableInt outerLoopIteration = runningContext.outerLoopIterationByType.computeIfAbsent(outerLoop.getType(), k -> new MutableInt()); // check outer loop status - outerLoopStatus = outerLoop.check(new OuterLoopContext(outerLoopIteration.getValue(), network, runningContext.lastNrResult), olReporter); + outerLoopContext.setIteration(outerLoopIteration.getValue()); + outerLoopContext.setLastNewtonRaphsonResult(runningContext.lastNrResult); + outerLoopStatus = outerLoop.check(outerLoopContext, olReporter); if (outerLoopStatus == OuterLoopStatus.UNSTABLE) { LOGGER.debug("Start outer loop iteration {} (name='{}')", outerLoopIteration, outerLoop.getType()); @@ -91,9 +95,16 @@ public AcLoadFlowResult run(Reporter reporter) { NewtonRaphson newtonRaphson = new NewtonRaphson(context.getNetwork(), context.getParameters().getNewtonRaphsonParameters(), context.getEquationSystem(), context.getJacobianMatrix(), context.getTargetVector()); + List outerLoops = context.getParameters().getOuterLoops(); + List> outerLoopsAndContexts = outerLoops.stream() + .map(outerLoop -> Pair.of(outerLoop, new OuterLoopContextImpl(context.getNetwork()))) + .collect(Collectors.toList()); + // outer loops initialization - for (OuterLoop outerLoop : context.getParameters().getOuterLoops()) { - outerLoop.initialize(context.getNetwork()); + for (var outerLoopAndContext : outerLoopsAndContexts) { + var outerLoop = outerLoopAndContext.getLeft(); + var outerLoopContext = outerLoopAndContext.getRight(); + outerLoop.initialize(outerLoopContext); } // run initial Newton-Raphson @@ -108,8 +119,8 @@ public AcLoadFlowResult run(Reporter reporter) { oldIterationCount = runningContext.lastNrResult.getIteration(); // outer loops are nested: inner most loop first in the list, outer most loop last - for (OuterLoop outerLoop : context.getParameters().getOuterLoops()) { - runOuterLoop(outerLoop, context.getNetwork(), newtonRaphson, runningContext, reporter); + for (var outerLoopAndContext : outerLoopsAndContexts) { + runOuterLoop(outerLoopAndContext.getLeft(), outerLoopAndContext.getRight(), newtonRaphson, runningContext, reporter); // continue with next outer loop only if last Newton-Raphson succeed if (runningContext.lastNrResult.getStatus() != NewtonRaphsonStatus.CONVERGED) { @@ -120,9 +131,11 @@ public AcLoadFlowResult run(Reporter reporter) { && runningContext.lastNrResult.getStatus() == NewtonRaphsonStatus.CONVERGED); } - // outer loops finalization - for (OuterLoop outerLoop : context.getParameters().getOuterLoops()) { - outerLoop.cleanup(context.getNetwork()); + // outer loops finalization (in reverse order to allow correct cleanup) + for (var outerLoopAndContext : Lists.reverse(outerLoopsAndContexts)) { + var outerLoop = outerLoopAndContext.getLeft(); + var outerLoopContext = outerLoopAndContext.getRight(); + outerLoop.cleanup(outerLoopContext); } int nrIterations = runningContext.lastNrResult.getIteration(); diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoop.java index 0b6c5bf3aa..2d6e7b1bf0 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoop.java @@ -7,7 +7,6 @@ package com.powsybl.openloadflow.ac.outerloop; import com.powsybl.commons.reporter.Reporter; -import com.powsybl.openloadflow.network.LfNetwork; /** * @author Geoffroy Jamgotchian @@ -16,11 +15,11 @@ public interface OuterLoop { String getType(); - default void initialize(LfNetwork network) { + default void initialize(OuterLoopContext context) { } OuterLoopStatus check(OuterLoopContext context, Reporter reporter); - default void cleanup(LfNetwork network) { + default void cleanup(OuterLoopContext context) { } } diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContext.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContext.java index a70f77b2a6..edc3fc9bae 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContext.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContext.java @@ -9,34 +9,18 @@ import com.powsybl.openloadflow.ac.nr.NewtonRaphsonResult; import com.powsybl.openloadflow.network.LfNetwork; -import java.util.Objects; - /** * @author Geoffroy Jamgotchian */ -public class OuterLoopContext { - - private final int iteration; - - private final LfNetwork network; +public interface OuterLoopContext { - private final NewtonRaphsonResult lastNewtonRaphsonResult; + LfNetwork getNetwork(); - OuterLoopContext(int iteration, LfNetwork network, NewtonRaphsonResult lastNewtonRaphsonResult) { - this.iteration = iteration; - this.network = Objects.requireNonNull(network); - this.lastNewtonRaphsonResult = Objects.requireNonNull(lastNewtonRaphsonResult); - } + int getIteration(); - public int getIteration() { - return iteration; - } + NewtonRaphsonResult getLastNewtonRaphsonResult(); - public LfNetwork getNetwork() { - return network; - } + Object getData(); - public NewtonRaphsonResult getLastNewtonRaphsonResult() { - return lastNewtonRaphsonResult; - } + void setData(Object data); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContextImpl.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContextImpl.java new file mode 100644 index 0000000000..3cf6c3465b --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/OuterLoopContextImpl.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2022, RTE (http://www.rte-france.com) + * 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/. + */ +package com.powsybl.openloadflow.ac.outerloop; + +import com.powsybl.openloadflow.ac.nr.NewtonRaphsonResult; +import com.powsybl.openloadflow.network.LfNetwork; + +import java.util.Objects; + +/** + * @author Geoffroy Jamgotchian + */ +public class OuterLoopContextImpl implements OuterLoopContext { + + private final LfNetwork network; + + private int iteration; + + private NewtonRaphsonResult lastNewtonRaphsonResult; + + private Object data; + + OuterLoopContextImpl(LfNetwork network) { + this.network = Objects.requireNonNull(network); + } + + @Override + public LfNetwork getNetwork() { + return network; + } + + @Override + public int getIteration() { + return iteration; + } + + public void setIteration(int iteration) { + this.iteration = iteration; + } + + @Override + public NewtonRaphsonResult getLastNewtonRaphsonResult() { + return lastNewtonRaphsonResult; + } + + public void setLastNewtonRaphsonResult(NewtonRaphsonResult lastNewtonRaphsonResult) { + this.lastNewtonRaphsonResult = lastNewtonRaphsonResult; + } + + @Override + public Object getData() { + return data; + } + + @Override + public void setData(Object data) { + this.data = data; + } +}