diff --git a/src/main/java/com/powsybl/openloadflow/AcLoadFlowFromCache.java b/src/main/java/com/powsybl/openloadflow/AcLoadFlowFromCache.java index 175174aa95..db4922c4bf 100644 --- a/src/main/java/com/powsybl/openloadflow/AcLoadFlowFromCache.java +++ b/src/main/java/com/powsybl/openloadflow/AcLoadFlowFromCache.java @@ -24,6 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -120,7 +121,10 @@ private static AcLoadFlowResult run(AcLoadFlowContext context) { context.setNetworkUpdated(false); return result; } - return new AcLoadFlowResult(context.getNetwork(), 0, 0, AcSolverStatus.CONVERGED, OuterLoopResult.stable(), 0d, 0d); + return new AcLoadFlowResult(context.getNetwork(), 0, + 0, AcSolverStatus.CONVERGED, OuterLoopResult.stable(), + 0d, 0d, + Collections.EMPTY_MAP); } public List run() { diff --git a/src/main/java/com/powsybl/openloadflow/ac/AcLoadFlowContext.java b/src/main/java/com/powsybl/openloadflow/ac/AcLoadFlowContext.java index f5ce66745f..daab4d50ee 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/AcLoadFlowContext.java +++ b/src/main/java/com/powsybl/openloadflow/ac/AcLoadFlowContext.java @@ -8,6 +8,7 @@ package com.powsybl.openloadflow.ac; import com.powsybl.openloadflow.ac.equations.asym.AsymmetricalAcEquationSystemCreator; +import com.powsybl.openloadflow.ac.outerloop.AcOuterLoop; import com.powsybl.openloadflow.equations.JacobianMatrix; import com.powsybl.openloadflow.lf.AbstractLoadFlowContext; import com.powsybl.openloadflow.ac.equations.AcEquationSystemCreator; @@ -18,6 +19,9 @@ import com.powsybl.openloadflow.equations.TargetVector; import com.powsybl.openloadflow.network.LfNetwork; +import java.util.HashMap; +import java.util.Map; + /** * @author Geoffroy Jamgotchian {@literal } */ @@ -31,6 +35,8 @@ public class AcLoadFlowContext extends AbstractLoadFlowContext, Object> outerLoopInitData = new HashMap<>(); + public AcLoadFlowContext(LfNetwork network, AcLoadFlowParameters parameters) { super(network, parameters); } @@ -84,6 +90,14 @@ public void setNetworkUpdated(boolean networkUpdated) { this.networkUpdated = networkUpdated; } + public Object getOuterLoopInitData(Class outerLoopClass) { + return outerLoopInitData.get(outerLoopClass); + } + + public void setOuterLoopInitData(Map, Object> outerLoopInitData) { + this.outerLoopInitData = outerLoopInitData; + } + @Override public void close() { super.close(); diff --git a/src/main/java/com/powsybl/openloadflow/ac/AcLoadFlowResult.java b/src/main/java/com/powsybl/openloadflow/ac/AcLoadFlowResult.java index 370839c919..4b8bac7be3 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/AcLoadFlowResult.java +++ b/src/main/java/com/powsybl/openloadflow/ac/AcLoadFlowResult.java @@ -8,6 +8,7 @@ package com.powsybl.openloadflow.ac; import com.powsybl.loadflow.LoadFlowResult; +import com.powsybl.openloadflow.ac.outerloop.AcOuterLoop; import com.powsybl.openloadflow.ac.solver.AcSolverStatus; import com.powsybl.openloadflow.lf.AbstractLoadFlowResult; import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult; @@ -15,6 +16,8 @@ import com.powsybl.openloadflow.network.LfNetwork; import com.powsybl.openloadflow.util.PerUnit; +import java.util.Collections; +import java.util.Map; import java.util.Objects; /** @@ -23,19 +26,24 @@ public class AcLoadFlowResult extends AbstractLoadFlowResult { public static AcLoadFlowResult createNoCalculationResult(LfNetwork network) { - return new AcLoadFlowResult(network, 0, 0, AcSolverStatus.NO_CALCULATION, OuterLoopResult.stable(), Double.NaN, Double.NaN); + return new AcLoadFlowResult(network, 0, 0, AcSolverStatus.NO_CALCULATION, OuterLoopResult.stable(), Double.NaN, Double.NaN, + Collections.EMPTY_MAP); } private final int solverIterations; private final AcSolverStatus solverStatus; + private final Map, Object> outerLoopInitData; + public AcLoadFlowResult(LfNetwork network, int outerLoopIterations, int solverIterations, AcSolverStatus solverStatus, OuterLoopResult outerLoopResult, - double slackBusActivePowerMismatch, double distributedActivePower) { + double slackBusActivePowerMismatch, double distributedActivePower, + Map, Object> outerLoopInitData) { super(network, slackBusActivePowerMismatch, outerLoopIterations, outerLoopResult, distributedActivePower); this.solverIterations = solverIterations; this.solverStatus = Objects.requireNonNull(solverStatus); + this.outerLoopInitData = outerLoopInitData; } public int getSolverIterations() { @@ -79,6 +87,10 @@ public Status toComponentResultStatus() { } } + public Map, Object> getOuterLoopInitData() { + return outerLoopInitData; + } + @Override public String toString() { return "AcLoadFlowResult(outerLoopIterations=" + outerLoopIterations diff --git a/src/main/java/com/powsybl/openloadflow/ac/AcOuterLoopContext.java b/src/main/java/com/powsybl/openloadflow/ac/AcOuterLoopContext.java index 2af20334a5..0b1936845c 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/AcOuterLoopContext.java +++ b/src/main/java/com/powsybl/openloadflow/ac/AcOuterLoopContext.java @@ -13,15 +13,23 @@ import com.powsybl.openloadflow.lf.outerloop.AbstractOuterLoopContext; import com.powsybl.openloadflow.network.LfNetwork; +import java.util.Optional; + /** * @author Geoffroy Jamgotchian {@literal } */ public class AcOuterLoopContext extends AbstractOuterLoopContext { private AcSolverResult lastSolverResult; + private Object outerLoopInitData; - AcOuterLoopContext(LfNetwork network) { + AcOuterLoopContext(LfNetwork network, Object dataForRunFromPreviousValues) { super(network); + this.outerLoopInitData = dataForRunFromPreviousValues; + } + + public Optional getOuterLoopInitData() { + return Optional.ofNullable(outerLoopInitData); } public AcSolverResult getLastSolverResult() { diff --git a/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java index 2afcd6f13b..159cee3f82 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java @@ -26,6 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -138,7 +139,7 @@ public AcLoadFlowResult run() { LOGGER.info("Network must have at least one bus with generator voltage control enabled"); Reports.reportNetworkMustHaveAtLeastOneBusGeneratorVoltageControlEnabled(reportNode); runningContext.lastSolverResult = new AcSolverResult(AcSolverStatus.SOLVER_FAILED, 0, Double.NaN); - return buildAcLoadFlowResult(runningContext, OuterLoopResult.stable(), distributedActivePower); + return buildAcLoadFlowResult(runningContext, OuterLoopResult.stable(), distributedActivePower, Collections.EMPTY_LIST); } AcSolver solver = solverFactory.create(context.getNetwork(), @@ -150,7 +151,7 @@ public AcLoadFlowResult run() { List outerLoops = context.getParameters().getOuterLoops(); List> outerLoopsAndContexts = outerLoops.stream() - .map(outerLoop -> Pair.of(outerLoop, new AcOuterLoopContext(context.getNetwork()))) + .map(outerLoop -> Pair.of(outerLoop, new AcOuterLoopContext(context.getNetwork(), context.getOuterLoopInitData(outerLoop.getClass())))) .toList(); // outer loops initialization @@ -218,17 +219,25 @@ public AcLoadFlowResult run() { new OuterLoopResult(runningContext.lastOuterLoopResult.outerLoopName(), OuterLoopStatus.UNSTABLE, runningContext.lastOuterLoopResult.statusText()); } - return buildAcLoadFlowResult(runningContext, outerLoopFinalResult, distributedActivePower); + return buildAcLoadFlowResult(runningContext, outerLoopFinalResult, distributedActivePower, outerLoopsAndContexts); } - private AcLoadFlowResult buildAcLoadFlowResult(RunningContext runningContext, OuterLoopResult outerLoopFinalResult, double distributedActivePower) { + private AcLoadFlowResult buildAcLoadFlowResult(RunningContext runningContext, + OuterLoopResult outerLoopFinalResult, + double distributedActivePower, + List> outerLoopsAndContexts) { + + Map, Object> outerLoopInitData = new HashMap<>(); + outerLoopsAndContexts.forEach(p -> p.getLeft().getInitData(p.getRight()).ifPresent(d -> outerLoopInitData.put(p.getLeft().getClass(), d))); + AcLoadFlowResult result = new AcLoadFlowResult(context.getNetwork(), runningContext.outerLoopTotalIterations, runningContext.nrTotalIterations.getValue(), runningContext.lastSolverResult.getStatus(), outerLoopFinalResult, runningContext.lastSolverResult.getSlackBusActivePowerMismatch(), - distributedActivePower + distributedActivePower, + outerLoopInitData ); LOGGER.info("AC loadflow complete on network {} (result={})", context.getNetwork(), result); diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcOuterLoop.java index 72be221001..3ff07e97c2 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/AcOuterLoop.java @@ -14,8 +14,17 @@ import com.powsybl.openloadflow.ac.equations.AcVariableType; import com.powsybl.openloadflow.lf.outerloop.OuterLoop; +import java.util.Optional; + /** * @author Geoffroy Jamgotchian {@literal } */ public interface AcOuterLoop extends OuterLoop { + + /** + * Returns data needed to initialize the outerloop for a rerun from previous values. + */ + default Optional getInitData(AcOuterLoopContext context) { + return Optional.empty(); + } } diff --git a/src/main/java/com/powsybl/openloadflow/ac/outerloop/ReactiveLimitsOuterLoop.java b/src/main/java/com/powsybl/openloadflow/ac/outerloop/ReactiveLimitsOuterLoop.java index becf192405..484de296d8 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/outerloop/ReactiveLimitsOuterLoop.java +++ b/src/main/java/com/powsybl/openloadflow/ac/outerloop/ReactiveLimitsOuterLoop.java @@ -56,6 +56,14 @@ private static final class ContextData { private final Map pvPqSwitchCount = new HashMap<>(); + public ContextData(Optional initData) { + initData.ifPresent(d -> { + if (d instanceof Map map) { + pvPqSwitchCount.putAll(map); + } + }); + } + void incrementPvPqSwitchCount(String busId) { pvPqSwitchCount.computeIfAbsent(busId, k -> new MutableInt(0)) .increment(); @@ -163,7 +171,7 @@ private boolean switchPvPq(List pvToPqBuses, int remaining @Override public void initialize(AcOuterLoopContext context) { - context.setData(new ContextData()); + context.setData(new ContextData(context.getOuterLoopInitData())); } private static boolean switchPqPv(List pqToPvBuses, ContextData contextData, ReportNode reportNode, int maxPqPvSwitch) { @@ -349,4 +357,9 @@ public OuterLoopResult check(AcOuterLoopContext context, ReportNode reportNode) } return new OuterLoopResult(this, status); } + + @Override + public Optional getInitData(AcOuterLoopContext context) { + return Optional.of(Collections.unmodifiableMap(((ContextData) context.getData()).pvPqSwitchCount)); + } } diff --git a/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java index 57d634ffc2..eb48186908 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java @@ -616,6 +616,8 @@ protected static void distributedMismatch(LfNetwork network, double mismatch, Lo protected abstract LoadFlowEngine createLoadFlowEngine(C context); + protected abstract void updateContext(R result, C context); + protected void afterPreContingencySimulation(P acParameters) { } @@ -649,6 +651,7 @@ protected SecurityAnalysisResult runSimulations(LfNetwork lfNetwork, List contingencies, try (AcLoadFlowContext context = new AcLoadFlowContext(lfNetwork, acParameters)) { - runLoadFlow(context, true); + runLoadFlow(context, true, true); // index factors by variable group to compute a minimal number of states SensitivityFactorGroupList factorGroups = createFactorGroups(validLfFactors.stream() diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index 07a08ee6b8..a5bb2806cc 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -1818,7 +1818,9 @@ void testStatusConversion() { private AcLoadFlowResult buildTestAcLoadFlowResult(AcSolverStatus solverStatus, OuterLoopStatus outerLoopStatus) { LfNetwork lfNetwork = Mockito.mock(LfNetwork.class); - return new AcLoadFlowResult(lfNetwork, 0, 0, solverStatus, new OuterLoopResult("", outerLoopStatus), 0d, 0d); + return new AcLoadFlowResult(lfNetwork, 0, 0, + solverStatus, new OuterLoopResult("", outerLoopStatus), + 0d, 0d, Collections.EMPTY_MAP); } @Test