From c1fe59e529a1baf42b88fe37f109e6472de74991 Mon Sep 17 00:00:00 2001 From: Thomas Bouquet Date: Wed, 11 Mar 2026 17:19:29 +0100 Subject: [PATCH 1/7] prepare regulation module Signed-off-by: Thomas Bouquet --- pom.xml | 1 + pst-regulation/pom.xml | 43 +++ .../ElementaryPstRegulationInput.java | 106 +++++++ .../openrao/pstregulation/PstRegulation.java | 258 ++++++++++++++++++ .../pstregulation/PstRegulationInput.java | 19 ++ .../pstregulation/PstRegulationOutput.java | 14 + .../pstregulation/PstRegulationResult.java | 19 ++ .../openrao/pstregulation/PstRegulator.java | 79 ++++++ 8 files changed, 539 insertions(+) create mode 100644 pst-regulation/pom.xml create mode 100644 pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/ElementaryPstRegulationInput.java create mode 100644 pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java create mode 100644 pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationInput.java create mode 100644 pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationOutput.java create mode 100644 pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationResult.java create mode 100644 pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulator.java diff --git a/pom.xml b/pom.xml index deb21f4385..17d448f6b5 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,7 @@ data distribution loopflow-computation + pst-regulation ra-optimisation sensitivity-analysis util diff --git a/pst-regulation/pom.xml b/pst-regulation/pom.xml new file mode 100644 index 0000000000..f5ddfa3fc7 --- /dev/null +++ b/pst-regulation/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + com.powsybl + powsybl-open-rao + 7.2.0-SNAPSHOT + + + open-rao-pst-regulation + jar + PST Regulation + Post-RAO PST regulatoin module + + + 21 + 21 + UTF-8 + + + + com.powsybl + open-rao-rao-result-api + ${project.version} + + + com.powsybl + open-rao-rao-api + + + com.powsybl + open-rao-util + + + com.powsybl + powsybl-open-loadflow + compile + + + + \ No newline at end of file diff --git a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/ElementaryPstRegulationInput.java b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/ElementaryPstRegulationInput.java new file mode 100644 index 0000000000..389035408d --- /dev/null +++ b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/ElementaryPstRegulationInput.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2026, 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.openrao.pstregulation; + +import com.powsybl.iidm.network.Branch; +import com.powsybl.iidm.network.Network; +import com.powsybl.iidm.network.TwoSides; +import com.powsybl.iidm.network.TwoWindingsTransformer; +import com.powsybl.openrao.commons.OpenRaoException; +import com.powsybl.openrao.commons.Unit; +import com.powsybl.openrao.data.crac.api.Crac; +import com.powsybl.openrao.data.crac.api.State; +import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; +import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Helper class to store all the data required for the regulation of a PST. It contains the PST range action with the + * most limiting threshold of the FlowCNEC monitored by the PST and its associated side. The record representation + * allows a more elegant and convenient manipulation of the data to configure the PST regulation for OpenLoadFlow. + * + * @author Thomas Bouquet {@literal } + */ +public record ElementaryPstRegulationInput(PstRangeAction pstRangeAction, TwoSides limitingSide, double limitingThreshold) { + public static ElementaryPstRegulationInput of(PstRangeAction pstRangeAction, String monitoredNetworkElement, State state, Crac crac, Network network) { + Set curativeFlowCnecs = crac.getFlowCnecs(state).stream() + .filter(flowCnec -> monitoredNetworkElement.equals(flowCnec.getNetworkElement().getId())) + .collect(Collectors.toSet()); + if (curativeFlowCnecs.isEmpty()) { + return null; + } + + // if the PST monitors itself, the most limiting terminal is used for regulation + if (pstRangeAction.getNetworkElement().getId().equals(monitoredNetworkElement)) { + double thresholdOne = getMostLimitingThreshold(curativeFlowCnecs, TwoSides.ONE); + double thresholdTwo = getMostLimitingThreshold(curativeFlowCnecs, TwoSides.TWO); + return thresholdOne <= thresholdTwo ? new ElementaryPstRegulationInput(pstRangeAction, TwoSides.ONE, thresholdOne) : new ElementaryPstRegulationInput(pstRangeAction, TwoSides.TWO, thresholdTwo); + } + + // otherwise, the terminal in common with the element in series it monitors is used + Pair commonTerminalSides = getSidesOfCommonTerminal(pstRangeAction, monitoredNetworkElement, network); + return new ElementaryPstRegulationInput(pstRangeAction, commonTerminalSides.getLeft(), getMostLimitingThreshold(curativeFlowCnecs, commonTerminalSides.getRight())); + } + + private static double getMostLimitingThreshold(Set curativeFlowCnecs, TwoSides twoSides) { + return curativeFlowCnecs.stream().mapToDouble(flowCnec -> getMostLimitingThreshold(flowCnec, twoSides)).min().orElse(Double.MAX_VALUE); + } + + /** + * Retrieves the most limiting current threshold of a FlowCnec (in Amperes) on a given side. + * The returned threshold in always positive since it accounts for a line loading (sign is just for direction). + */ + private static double getMostLimitingThreshold(FlowCnec flowCnec, TwoSides twoSides) { + double mostLimitingThreshold = Double.MAX_VALUE; + + Optional upperBound = flowCnec.getUpperBound(twoSides, Unit.AMPERE); + // current threshold -> sign is used for current direction so upper bound is expected to be positive + if (upperBound.isPresent() && upperBound.get() >= 0) { + mostLimitingThreshold = upperBound.get(); + } + + Optional lowerBound = flowCnec.getLowerBound(twoSides, Unit.AMPERE); + // current threshold -> sign is used for current direction so lower bound is expected to be negative + if (lowerBound.isPresent() && lowerBound.get() <= 0) { + mostLimitingThreshold = Math.min(mostLimitingThreshold, -lowerBound.get()); + } + + return mostLimitingThreshold; + } + + /** + * If the PST monitors a line connected in series, returns a pair that contains the respective side of the terminal + * they share in common. + */ + private static Pair getSidesOfCommonTerminal(PstRangeAction pstRangeAction, String monitoredNetworkElement, Network network) { + Branch branch = network.getBranch(monitoredNetworkElement); + if (branch == null) { + throw new OpenRaoException("No branch with id '%s' found in network.".formatted(monitoredNetworkElement)); + } + + String twoWindingsTransformerId = pstRangeAction.getNetworkElement().getId(); + TwoWindingsTransformer twoWindingsTransformer = network.getTwoWindingsTransformer(twoWindingsTransformerId); + if (twoWindingsTransformer == null) { + throw new OpenRaoException("No two-windings transformer with id '%s' found in network.".formatted(twoWindingsTransformerId)); + } + + for (TwoSides twtSide : TwoSides.values()) { + for (TwoSides branchSide : TwoSides.values()) { + if (twoWindingsTransformer.getTerminal(twtSide).getVoltageLevel().getId().equals(branch.getTerminal(branchSide).getVoltageLevel().getId())) { + return Pair.of(twtSide, branchSide); + } + } + } + + throw new OpenRaoException("Two-windings transformer '%s' and branch '%s' do not share a common terminal so PST regulation cannot be performed.".formatted(twoWindingsTransformerId, monitoredNetworkElement)); + } +} diff --git a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java new file mode 100644 index 0000000000..c8754b443d --- /dev/null +++ b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2026, 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.openrao.pstregulation; + +import com.powsybl.contingency.Contingency; +import com.powsybl.iidm.network.Network; +import com.powsybl.loadflow.LoadFlowParameters; +import com.powsybl.openloadflow.OpenLoadFlowParameters; +import com.powsybl.openrao.commons.OpenRaoException; +import com.powsybl.openrao.commons.Unit; +import com.powsybl.openrao.data.crac.api.Crac; +import com.powsybl.openrao.data.crac.api.Identifiable; +import com.powsybl.openrao.data.crac.api.Instant; +import com.powsybl.openrao.data.crac.api.State; +import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; +import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; +import com.powsybl.openrao.data.raoresult.api.ComputationStatus; +import com.powsybl.openrao.data.raoresult.api.RaoResult; +import com.powsybl.openrao.raoapi.parameters.RaoParameters; +import com.powsybl.openrao.raoapi.parameters.extensions.OpenRaoSearchTreeParameters; +import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoPstRegulationParameters; +import com.powsybl.openrao.util.AbstractNetworkPool; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_LOGS; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_WARNS; +import static com.powsybl.openrao.raoapi.parameters.extensions.MultithreadingParameters.getAvailableCPUs; + +/** + * @author Thomas Bouquet {@literal } + */ +public final class PstRegulation { + private PstRegulation() { + } + + public static RaoResult regulatePsts(Network network, Crac crac, RaoResult raoResult, RaoParameters raoParameters) { + // TODO + return null; + } + + private static Set regulatePsts(Map pstsToRegulate, Network network, Crac crac, RaoParameters raoParameters, RaoResult raoResult) { + // filter out non-curative PSTs + // currently, only PSTs with a usage rule for a given state are regulated + Set rangeActionsToRegulate = getPstRangeActionsForRegulation(pstsToRegulate.keySet(), crac); + if (rangeActionsToRegulate.isEmpty()) { + return Set.of(); + } + + Set statesToRegulate = getStatesToRegulate(crac, raoResult, getFlowUnit(raoParameters), rangeActionsToRegulate, SearchTreeRaoPstRegulationParameters.getPstsToRegulate(raoParameters), network); + if (statesToRegulate.isEmpty()) { + return Set.of(); + } + + Set contingencies = statesToRegulate.stream().map(PstRegulationInput::curativeState).map(State::getContingency).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet()); + BUSINESS_LOGS.info("{} contingency scenario(s) to regulate: {}", contingencies.size(), String.join(", ", contingencies.stream().map(contingency -> contingency.getName().orElse(contingency.getId())).sorted().toList())); + BUSINESS_LOGS.info("{} PST(s) to regulate: {}", rangeActionsToRegulate.size(), String.join(", ", rangeActionsToRegulate.stream().map(PstRangeAction::getName).sorted().toList())); + + // update loadflow parameters + LoadFlowParameters loadFlowParameters = getLoadFlowParameters(raoParameters); + boolean initialPhaseShifterRegulationOnValue = loadFlowParameters.isPhaseShifterRegulationOn(); + updateLoadFlowParametersForPstRegulation(loadFlowParameters); + + // apply optimal preventive remedial actions + applyOptimalRemedialActionsForState(network, raoResult, crac.getPreventiveState()); + + // regulate PSTs for each curative scenario in parallel + try (AbstractNetworkPool networkPool = AbstractNetworkPool.create(network, network.getVariantManager().getWorkingVariantId(), getNumberOfThreads(crac, raoParameters), true)) { + List> tasks = statesToRegulate.stream().map(pstRegulationInput -> + networkPool.submit(() -> regulatePstsForContingencyScenario(pstRegulationInput, crac, rangeActionsToRegulate, raoResult, loadFlowParameters, networkPool)) + ).toList(); + Set pstRegulationResults = new HashSet<>(); + for (ForkJoinTask task : tasks) { + try { + pstRegulationResults.add(task.get()); + } catch (ExecutionException e) { + throw new OpenRaoException(e); + } + } + networkPool.shutdownAndAwaitTermination(1000, TimeUnit.SECONDS); + return pstRegulationResults; + } catch (Exception e) { + Thread.currentThread().interrupt(); + BUSINESS_WARNS.warn("An error occurred during PST regulation, pre-regulation RAO result will be kept."); + return Set.of(); + } finally { + loadFlowParameters.setPhaseShifterRegulationOn(initialPhaseShifterRegulationOnValue); + } + } + + private static Unit getFlowUnit(RaoParameters raoParameters) { + OpenRaoSearchTreeParameters searchTreeParameters = raoParameters.getExtension(OpenRaoSearchTreeParameters.class); + if (searchTreeParameters != null) { + return searchTreeParameters.getLoadFlowAndSensitivityParameters().getSensitivityWithLoadFlowParameters().getLoadFlowParameters().isDc() ? Unit.MEGAWATT : Unit.AMPERE; + } + return Unit.AMPERE; + } + + /** + * Determines the states for which PST regulation must be applied. There are two conditions: + *
    + *
  1. the state must be unsecure;
  2. + *
  3. the limiting elements must be in series with a regulated PST.
  4. + *
+ * For all such states, the associated PST regulation input is included in a set that is returned. + */ + private static Set getStatesToRegulate(Crac crac, RaoResult raoResult, Unit unit, Set rangeActionsToRegulate, Map linesInSeriesWithPst, Network network) { + Instant lastInstant = crac.getLastInstant(); + return lastInstant.isCurative() ? + crac.getStates(lastInstant).stream() + .filter(state -> raoResult.getComputationStatus(state) != ComputationStatus.FAILURE) + .map(curativeState -> getPstRegulationInput(curativeState, crac, raoResult, unit, rangeActionsToRegulate, linesInSeriesWithPst, network)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet()) + : Set.of(); + } + + private static Optional getPstRegulationInput(State curativeState, Crac crac, RaoResult raoResult, Unit unit, Set rangeActionsToRegulate, Map linesInSeriesWithPst, Network network) { + Optional limitingElement = getMostLimitingElementProtectedByPst(curativeState, crac, raoResult, unit, new HashSet<>(linesInSeriesWithPst.values())); + if (limitingElement.isPresent()) { + Set elementaryPstRegulationInputs = rangeActionsToRegulate.stream() + .filter(pstRangeAction -> linesInSeriesWithPst.containsKey(pstRangeAction.getNetworkElement().getId())) + .map(pstRangeAction -> ElementaryPstRegulationInput.of(pstRangeAction, linesInSeriesWithPst.get(pstRangeAction.getNetworkElement().getId()), curativeState, crac, network)) + .collect(Collectors.toSet()); + return Optional.of(new PstRegulationInput(curativeState, limitingElement.get(), elementaryPstRegulationInputs)); + } + return Optional.empty(); + } + + /** + * If the most limiting element of a curative state is overloaded and is in series with a PST, it is returned. + * If not, an empty optional value is returned instead. + */ + private static Optional getMostLimitingElementProtectedByPst(State curativeState, Crac crac, RaoResult raoResult, Unit unit, Set linesInSeriesWithPst) { + Map marginPerCnec = crac.getFlowCnecs(curativeState).stream().collect(Collectors.toMap(Function.identity(), flowCnec -> raoResult.getMargin(curativeState.getInstant(), flowCnec, unit))); + List> sortedNegativeMargins = marginPerCnec.entrySet().stream() + .filter(entry -> entry.getValue() < 0) + .sorted(Map.Entry.comparingByValue()).toList(); + if (sortedNegativeMargins.isEmpty()) { + return Optional.empty(); + } + double minMargin = sortedNegativeMargins.get(0).getValue(); + Set limitingElements = new HashSet<>(); + sortedNegativeMargins.stream().filter(entry -> entry.getValue() == minMargin).forEach(entry -> limitingElements.add(entry.getKey())); + return limitingElements.stream() + .filter(flowCnec -> linesInSeriesWithPst.contains(flowCnec.getNetworkElement().getId())) + .min(Comparator.comparing(Identifiable::getId)); + } + + private static LoadFlowParameters getLoadFlowParameters(RaoParameters raoParameters) { + return raoParameters.hasExtension(OpenRaoSearchTreeParameters.class) ? raoParameters.getExtension(OpenRaoSearchTreeParameters.class).getLoadFlowAndSensitivityParameters().getSensitivityWithLoadFlowParameters().getLoadFlowParameters() : new LoadFlowParameters(); + } + + private static void updateLoadFlowParametersForPstRegulation(LoadFlowParameters loadFlowParameters) { + loadFlowParameters.setPhaseShifterRegulationOn(true); + if (loadFlowParameters.getExtension(OpenLoadFlowParameters.class) == null) { + loadFlowParameters.addExtension(OpenLoadFlowParameters.class, new OpenLoadFlowParameters()); + } + loadFlowParameters.getExtension(OpenLoadFlowParameters.class).setMaxOuterLoopIterations(1000); + } + + private static void applyOptimalRemedialActionsForState(Network networkClone, RaoResult raoResult, State state) { + // network actions need to be applied BEFORE range actions because to apply HVDC range actions we need to apply AC emulation deactivation network actions beforehand + raoResult.getActivatedNetworkActionsDuringState(state).forEach(networkAction -> networkAction.apply(networkClone)); + raoResult.getActivatedRangeActionsDuringState(state).forEach(rangeAction -> rangeAction.apply(networkClone, raoResult.getOptimizedSetPointOnState(state, rangeAction))); + } + + private static Set getPstRangeActionsForRegulation(Set pstsToRegulate, Crac crac) { + Map rangeActionPerPst = getRangeActionPerPst(pstsToRegulate, crac); + Set rangeActionsToRegulate = new HashSet<>(); + for (String pstId : pstsToRegulate) { + if (rangeActionPerPst.containsKey(pstId)) { + rangeActionsToRegulate.add(rangeActionPerPst.get(pstId)); + } else { + BUSINESS_LOGS.info("PST {} cannot be regulated as no curative PST range action was defined for it.", pstId); + } + } + return rangeActionsToRegulate; + } + + private static Map getRangeActionPerPst(Set pstsToRegulate, Crac crac) { + // filter out crac's last instant range actions, as results reporting would be less relevant + return crac.getPstRangeActions().stream() + .filter(pstRangeAction -> pstRangeAction.getUsageRules().stream().anyMatch(usageRule -> usageRule.getInstant() == crac.getLastInstant())) + .filter(pstRangeAction -> pstsToRegulate.contains(pstRangeAction.getNetworkElement().getId())) + .collect(Collectors.toMap(pstRangeAction -> pstRangeAction.getNetworkElement().getId(), Function.identity())); + } + + private static int getNumberOfThreads(Crac crac, RaoParameters raoParameters) { + return Math.min(getAvailableCPUs(raoParameters), crac.getContingencies().size()); + } + + /** + * Performs PST regulation for a curative state. The taps are changed during the loadflow iterations. + */ + private static PstRegulationResult regulatePstsForContingencyScenario(PstRegulationInput pstRegulationInput, Crac crac, Set rangeActionsToRegulate, RaoResult raoResult, LoadFlowParameters loadFlowParameters, AbstractNetworkPool networkPool) throws InterruptedException { + Network networkClone = networkPool.getAvailableNetwork(); + Contingency contingency = pstRegulationInput.curativeState().getContingency().orElseThrow(); + simulateContingencyAndApplyCurativeActions(contingency, networkClone, crac, raoResult); + Map initialTapPerPst = getInitialTapPerPst(rangeActionsToRegulate, networkClone); + Map regulatedTapPerPst = PstRegulator.regulatePsts(pstRegulationInput.elementaryPstRegulationInputs(), networkClone, loadFlowParameters); + logPstRegulationResultsForContingencyScenario(contingency, initialTapPerPst, regulatedTapPerPst, pstRegulationInput.limitingElement()); + networkPool.releaseUsedNetwork(networkClone); + return new PstRegulationResult(contingency, regulatedTapPerPst); + } + + private static void simulateContingencyAndApplyCurativeActions(Contingency contingency, Network networkClone, Crac crac, RaoResult raoResult) { + // simulate contingency + contingency.toModification().apply(networkClone); + + // apply optimal automatons and curative remedial actions + crac.getStates(contingency).stream() + .filter(state -> !state.getInstant().isOutage()) + .forEach(state -> applyOptimalRemedialActionsForState(networkClone, raoResult, state)); + } + + private static Map getInitialTapPerPst(Set rangeActionsToRegulate, Network networkClone) { + return rangeActionsToRegulate.stream().collect(Collectors.toMap(Function.identity(), pstRangeAction -> networkClone.getTwoWindingsTransformer(pstRangeAction.getNetworkElement().getId()).getPhaseTapChanger().getTapPosition())); + } + + private static void logPstRegulationResultsForContingencyScenario(Contingency contingency, + Map initialTapPerPst, + Map regulatedTapPerPst, + FlowCnec mostLimitingElement) { + List sortedPstRangeActions = initialTapPerPst.keySet().stream().sorted(Comparator.comparing(PstRangeAction::getId)).toList(); + List shiftDetails = new ArrayList<>(); + sortedPstRangeActions.forEach( + pstRangeAction -> { + int initialTap = initialTapPerPst.get(pstRangeAction); + int regulatedTap = regulatedTapPerPst.get(pstRangeAction); + if (initialTap != regulatedTap) { + shiftDetails.add("%s (%s -> %s)".formatted(pstRangeAction.getName(), initialTap, regulatedTap)); + } + } + ); + String allShiftedPstsDetails = shiftDetails.isEmpty() ? "no PST shifted" : String.join(", ", shiftDetails); + if (!shiftDetails.isEmpty()) { + BUSINESS_LOGS.info("FlowCNEC '{}' of contingency scenario '{}' is overloaded and is the most limiting element, PST regulation has been triggered: {}", mostLimitingElement.getId(), contingency.getName().orElse(contingency.getId()), allShiftedPstsDetails); + } + } +} diff --git a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationInput.java b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationInput.java new file mode 100644 index 0000000000..9fff256ca5 --- /dev/null +++ b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationInput.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2026, 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.openrao.pstregulation; + +import com.powsybl.openrao.data.crac.api.State; +import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; + +import java.util.Set; + +/** + * @author Thomas Bouquet {@literal } + */ +public record PstRegulationInput(State curativeState, FlowCnec limitingElement, Set elementaryPstRegulationInputs) { +} diff --git a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationOutput.java b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationOutput.java new file mode 100644 index 0000000000..3a5d9e66c4 --- /dev/null +++ b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationOutput.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2026, 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.openrao.pstregulation; + +/** + * @author Thomas Bouquet {@literal } + */ +public class PstRegulationOutput { +} diff --git a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationResult.java b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationResult.java new file mode 100644 index 0000000000..d7b92177d8 --- /dev/null +++ b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulationResult.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2026, 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.openrao.pstregulation; + +import com.powsybl.contingency.Contingency; +import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; + +import java.util.Map; + +/** + * @author Thomas Bouquet {@literal } + */ +public record PstRegulationResult(Contingency contingency, Map regulatedTapPerPst) { +} diff --git a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulator.java b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulator.java new file mode 100644 index 0000000000..881c146780 --- /dev/null +++ b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulator.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026, 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.openrao.pstregulation; + +import com.powsybl.iidm.network.Network; +import com.powsybl.iidm.network.PhaseTapChanger; +import com.powsybl.iidm.network.TwoWindingsTransformer; +import com.powsybl.loadflow.LoadFlow; +import com.powsybl.loadflow.LoadFlowParameters; +import com.powsybl.openrao.commons.OpenRaoException; +import com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider; +import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; + +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Utility class that + * @author Thomas Bouquet {@literal } + */ +public final class PstRegulator { + private PstRegulator() { + } + + public static Map regulatePsts(Set elementaryPstRegulationInputs, Network network, LoadFlowParameters loadFlowParameters) { + elementaryPstRegulationInputs.forEach(elementaryPstRegulationInput -> setRegulationForPst(network, elementaryPstRegulationInput)); + LoadFlow.find("OpenLoadFlow").run(network, loadFlowParameters); + return elementaryPstRegulationInputs.stream().collect(Collectors.toMap(ElementaryPstRegulationInput::pstRangeAction, pstRegulationInput -> getRegulatedTap(network, pstRegulationInput.pstRangeAction()))); + } + + private static void setRegulationForPst(Network network, ElementaryPstRegulationInput elementaryPstRegulationInput) { + TwoWindingsTransformer twt = getTwoWindingsTransformer(network, elementaryPstRegulationInput.pstRangeAction()); + PhaseTapChanger phaseTapChanger = twt.getPhaseTapChanger(); + phaseTapChanger.setRegulationValue(elementaryPstRegulationInput.limitingThreshold()); + setRegulationTerminal(twt, elementaryPstRegulationInput); + phaseTapChanger.setRegulationMode(PhaseTapChanger.RegulationMode.CURRENT_LIMITER); + setTargetDeadband(twt); + phaseTapChanger.setRegulating(true); + } + + private static TwoWindingsTransformer getTwoWindingsTransformer(Network network, PstRangeAction pstRangeAction) { + String pstId = pstRangeAction.getNetworkElement().getId(); + TwoWindingsTransformer twt = network.getTwoWindingsTransformer(pstId); + if (twt == null) { + throw new OpenRaoException("No two-windings transformer with id %s found in network.".formatted(pstId)); + } + return twt; + } + + private static void setRegulationTerminal(TwoWindingsTransformer twt, ElementaryPstRegulationInput elementaryPstRegulationInput) { + PhaseTapChanger phaseTapChanger = twt.getPhaseTapChanger(); + if (phaseTapChanger.getRegulationTerminal() == null) { + OpenRaoLoggerProvider.TECHNICAL_LOGS.info("No default regulation terminal defined for phase tap changer of two-windings transformer %s, terminal on side %s will be used.".formatted(twt.getId(), elementaryPstRegulationInput.limitingSide())); + phaseTapChanger.setRegulationTerminal(twt.getTerminal(elementaryPstRegulationInput.limitingSide())); + } + } + + private static void setTargetDeadband(TwoWindingsTransformer twt) { + PhaseTapChanger phaseTapChanger = twt.getPhaseTapChanger(); + if (Double.isNaN(phaseTapChanger.getTargetDeadband())) { + OpenRaoLoggerProvider.TECHNICAL_LOGS.info("No default target deadband defined for phase tap changer of two-windings transformer %s, a value of 0.0 will be used.".formatted(twt.getId())); + phaseTapChanger.setTargetDeadband(0.0); // value is not used by OpenLoadFlow in CURRENT_LIMITER mode + } + } + + private static int getRegulatedTap(Network network, PstRangeAction pstRangeAction) { + Integer tapPosition = getTwoWindingsTransformer(network, pstRangeAction).getPhaseTapChanger().getSolvedTapPosition(); + if (tapPosition == null) { + throw new OpenRaoException("Could not retrieve regulated tap position for PST range action %s.".formatted(pstRangeAction.getName())); + } + return getTwoWindingsTransformer(network, pstRangeAction).getPhaseTapChanger().getSolvedTapPosition(); + } +} From 17b5705ed155078d781d09ed074f9c27a5d95ff2 Mon Sep 17 00:00:00 2001 From: Thomas Bouquet Date: Fri, 13 Mar 2026 16:15:50 +0100 Subject: [PATCH 2/7] draft Signed-off-by: Thomas Bouquet --- pst-regulation/pom.xml | 8 ++ .../openrao/pstregulation/PstRegulation.java | 81 ++++++++++++++++--- 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/pst-regulation/pom.xml b/pst-regulation/pom.xml index f5ddfa3fc7..77dfc0ef8c 100644 --- a/pst-regulation/pom.xml +++ b/pst-regulation/pom.xml @@ -38,6 +38,14 @@ powsybl-open-loadflow compile + + com.powsybl + open-rao-sensitivity-analysis + + + com.powsybl + open-rao-search-tree-rao + \ No newline at end of file diff --git a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java index c8754b443d..ee6c954319 100644 --- a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java +++ b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java @@ -18,16 +18,25 @@ import com.powsybl.openrao.data.crac.api.Instant; import com.powsybl.openrao.data.crac.api.State; import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; +import com.powsybl.openrao.data.crac.api.networkaction.NetworkAction; import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; import com.powsybl.openrao.data.raoresult.api.ComputationStatus; import com.powsybl.openrao.data.raoresult.api.RaoResult; import com.powsybl.openrao.raoapi.parameters.RaoParameters; import com.powsybl.openrao.raoapi.parameters.extensions.OpenRaoSearchTreeParameters; import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoPstRegulationParameters; +import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; +import com.powsybl.openrao.searchtreerao.result.api.PrePerimeterResult; +import com.powsybl.openrao.searchtreerao.result.impl.NetworkActionsResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.OptimizationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; +import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; import com.powsybl.openrao.util.AbstractNetworkPool; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -47,25 +56,25 @@ * @author Thomas Bouquet {@literal } */ public final class PstRegulation { + private static final String INITIAL_SCENARIO = "InitialScenario"; + private PstRegulation() { } public static RaoResult regulatePsts(Network network, Crac crac, RaoResult raoResult, RaoParameters raoParameters) { - // TODO - return null; - } + Map pstsToRegulate = SearchTreeRaoPstRegulationParameters.getPstsToRegulate(raoParameters); + if (pstsToRegulate.isEmpty()) { + return raoResult; + } - private static Set regulatePsts(Map pstsToRegulate, Network network, Crac crac, RaoParameters raoParameters, RaoResult raoResult) { - // filter out non-curative PSTs - // currently, only PSTs with a usage rule for a given state are regulated Set rangeActionsToRegulate = getPstRangeActionsForRegulation(pstsToRegulate.keySet(), crac); if (rangeActionsToRegulate.isEmpty()) { - return Set.of(); + return raoResult; } Set statesToRegulate = getStatesToRegulate(crac, raoResult, getFlowUnit(raoParameters), rangeActionsToRegulate, SearchTreeRaoPstRegulationParameters.getPstsToRegulate(raoParameters), network); if (statesToRegulate.isEmpty()) { - return Set.of(); + return raoResult; } Set contingencies = statesToRegulate.stream().map(PstRegulationInput::curativeState).map(State::getContingency).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet()); @@ -94,11 +103,11 @@ private static Set regulatePsts(Map pstsToR } } networkPool.shutdownAndAwaitTermination(1000, TimeUnit.SECONDS); - return pstRegulationResults; + return mergePstRegulationResultsWithRaoResult(pstRegulationResults, raoResult, network, crac); } catch (Exception e) { Thread.currentThread().interrupt(); BUSINESS_WARNS.warn("An error occurred during PST regulation, pre-regulation RAO result will be kept."); - return Set.of(); + return raoResult; } finally { loadFlowParameters.setPhaseShifterRegulationOn(initialPhaseShifterRegulationOnValue); } @@ -255,4 +264,56 @@ private static void logPstRegulationResultsForContingencyScenario(Contingency co BUSINESS_LOGS.info("FlowCNEC '{}' of contingency scenario '{}' is overloaded and is the most limiting element, PST regulation has been triggered: {}", mostLimitingElement.getId(), contingency.getName().orElse(contingency.getId()), allShiftedPstsDetails); } } + + private static RaoResult mergePstRegulationResultsWithRaoResult(Set pstRegulationResults, RaoResult raoResult, Network network, Crac crac) { + // create a new network variant from initial variant for performing the results merging + String variantName = "PSTRegulationResultsMerging"; + network.getVariantManager().setWorkingVariant(INITIAL_SCENARIO); + network.getVariantManager().cloneVariant(INITIAL_SCENARIO, variantName); + network.getVariantManager().setWorkingVariant(variantName); + + // apply PRAs + applyOptimalRemedialActionsForState(network, raoResult, crac.getPreventiveState()); + + Set regulatedStates = pstRegulationResults.stream().map(pstRegulationResult -> crac.getState(pstRegulationResult.contingency().getId(), crac.getLastInstant())).collect(Collectors.toSet()); + Map> appliedNetworkActions = new HashMap<>(); + + // gather all applied ARAs and CRAs + AppliedRemedialActions appliedRemedialActions = new AppliedRemedialActions(); + postContingencyResults.forEach((state, postPerimeterResult) -> { + appliedNetworkActions.put(state, postPerimeterResult.optimizationResult().getActivatedNetworkActions()); + appliedRemedialActions.addAppliedNetworkActions(state, postPerimeterResult.optimizationResult().getActivatedNetworkActions()); + appliedRemedialActions.addAppliedRangeActions(state, getAppliedRangeActionsAndSetPoint(state, postPraResult.optimizationResult())); + appliedRemedialActions.addAppliedRangeActions(state, getAppliedRangeActionsAndSetPoint(state, postPerimeterResult.optimizationResult())); + }); + + // overwrite PST range action results for regulated PSTs + pstRegulationResults.forEach(pstRegulationResult -> pstRegulationResult.regulatedTapPerPst().forEach((pstRangeAction, regulatedTap) -> appliedRemedialActions.addAppliedRangeAction(crac.getState(pstRegulationResult.contingency().getId(), crac.getLastInstant()), pstRangeAction, pstRangeAction.convertTapToAngle(regulatedTap)))); + + PrePerimeterResult postCraSensitivityAnalysisOutput = prePerimeterSensitivityAnalysis.runBasedOnInitialResults(network, initialFlowResult, Collections.emptySet(), appliedRemedialActions); + + Map postRegulationPostContingencyResults = new HashMap<>(); + + // override optimization result + RangeActionActivationResultImpl postRegulationRangeActionActivationResult = new RangeActionActivationResultImpl(postCraSensitivityAnalysisOutput); + postContingencyResults.keySet().forEach(state -> appliedRemedialActions.getAppliedRangeActions(state).forEach((rangeAction, setPoint) -> postRegulationRangeActionActivationResult.putResult(rangeAction, state, setPoint))); + OptimizationResult newOptimizationResult = new OptimizationResultImpl(postCraSensitivityAnalysisOutput, postCraSensitivityAnalysisOutput, postCraSensitivityAnalysisOutput, new NetworkActionsResultImpl(appliedNetworkActions), postRegulationRangeActionActivationResult); + + for (State state : postContingencyResults.keySet()) { + // For instants before pst regulation instant, keep previous results + if (state.getInstant().comesBefore(crac.getLastInstant())) { + postRegulationPostContingencyResults.put(state, postContingencyResults.get(state)); + } else { + // For curative instant, update regulatedStates with newly computed sensi result + postRegulationPostContingencyResults.put(state, new PostPerimeterResult( + regulatedStates.contains(state) ? newOptimizationResult : postContingencyResults.get(state).optimizationResult(), + postCraSensitivityAnalysisOutput + )); + } + } + + return postRegulationPostContingencyResults; + + return raoResult; + } } From 8f55ce7baa23328485ba9a963c10d1182e774ea7 Mon Sep 17 00:00:00 2001 From: Thomas Bouquet Date: Fri, 20 Mar 2026 09:04:54 +0100 Subject: [PATCH 3/7] code compiles Signed-off-by: Thomas Bouquet --- .../openrao/pstregulation/PstRegulation.java | 61 ++++++++++++------- .../openrao/pstregulation/PstRegulator.java | 1 - .../algorithm/CastorFullOptimization.java | 28 +-------- tests/pom.xml | 6 ++ .../tests/steps/PstRegulationSteps.java | 21 +++++++ .../61_pst_regulation/US91_13.feature | 5 ++ 6 files changed, 71 insertions(+), 51 deletions(-) create mode 100644 tests/src/test/java/com/powsybl/openrao/tests/steps/PstRegulationSteps.java diff --git a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java index ee6c954319..a084a5ac7a 100644 --- a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java +++ b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java @@ -22,13 +22,21 @@ import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; import com.powsybl.openrao.data.raoresult.api.ComputationStatus; import com.powsybl.openrao.data.raoresult.api.RaoResult; +import com.powsybl.openrao.raoapi.RaoInput; import com.powsybl.openrao.raoapi.parameters.RaoParameters; import com.powsybl.openrao.raoapi.parameters.extensions.OpenRaoSearchTreeParameters; import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoPstRegulationParameters; +import com.powsybl.openrao.searchtreerao.castor.algorithm.PostPerimeterSensitivityAnalysis; +import com.powsybl.openrao.searchtreerao.castor.algorithm.PrePerimeterSensitivityAnalysis; +import com.powsybl.openrao.searchtreerao.castor.algorithm.StateTree; +import com.powsybl.openrao.searchtreerao.commons.ToolProvider; +import com.powsybl.openrao.searchtreerao.result.api.NetworkActionsResult; import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; import com.powsybl.openrao.searchtreerao.result.api.PrePerimeterResult; import com.powsybl.openrao.searchtreerao.result.impl.NetworkActionsResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.OptimizationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.PostPerimeterResult; +import com.powsybl.openrao.searchtreerao.result.impl.PreventiveAndCurativesRaoResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; import com.powsybl.openrao.util.AbstractNetworkPool; @@ -103,10 +111,10 @@ public static RaoResult regulatePsts(Network network, Crac crac, RaoResult raoRe } } networkPool.shutdownAndAwaitTermination(1000, TimeUnit.SECONDS); - return mergePstRegulationResultsWithRaoResult(pstRegulationResults, raoResult, network, crac); + return mergePstRegulationResultsWithRaoResult(pstRegulationResults, raoResult, network, crac, raoParameters); } catch (Exception e) { Thread.currentThread().interrupt(); - BUSINESS_WARNS.warn("An error occurred during PST regulation, pre-regulation RAO result will be kept."); + BUSINESS_WARNS.warn("An error occurred during PST regulation, pre-regulation RAO result will be kept. Error was: {}", e.getMessage()); return raoResult; } finally { loadFlowParameters.setPhaseShifterRegulationOn(initialPhaseShifterRegulationOnValue); @@ -265,7 +273,11 @@ private static void logPstRegulationResultsForContingencyScenario(Contingency co } } - private static RaoResult mergePstRegulationResultsWithRaoResult(Set pstRegulationResults, RaoResult raoResult, Network network, Crac crac) { + private static RaoResult mergePstRegulationResultsWithRaoResult(Set pstRegulationResults, RaoResult raoResult, Network network, Crac crac, RaoParameters raoParameters) { + ToolProvider toolProvider = ToolProvider.buildFromRaoInputAndParameters(RaoInput.build(network, crac).build(), raoParameters); + PrePerimeterSensitivityAnalysis prePerimeterSensitivityAnalysis = new PrePerimeterSensitivityAnalysis(crac, crac.getFlowCnecs(), crac.getRangeActions(), raoParameters, toolProvider, true); + PrePerimeterResult initialFlowResult = prePerimeterSensitivityAnalysis.runInitialSensitivityAnalysis(network); + // create a new network variant from initial variant for performing the results merging String variantName = "PSTRegulationResultsMerging"; network.getVariantManager().setWorkingVariant(INITIAL_SCENARIO); @@ -274,18 +286,24 @@ private static RaoResult mergePstRegulationResultsWithRaoResult(Set regulatedStates = pstRegulationResults.stream().map(pstRegulationResult -> crac.getState(pstRegulationResult.contingency().getId(), crac.getLastInstant())).collect(Collectors.toSet()); Map> appliedNetworkActions = new HashMap<>(); // gather all applied ARAs and CRAs AppliedRemedialActions appliedRemedialActions = new AppliedRemedialActions(); - postContingencyResults.forEach((state, postPerimeterResult) -> { - appliedNetworkActions.put(state, postPerimeterResult.optimizationResult().getActivatedNetworkActions()); - appliedRemedialActions.addAppliedNetworkActions(state, postPerimeterResult.optimizationResult().getActivatedNetworkActions()); - appliedRemedialActions.addAppliedRangeActions(state, getAppliedRangeActionsAndSetPoint(state, postPraResult.optimizationResult())); - appliedRemedialActions.addAppliedRangeActions(state, getAppliedRangeActionsAndSetPoint(state, postPerimeterResult.optimizationResult())); - }); + crac.getStates().stream().filter(state -> state.getInstant().isAuto() || state.getInstant().isCurative()) + .forEach(state -> { + appliedNetworkActions.put(state, raoResult.getActivatedNetworkActionsDuringState(state)); + appliedRemedialActions.addAppliedNetworkActions(state, raoResult.getActivatedNetworkActionsDuringState(state)); + appliedRemedialActions.addAppliedRangeActions(state, raoResult.getOptimizedSetPointsOnState(state)); + }); // overwrite PST range action results for regulated PSTs pstRegulationResults.forEach(pstRegulationResult -> pstRegulationResult.regulatedTapPerPst().forEach((pstRangeAction, regulatedTap) -> appliedRemedialActions.addAppliedRangeAction(crac.getState(pstRegulationResult.contingency().getId(), crac.getLastInstant()), pstRangeAction, pstRangeAction.convertTapToAngle(regulatedTap)))); @@ -294,26 +312,23 @@ private static RaoResult mergePstRegulationResultsWithRaoResult(Set postRegulationPostContingencyResults = new HashMap<>(); + // TODO: compute post results per instant + // override optimization result RangeActionActivationResultImpl postRegulationRangeActionActivationResult = new RangeActionActivationResultImpl(postCraSensitivityAnalysisOutput); - postContingencyResults.keySet().forEach(state -> appliedRemedialActions.getAppliedRangeActions(state).forEach((rangeAction, setPoint) -> postRegulationRangeActionActivationResult.putResult(rangeAction, state, setPoint))); + crac.getStates().stream().filter(state -> state.getInstant().isAuto() || state.getInstant().isCurative()) + .forEach(state -> appliedRemedialActions.getAppliedRangeActions(state).forEach((rangeAction, setPoint) -> postRegulationRangeActionActivationResult.putResult(rangeAction, state, setPoint))); OptimizationResult newOptimizationResult = new OptimizationResultImpl(postCraSensitivityAnalysisOutput, postCraSensitivityAnalysisOutput, postCraSensitivityAnalysisOutput, new NetworkActionsResultImpl(appliedNetworkActions), postRegulationRangeActionActivationResult); - for (State state : postContingencyResults.keySet()) { - // For instants before pst regulation instant, keep previous results - if (state.getInstant().comesBefore(crac.getLastInstant())) { - postRegulationPostContingencyResults.put(state, postContingencyResults.get(state)); - } else { - // For curative instant, update regulatedStates with newly computed sensi result + crac.getStates().stream().filter(state -> !state.isPreventive()) + .forEach(state -> { postRegulationPostContingencyResults.put(state, new PostPerimeterResult( - regulatedStates.contains(state) ? newOptimizationResult : postContingencyResults.get(state).optimizationResult(), + newOptimizationResult, postCraSensitivityAnalysisOutput )); - } - } - - return postRegulationPostContingencyResults; + }); - return raoResult; + StateTree stateTree = new StateTree(crac); + return new PreventiveAndCurativesRaoResultImpl(stateTree, initialFlowResult, postPerimeterResult, postRegulationPostContingencyResults, crac, raoParameters); } } diff --git a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulator.java b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulator.java index 881c146780..ab0e0d9eeb 100644 --- a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulator.java +++ b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulator.java @@ -21,7 +21,6 @@ import java.util.stream.Collectors; /** - * Utility class that * @author Thomas Bouquet {@literal } */ public final class PstRegulator { diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java index e3e80a3db5..d32626cfa1 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java @@ -243,33 +243,7 @@ public CompletableFuture run() { RaoLogger.checkIfMostLimitingElementIsFictional(BUSINESS_LOGS, stateTree.getBasecaseScenario(), finalSecondPreventiveResult.optimizationResult(), stateTree.getContingencyScenarios(), finalPostContingencyResults, raoParameters.getObjectiveFunctionParameters().getType(), getFlowUnit(raoParameters)); } - CompletableFuture raoResult = postCheckResults(mergedRaoResults, initialOutput, raoParameters.getObjectiveFunctionParameters(), true); - - // PST regulation - Map pstsToRegulate = SearchTreeRaoPstRegulationParameters.getPstsToRegulate(raoParameters); - if (!pstsToRegulate.isEmpty()) { - BUSINESS_LOGS.info("----- PST regulation [start]"); - network.getVariantManager().cloneVariant(INITIAL_SCENARIO, PST_REGULATION); - network.getVariantManager().setWorkingVariant(PST_REGULATION); - Set pstRegulationResults = CastorPstRegulation.regulatePsts(pstsToRegulate, finalPostContingencyResults, network, crac, raoParameters, mergedRaoResults); - Map postRegulationResults = mergeRaoAndPstRegulationResults(pstRegulationResults, finalSecondPreventiveResult, finalPostContingencyResults, prePerimeterSensitivityAnalysis, initialOutput, toolProvider); - RaoResult raoResultWithRegulation = new PreventiveAndCurativesRaoResultImpl( - stateTree, - initialOutput, - postPreventiveResult, - finalSecondPreventiveResult, - postRegulationResults, - crac, - raoParameters); - raoResultWithRegulation.setExecutionDetails(mergedRaoResults.getExecutionDetails()); - BUSINESS_LOGS.info("----- PST regulation [end]"); - BUSINESS_LOGS.info("Merging RAO and PST regulation results:"); - RaoLogger.logMostLimitingElementsResults(BUSINESS_LOGS, stateTree.getBasecaseScenario(), finalSecondPreventiveResult.optimizationResult(), stateTree.getContingencyScenarios(), postRegulationResults, raoParameters.getObjectiveFunctionParameters().getType(), getFlowUnit(raoParameters), NUMBER_LOGGED_ELEMENTS_END_RAO); - RaoLogger.checkIfMostLimitingElementIsFictional(BUSINESS_LOGS, stateTree.getBasecaseScenario(), finalSecondPreventiveResult.optimizationResult(), stateTree.getContingencyScenarios(), postRegulationResults, raoParameters.getObjectiveFunctionParameters().getType(), getFlowUnit(raoParameters)); - return postCheckResults(raoResultWithRegulation, initialOutput, raoParameters.getObjectiveFunctionParameters(), false); - } - - return raoResult; + return postCheckResults(mergedRaoResults, initialOutput, raoParameters.getObjectiveFunctionParameters(), true); } catch (RuntimeException e) { BUSINESS_LOGS.error("{} \n {}", e.getMessage(), ExceptionUtils.getStackTrace(e)); return CompletableFuture.completedFuture(new FailedRaoResultImpl(String.format("RAO failed during %s : %s", currentStep, e.getMessage()))); diff --git a/tests/pom.xml b/tests/pom.xml index ac41696b6b..cb01b61baa 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -324,6 +324,12 @@ commons-io runtime + + com.powsybl + open-rao-pst-regulation + 7.2.0-SNAPSHOT + test + \ No newline at end of file diff --git a/tests/src/test/java/com/powsybl/openrao/tests/steps/PstRegulationSteps.java b/tests/src/test/java/com/powsybl/openrao/tests/steps/PstRegulationSteps.java new file mode 100644 index 0000000000..db0e447604 --- /dev/null +++ b/tests/src/test/java/com/powsybl/openrao/tests/steps/PstRegulationSteps.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026, 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.openrao.tests.steps; + +import com.powsybl.openrao.pstregulation.PstRegulation; +import io.cucumber.java.en.When; + +/** + * @author Thomas Bouquet {@literal } + */ +public class PstRegulationSteps { + @When("I launch PST regulation") + public void launchPSTRegulation() { + CommonTestData.setRaoResult(PstRegulation.regulatePsts(CommonTestData.getNetwork(), CommonTestData.getCrac(), CommonTestData.getRaoResult(), CommonTestData.getRaoParameters())); + } +} diff --git a/tests/src/test/resources/com/powsybl/openrao/tests/features/6_post_computation_features/61_pst_regulation/US91_13.feature b/tests/src/test/resources/com/powsybl/openrao/tests/features/6_post_computation_features/61_pst_regulation/US91_13.feature index 4f8075618d..889cd6f7b9 100644 --- a/tests/src/test/resources/com/powsybl/openrao/tests/features/6_post_computation_features/61_pst_regulation/US91_13.feature +++ b/tests/src/test/resources/com/powsybl/openrao/tests/features/6_post_computation_features/61_pst_regulation/US91_13.feature @@ -36,6 +36,7 @@ Feature: US 91.13: PST Regulation Given crac file is "epic91/crac-91-13-1.json" Given configuration file is "epic91/RaoParameters_ac_pstRegulation.json" When I launch rao + When I launch PST regulation Then the execution details should be "The RAO only went through first preventive" Then its security status should be "UNSECURED" Then the worst margin is -1382.77 A @@ -77,6 +78,7 @@ Feature: US 91.13: PST Regulation Given crac file is "epic91/crac-91-13-2.json" Given configuration file is "epic91/RaoParameters_ac_pstRegulation.json" When I launch rao + When I launch PST regulation Then the execution details should be "The RAO only went through first preventive" Then its security status should be "UNSECURED" Then the worst margin is -247.23 A @@ -143,6 +145,7 @@ Feature: US 91.13: PST Regulation Given crac file is "epic91/crac-91-13-3.json" Given configuration file is "epic91/RaoParameters_ac_3pstsRegulation.json" When I launch rao + When I launch PST regulation Then the execution details should be "The RAO only went through first preventive" Then its security status should be "UNSECURED" # Preventive taps @@ -185,6 +188,7 @@ Feature: US 91.13: PST Regulation Given crac file is "epic91/crac-91-13-4.json" Given configuration file is "epic91/RaoParameters_ac_2pstsRegulation.json" When I launch rao + When I launch PST regulation Then the execution details should be "The RAO only went through first preventive" Then its security status should be "UNSECURED" Then the worst margin is -733.27 A @@ -217,6 +221,7 @@ Feature: US 91.13: PST Regulation Given crac file is "epic91/crac-91-13-5.json" Given configuration file is "epic91/RaoParameters_ac_pstRegulationSeries.json" When I launch rao + When I launch PST regulation Then the execution details should be "The RAO only went through first preventive" Then its security status should be "UNSECURED" Then the worst margin is -1187.64 A From c086dd2b320cbf411cf96fc7a0adea7cac374112 Mon Sep 17 00:00:00 2001 From: Thomas Bouquet Date: Fri, 20 Mar 2026 15:58:05 +0100 Subject: [PATCH 4/7] fix taps in cucumbers but not flows Signed-off-by: Thomas Bouquet --- .../openrao/pstregulation/PstRegulation.java | 80 +++++----- .../algorithm/CastorFullOptimization.java | 31 ++-- .../powsybl/openrao/tests/steps/RaoSteps.java | 138 +++++++++--------- 3 files changed, 138 insertions(+), 111 deletions(-) diff --git a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java index a084a5ac7a..6b1c62c456 100644 --- a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java +++ b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java @@ -18,7 +18,6 @@ import com.powsybl.openrao.data.crac.api.Instant; import com.powsybl.openrao.data.crac.api.State; import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; -import com.powsybl.openrao.data.crac.api.networkaction.NetworkAction; import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; import com.powsybl.openrao.data.raoresult.api.ComputationStatus; import com.powsybl.openrao.data.raoresult.api.RaoResult; @@ -30,7 +29,6 @@ import com.powsybl.openrao.searchtreerao.castor.algorithm.PrePerimeterSensitivityAnalysis; import com.powsybl.openrao.searchtreerao.castor.algorithm.StateTree; import com.powsybl.openrao.searchtreerao.commons.ToolProvider; -import com.powsybl.openrao.searchtreerao.result.api.NetworkActionsResult; import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; import com.powsybl.openrao.searchtreerao.result.api.PrePerimeterResult; import com.powsybl.openrao.searchtreerao.result.impl.NetworkActionsResultImpl; @@ -38,6 +36,7 @@ import com.powsybl.openrao.searchtreerao.result.impl.PostPerimeterResult; import com.powsybl.openrao.searchtreerao.result.impl.PreventiveAndCurativesRaoResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl; import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; import com.powsybl.openrao.util.AbstractNetworkPool; @@ -274,6 +273,11 @@ private static void logPstRegulationResultsForContingencyScenario(Contingency co } private static RaoResult mergePstRegulationResultsWithRaoResult(Set pstRegulationResults, RaoResult raoResult, Network network, Crac crac, RaoParameters raoParameters) { + Map resultsPerState = pstRegulationResults.stream().collect(Collectors.toMap( + pstRegulationResult -> crac.getState(pstRegulationResult.contingency(), crac.getLastInstant()), + Function.identity() + )); + ToolProvider toolProvider = ToolProvider.buildFromRaoInputAndParameters(RaoInput.build(network, crac).build(), raoParameters); PrePerimeterSensitivityAnalysis prePerimeterSensitivityAnalysis = new PrePerimeterSensitivityAnalysis(crac, crac.getFlowCnecs(), crac.getRangeActions(), raoParameters, toolProvider, true); PrePerimeterResult initialFlowResult = prePerimeterSensitivityAnalysis.runInitialSensitivityAnalysis(network); @@ -285,50 +289,60 @@ private static RaoResult mergePstRegulationResultsWithRaoResult(Set postRegulationPostContingencyResults = new HashMap<>(); + + List postOutageInstants = crac.getSortedInstants().stream().filter(instant -> instant.isAuto() || instant.isCurative()).toList(); + + for (Contingency contingency : crac.getContingencies()) { + AppliedRemedialActions appliedRemedialActions = new AppliedRemedialActions(); - OptimizationResult preventiveResult = new OptimizationResultImpl(postPraResult, postPraResult, postPraResult, preventiveNetworkActionsResult, preventiveRangeActionActivationResult); - PostPerimeterResult postPerimeterResult = new PostPerimeterSensitivityAnalysis(crac, crac.getFlowCnecs(), crac.getRangeActions(), raoParameters, toolProvider, true).runBasedOnInitialPreviousAndOptimizationResults(network, initialFlowResult, postPraResult, Set.of(), preventiveResult, new AppliedRemedialActions()); + network.getVariantManager().cloneVariant(variantName, contingency.getId()); + network.getVariantManager().setWorkingVariant(contingency.getId()); - Map> appliedNetworkActions = new HashMap<>(); + PrePerimeterResult prePerimeterResult = postPreventivePerimeterResult.prePerimeterResultForAllFollowingStates(); + + for (Instant instant : postOutageInstants) { + State state = crac.getState(contingency, instant); - // gather all applied ARAs and CRAs - AppliedRemedialActions appliedRemedialActions = new AppliedRemedialActions(); - crac.getStates().stream().filter(state -> state.getInstant().isAuto() || state.getInstant().isCurative()) - .forEach(state -> { - appliedNetworkActions.put(state, raoResult.getActivatedNetworkActionsDuringState(state)); appliedRemedialActions.addAppliedNetworkActions(state, raoResult.getActivatedNetworkActionsDuringState(state)); appliedRemedialActions.addAppliedRangeActions(state, raoResult.getOptimizedSetPointsOnState(state)); - }); - - // overwrite PST range action results for regulated PSTs - pstRegulationResults.forEach(pstRegulationResult -> pstRegulationResult.regulatedTapPerPst().forEach((pstRangeAction, regulatedTap) -> appliedRemedialActions.addAppliedRangeAction(crac.getState(pstRegulationResult.contingency().getId(), crac.getLastInstant()), pstRangeAction, pstRangeAction.convertTapToAngle(regulatedTap)))); - PrePerimeterResult postCraSensitivityAnalysisOutput = prePerimeterSensitivityAnalysis.runBasedOnInitialResults(network, initialFlowResult, Collections.emptySet(), appliedRemedialActions); + if (resultsPerState.containsKey(state)) { + PstRegulationResult pstRegulationResult = resultsPerState.get(state); + pstRegulationResult.regulatedTapPerPst().forEach((pstRangeAction, regulatedTap) -> appliedRemedialActions.addAppliedRangeAction(state, pstRangeAction, pstRangeAction.convertTapToAngle(regulatedTap))); + } - Map postRegulationPostContingencyResults = new HashMap<>(); + appliedRemedialActions.getAppliedNetworkActions(state).forEach(networkAction -> networkAction.apply(network)); + appliedRemedialActions.getAppliedRangeActions(state).forEach((rangeAction, setPoint) -> rangeAction.apply(network, setPoint)); - // TODO: compute post results per instant + PrePerimeterResult postInstantPerimeterResult = prePerimeterSensitivityAnalysis.runBasedOnInitialResults(network, initialFlowResult, Collections.emptySet(), new AppliedRemedialActions()); - // override optimization result - RangeActionActivationResultImpl postRegulationRangeActionActivationResult = new RangeActionActivationResultImpl(postCraSensitivityAnalysisOutput); - crac.getStates().stream().filter(state -> state.getInstant().isAuto() || state.getInstant().isCurative()) - .forEach(state -> appliedRemedialActions.getAppliedRangeActions(state).forEach((rangeAction, setPoint) -> postRegulationRangeActionActivationResult.putResult(rangeAction, state, setPoint))); - OptimizationResult newOptimizationResult = new OptimizationResultImpl(postCraSensitivityAnalysisOutput, postCraSensitivityAnalysisOutput, postCraSensitivityAnalysisOutput, new NetworkActionsResultImpl(appliedNetworkActions), postRegulationRangeActionActivationResult); + OptimizationResult newOptimizationResult = new OptimizationResultImpl( + postInstantPerimeterResult, + postInstantPerimeterResult, + postInstantPerimeterResult, + new NetworkActionsResultImpl(Map.of(state, raoResult.getActivatedNetworkActionsDuringState(state))), + new RangeActionActivationResultImpl(postInstantPerimeterResult) + ); + PostPerimeterResult postPerimeterStateResult = new PostPerimeterSensitivityAnalysis(crac, crac.getFlowCnecs(), crac.getRangeActions(), raoParameters, toolProvider, true).runBasedOnInitialPreviousAndOptimizationResults(network, initialFlowResult, prePerimeterResult, Set.of(), newOptimizationResult, new AppliedRemedialActions()); + postRegulationPostContingencyResults.put(state, postPerimeterStateResult); - crac.getStates().stream().filter(state -> !state.isPreventive()) - .forEach(state -> { - postRegulationPostContingencyResults.put(state, new PostPerimeterResult( - newOptimizationResult, - postCraSensitivityAnalysisOutput - )); - }); + prePerimeterResult = postInstantPerimeterResult; + } + } StateTree stateTree = new StateTree(crac); - return new PreventiveAndCurativesRaoResultImpl(stateTree, initialFlowResult, postPerimeterResult, postRegulationPostContingencyResults, crac, raoParameters); + return new PreventiveAndCurativesRaoResultImpl(stateTree, initialFlowResult, postPreventivePerimeterResult, postRegulationPostContingencyResults, crac, raoParameters); } } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java index d32626cfa1..f4d531f86b 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java @@ -7,6 +7,7 @@ package com.powsybl.openrao.searchtreerao.castor.algorithm; +import com.powsybl.iidm.network.Network; import com.powsybl.openrao.data.crac.api.Crac; import com.powsybl.openrao.data.crac.api.Instant; import com.powsybl.openrao.data.crac.api.State; @@ -21,32 +22,44 @@ import com.powsybl.openrao.raoapi.parameters.RaoParameters; import com.powsybl.openrao.raoapi.parameters.extensions.LoadFlowAndSensitivityParameters; import com.powsybl.openrao.raoapi.parameters.extensions.OpenRaoSearchTreeParameters; -import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoPstRegulationParameters; -import com.powsybl.openrao.searchtreerao.castor.algorithm.pstregulation.CastorPstRegulation; import com.powsybl.openrao.searchtreerao.castor.algorithm.pstregulation.PstRegulationResult; import com.powsybl.openrao.searchtreerao.commons.RaoLogger; import com.powsybl.openrao.searchtreerao.commons.RaoUtil; import com.powsybl.openrao.searchtreerao.commons.ToolProvider; import com.powsybl.openrao.searchtreerao.commons.objectivefunction.ObjectiveFunction; -import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.*; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.PreventiveOptimizationPerimeter; import com.powsybl.openrao.searchtreerao.commons.parameters.TreeParameters; import com.powsybl.openrao.searchtreerao.commons.parameters.UnoptimizedCnecParameters; -import com.powsybl.openrao.searchtreerao.result.api.*; -import com.powsybl.openrao.searchtreerao.result.impl.*; +import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; +import com.powsybl.openrao.searchtreerao.result.api.PrePerimeterResult; +import com.powsybl.openrao.searchtreerao.result.impl.FailedRaoResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.NetworkActionsResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.OneStateOnlyRaoResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.OptimizationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.PostPerimeterResult; +import com.powsybl.openrao.searchtreerao.result.impl.PreventiveAndCurativesRaoResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.RemedialActionActivationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.UnoptimizedRaoResultImpl; import com.powsybl.openrao.searchtreerao.searchtree.algorithms.SearchTree; import com.powsybl.openrao.searchtreerao.searchtree.inputs.SearchTreeInput; import com.powsybl.openrao.searchtreerao.searchtree.parameters.SearchTreeParameters; import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; -import com.powsybl.iidm.network.Network; import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.tuple.Pair; import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.concurrent.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.*; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_LOGS; +import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; import static com.powsybl.openrao.searchtreerao.commons.HvdcUtils.getHvdcRangeActionsOnHvdcLineInAcEmulation; import static com.powsybl.openrao.searchtreerao.commons.RaoLogger.formatDoubleBasedOnMargin; import static com.powsybl.openrao.searchtreerao.commons.RaoLogger.getVirtualCostDetailed; diff --git a/tests/src/test/java/com/powsybl/openrao/tests/steps/RaoSteps.java b/tests/src/test/java/com/powsybl/openrao/tests/steps/RaoSteps.java index 4b0d89d98d..19f9b440e4 100644 --- a/tests/src/test/java/com/powsybl/openrao/tests/steps/RaoSteps.java +++ b/tests/src/test/java/com/powsybl/openrao/tests/steps/RaoSteps.java @@ -160,69 +160,69 @@ public void iLaunchLoopflowComputation(String timestamp) { @Then("the calculation succeeds") public void theCalculationSucceeds() { - assertEquals(ComputationStatus.DEFAULT, raoResult.getComputationStatus()); + assertEquals(ComputationStatus.DEFAULT, CommonTestData.getRaoResult().getComputationStatus()); } @Then("the calculation partially fails") public void theCalculationPartiallyFails() { - assertEquals(ComputationStatus.PARTIAL_FAILURE, raoResult.getComputationStatus()); + assertEquals(ComputationStatus.PARTIAL_FAILURE, CommonTestData.getRaoResult().getComputationStatus()); } @Then("the calculation fails") public void theCalculationFails() { - assertEquals(ComputationStatus.FAILURE, raoResult.getComputationStatus()); + assertEquals(ComputationStatus.FAILURE, CommonTestData.getRaoResult().getComputationStatus()); } @Then("its security status should be {string}") public void statusShouldBe(String status) { - assertEquals(status.equalsIgnoreCase("secured"), raoResult.isSecure(PhysicalParameter.FLOW)); + assertEquals(status.equalsIgnoreCase("secured"), CommonTestData.getRaoResult().isSecure(PhysicalParameter.FLOW)); } @Then("the value of the objective function initially should be {double}") public void objectiveFunctionValueInitialShouldBe(double expectedValue) { - assertEquals(expectedValue, raoResult.getCost(null), flowAmpereTolerance(expectedValue)); + assertEquals(expectedValue, CommonTestData.getRaoResult().getCost(null), flowAmpereTolerance(expectedValue)); } @Then("the value of the objective function after PRA should be {double}") public void objectiveFunctionValueAfterPraShouldBe(double expectedValue) { - assertEquals(expectedValue, raoResult.getCost(crac.getPreventiveInstant()), flowAmpereTolerance(expectedValue)); + assertEquals(expectedValue, CommonTestData.getRaoResult().getCost(crac.getPreventiveInstant()), flowAmpereTolerance(expectedValue)); } @Then("the value of the objective function after ARA should be {double}") public void objectiveFunctionValueAfterAraShouldBe(double expectedValue) { Instant instant = crac.hasAutoInstant() ? crac.getInstant(InstantKind.AUTO) : crac.getOutageInstant(); - assertEquals(expectedValue, raoResult.getCost(instant), flowAmpereTolerance(expectedValue)); + assertEquals(expectedValue, CommonTestData.getRaoResult().getCost(instant), flowAmpereTolerance(expectedValue)); } @Then("the value of the objective function after CRA should be {double}") public void objectiveFunctionValueAfterCraShouldBe(double expectedValue) { - assertEquals(expectedValue, raoResult.getCost(crac.getLastInstant()), flowAmpereTolerance(expectedValue)); + assertEquals(expectedValue, CommonTestData.getRaoResult().getCost(crac.getLastInstant()), flowAmpereTolerance(expectedValue)); } @Then("the value of the objective function before optimisation should be {double}") public void objectiveFunctionValueBeforeOptShouldBe(double expectedValue) { - assertEquals(expectedValue, raoResult.getCost(null), flowAmpereTolerance(expectedValue)); + assertEquals(expectedValue, CommonTestData.getRaoResult().getCost(null), flowAmpereTolerance(expectedValue)); } @Then("{int} remedial actions are used in preventive") public void countPra(int expectedCount) { - assertEquals(expectedCount, raoResult.getActivatedNetworkActionsDuringState(preventiveState).size() + raoResult.getActivatedRangeActionsDuringState(preventiveState).size()); + assertEquals(expectedCount, CommonTestData.getRaoResult().getActivatedNetworkActionsDuringState(preventiveState).size() + raoResult.getActivatedRangeActionsDuringState(preventiveState).size()); } @Then("{int} network actions are used in preventive") public void countNetworkActionPra(int expectedCount) { - assertEquals(expectedCount, raoResult.getActivatedNetworkActionsDuringState(preventiveState).size()); + assertEquals(expectedCount, CommonTestData.getRaoResult().getActivatedNetworkActionsDuringState(preventiveState).size()); } @Then("{int} ± {int} remedial actions are used in preventive") public void countPra(int expectedCount, int tolerance) { - assertEquals(expectedCount, raoResult.getActivatedNetworkActionsDuringState(preventiveState).size() + raoResult.getActivatedRangeActionsDuringState(preventiveState).size(), tolerance); + assertEquals(expectedCount, CommonTestData.getRaoResult().getActivatedNetworkActionsDuringState(preventiveState).size() + raoResult.getActivatedRangeActionsDuringState(preventiveState).size(), tolerance); } @Then("{int} remedial actions are used after {string} at {string}") public void countCra(int expectedCount, String contingencyId, String instant) { State state = getState(contingencyId, instant); - assertEquals(expectedCount, raoResult.getActivatedRangeActionsDuringState(state).size() + raoResult.getActivatedNetworkActionsDuringState(state).size()); + assertEquals(expectedCount, CommonTestData.getRaoResult().getActivatedRangeActionsDuringState(state).size() + raoResult.getActivatedNetworkActionsDuringState(state).size()); } @Then("the remedial action {string} is used in preventive") @@ -265,51 +265,51 @@ public void remedialActionNotUsedInPreventive(String remedialAction) { @Then("the tap of PstRangeAction {string} should be {int} in preventive") public void theTapOfPstRangeActionShouldBe(String pstRangeActionId, int chosenPstTap) { - assertEquals(chosenPstTap, raoResult.getOptimizedTapOnState(preventiveState, (PstRangeAction) crac.getRangeAction(pstRangeActionId))); + assertEquals(chosenPstTap, CommonTestData.getRaoResult().getOptimizedTapOnState(preventiveState, (PstRangeAction) crac.getRangeAction(pstRangeActionId))); } @Then("the tap of PstRangeAction {string} should be {int} ± {int} in preventive") public void theTapOfPstRangeActionShouldBe(String pstRangeActionId, int chosenPstTap, int tolerance) { - assertEquals(chosenPstTap, raoResult.getOptimizedTapOnState(preventiveState, (PstRangeAction) crac.getRangeAction(pstRangeActionId)), tolerance); + assertEquals(chosenPstTap, CommonTestData.getRaoResult().getOptimizedTapOnState(preventiveState, (PstRangeAction) crac.getRangeAction(pstRangeActionId)), tolerance); } @Then("the tap of PstRangeAction {string} should be {int} after {string} at {string}") public void theTapOfPstRangeActionShouldBe(String pstRangeActionId, int chosenPstTap, String contingencyId, String instant) { PstRangeAction rangeAction = (PstRangeAction) crac.getRangeAction(pstRangeActionId); - assertEquals(chosenPstTap, raoResult.getOptimizedTapOnState(getState(contingencyId, instant), rangeAction)); + assertEquals(chosenPstTap, CommonTestData.getRaoResult().getOptimizedTapOnState(getState(contingencyId, instant), rangeAction)); } @Then("the setpoint of RangeAction {string} should be {double} MW in preventive") public void theSetpointOfRangeActionShouldBe(String rangeActionId, double chosenSetpoint) { - assertEquals(chosenSetpoint, raoResult.getOptimizedSetPointOnState(preventiveState, crac.getRangeAction(rangeActionId)), TOLERANCE_RANGEACTION_SETPOINT); + assertEquals(chosenSetpoint, CommonTestData.getRaoResult().getOptimizedSetPointOnState(preventiveState, crac.getRangeAction(rangeActionId)), TOLERANCE_RANGEACTION_SETPOINT); } @Then("the initial setpoint of RangeAction {string} should be {double}") public void theInitialSetpointOfRangeActionShouldBe(String rangeActionId, double chosenSetpoint) { - assertEquals(chosenSetpoint, raoResult.getPreOptimizationSetPointOnState(preventiveState, crac.getRangeAction(rangeActionId)), TOLERANCE_RANGEACTION_SETPOINT); + assertEquals(chosenSetpoint, CommonTestData.getRaoResult().getPreOptimizationSetPointOnState(preventiveState, crac.getRangeAction(rangeActionId)), TOLERANCE_RANGEACTION_SETPOINT); } @Then("the initial tap of PstRangeAction {string} should be {int}") public void theInitialTapOfPstRangeActionShouldBe(String pstRangeActionId, int chosenTap) { - assertEquals(chosenTap, raoResult.getPreOptimizationTapOnState(preventiveState, crac.getPstRangeAction(pstRangeActionId))); + assertEquals(chosenTap, CommonTestData.getRaoResult().getPreOptimizationTapOnState(preventiveState, crac.getPstRangeAction(pstRangeActionId))); } @Then("the setpoint of RangeAction {string} should be {double} MW after {string} at {string}") public void theSetpointOfRangeActionShouldBe(String rangeActionId, double chosenSetpoint, String contingencyId, String instant) { RangeAction rangeAction = crac.getRangeAction(rangeActionId); - assertEquals(chosenSetpoint, raoResult.getOptimizedSetPointOnState(getState(contingencyId, instant), rangeAction), TOLERANCE_RANGEACTION_SETPOINT); + assertEquals(chosenSetpoint, CommonTestData.getRaoResult().getOptimizedSetPointOnState(getState(contingencyId, instant), rangeAction), TOLERANCE_RANGEACTION_SETPOINT); } @Then("the setpoint of RangeAction {string} should be {double} before {string} at {string}") public void theSetpointOfRangeActionShouldBeBefore(String rangeActionId, double chosenSetpoint, String contingencyId, String instant) { RangeAction rangeAction = crac.getRangeAction(rangeActionId); - assertEquals(chosenSetpoint, raoResult.getPreOptimizationSetPointOnState(getState(contingencyId, instant), rangeAction), TOLERANCE_RANGEACTION_SETPOINT); + assertEquals(chosenSetpoint, CommonTestData.getRaoResult().getPreOptimizationSetPointOnState(getState(contingencyId, instant), rangeAction), TOLERANCE_RANGEACTION_SETPOINT); } @Then("the tap of PstRangeAction {string} should be {int} before {string} at {string}") public void theSetpointOfRangeActionShouldBeBefore(String pstRangeActionId, int chosenTap, String contingencyId, String instant) { PstRangeAction pstRangeAction = crac.getPstRangeAction(pstRangeActionId); - assertEquals(chosenTap, raoResult.getPreOptimizationTapOnState(getState(contingencyId, instant), pstRangeAction)); + assertEquals(chosenTap, CommonTestData.getRaoResult().getPreOptimizationTapOnState(getState(contingencyId, instant), pstRangeAction)); } private State getState(String contingencyId, String instantId) { @@ -358,22 +358,22 @@ private double getTargetPFromVariant(final String generatorId, final String sear @Then("the initial margin on cnec {string} should be {double} A") public void initialMarginInA(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getMargin(null, crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getMargin(null, crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); } @Then("the margin on cnec {string} after PRA should be {double} A") public void afterPraMarginInA(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getMargin(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getMargin(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); } @Then("the margin on cnec {string} after ARA should be {double} A") public void afterAraMarginInA(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getMargin(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getMargin(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); } @Then("the margin on cnec {string} after CRA should be {double} A") public void afterCraMarginInA(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getMargin(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getMargin(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); } @Then("the worst margin is {double} A") @@ -402,23 +402,23 @@ public void worstMarginAndCnecInA(double expectedMargin, String expectedCnecName @Then("the initial margin on cnec {string} should be {double} MW") public void initialMarginInMW(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getMargin(null, crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getMargin(null, crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); } @Then("the margin on cnec {string} after PRA should be {double} MW") public void afterPraMarginInMW(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getMargin(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getMargin(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); } @Then("the margin on cnec {string} after ARA should be {double} MW") public void afterAraMarginInMW(String cnecId, Double expectedMargin) { Instant instant = crac.hasAutoInstant() ? crac.getInstant(InstantKind.AUTO) : crac.getOutageInstant(); - assertEquals(expectedMargin, raoResult.getMargin(instant, crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getMargin(instant, crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); } @Then("the margin on cnec {string} after CRA should be {double} MW") public void afterCraMarginInMW(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getMargin(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getMargin(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); } @Then("the worst margin is {double} MW") @@ -441,22 +441,22 @@ public void worstMarginAndCnecInMW(double expectedMargin, String expectedCnecNam @Then("the initial relative margin on cnec {string} should be {double} A") public void initialRelativeMarginInA(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getRelativeMargin(null, crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getRelativeMargin(null, crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); } @Then("the relative margin on cnec {string} after PRA should be {double} A") public void afterPraRelativeMarginInA(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getRelativeMargin(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getRelativeMargin(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); } @Then("the relative margin on cnec {string} after ARA should be {double} A") public void afterAraRelativeMarginInA(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getRelativeMargin(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getRelativeMargin(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); } @Then("the relative margin on cnec {string} after CRA should be {double} A") public void afterCraRelativeMarginInA(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getRelativeMargin(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getRelativeMargin(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), Unit.AMPERE), flowAmpereTolerance(expectedMargin)); } @Then("the worst relative margin is {double} A") @@ -479,22 +479,22 @@ public void worstRelativeMarginAndCnecInA(double expectedMargin, String expected @Then("the initial relative margin on cnec {string} should be {double} MW") public void initialRelativeMarginInMW(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getRelativeMargin(null, crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getRelativeMargin(null, crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); } @Then("the relative margin on cnec {string} after PRA should be {double} MW") public void afterPraRelativeMarginInMW(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getRelativeMargin(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getRelativeMargin(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); } @Then("the relative margin on cnec {string} after ARA should be {double} MW") public void afterAraRelativeMarginInMW(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getRelativeMargin(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getRelativeMargin(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); } @Then("the relative margin on cnec {string} after CRA should be {double} MW") public void afterCraRelativeMarginInMW(String cnecId, Double expectedMargin) { - assertEquals(expectedMargin, raoResult.getRelativeMargin(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); + assertEquals(expectedMargin, CommonTestData.getRaoResult().getRelativeMargin(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), Unit.MEGAWATT), flowMegawattTolerance(expectedMargin)); } @Then("the worst relative margin is {double} MW") @@ -517,41 +517,41 @@ public void worstRelativeMarginAndCnecInMW(double expectedMargin, String expecte @Then("the initial flow on cnec {string} should be {double} A on side 1 and {double} A on side 2") public void initialFlowInA(String cnecId, Double expectedFlow1, Double expectedFlow2) { - assertEquals(expectedFlow1, raoResult.getFlow(null, crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.AMPERE), flowAmpereTolerance(expectedFlow1)); - assertEquals(expectedFlow2, raoResult.getFlow(null, crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.AMPERE), flowAmpereTolerance(expectedFlow2)); + assertEquals(expectedFlow1, CommonTestData.getRaoResult().getFlow(null, crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.AMPERE), flowAmpereTolerance(expectedFlow1)); + assertEquals(expectedFlow2, CommonTestData.getRaoResult().getFlow(null, crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.AMPERE), flowAmpereTolerance(expectedFlow2)); } @Then("the flow on cnec {string} after PRA should be {double} A on side 1 and {double} A on side 2") public void afterPraFlowInA(String cnecId, Double expectedFlow1, Double expectedFlow2) { - assertEquals(expectedFlow1, raoResult.getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.AMPERE), flowAmpereTolerance(expectedFlow1)); - assertEquals(expectedFlow2, raoResult.getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.AMPERE), flowAmpereTolerance(expectedFlow2)); + assertEquals(expectedFlow1, CommonTestData.getRaoResult().getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.AMPERE), flowAmpereTolerance(expectedFlow1)); + assertEquals(expectedFlow2, CommonTestData.getRaoResult().getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.AMPERE), flowAmpereTolerance(expectedFlow2)); } @Then("the flow on cnec {string} after ARA should be {double} A on side 1 and {double} A on side 2") public void afterAraFlowInA(String cnecId, Double expectedFlow1, Double expectedFlow2) { - assertEquals(expectedFlow1, raoResult.getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.AMPERE), flowAmpereTolerance(expectedFlow1)); - assertEquals(expectedFlow2, raoResult.getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.AMPERE), flowAmpereTolerance(expectedFlow2)); + assertEquals(expectedFlow1, CommonTestData.getRaoResult().getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.AMPERE), flowAmpereTolerance(expectedFlow1)); + assertEquals(expectedFlow2, CommonTestData.getRaoResult().getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.AMPERE), flowAmpereTolerance(expectedFlow2)); } @Then("the flow on cnec {string} after CRA should be {double} A on side 1 and {double} A on side 2") public void afterCraFlowInA(String cnecId, Double expectedFlow1, Double expectedFlow2) { - assertEquals(expectedFlow1, raoResult.getFlow(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.AMPERE), flowAmpereTolerance(expectedFlow1)); - assertEquals(expectedFlow2, raoResult.getFlow(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.AMPERE), flowAmpereTolerance(expectedFlow2)); + assertEquals(expectedFlow1, CommonTestData.getRaoResult().getFlow(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.AMPERE), flowAmpereTolerance(expectedFlow1)); + assertEquals(expectedFlow2, CommonTestData.getRaoResult().getFlow(crac.getInstant(InstantKind.CURATIVE), crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.AMPERE), flowAmpereTolerance(expectedFlow2)); } @Then("the initial flow on cnec {string} should be {double} A on side {int}") public void initialFlowInABothSides(String cnecId, Double expectedFlow, Integer side) { - assertEquals(expectedFlow, raoResult.getFlow(null, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.AMPERE), flowAmpereTolerance(expectedFlow)); + assertEquals(expectedFlow, CommonTestData.getRaoResult().getFlow(null, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.AMPERE), flowAmpereTolerance(expectedFlow)); } @Then("the flow on cnec {string} after PRA should be {double} A on side {int}") public void afterPraFlowInABothSides(String cnecId, Double expectedFlow, Integer side) { - assertEquals(expectedFlow, raoResult.getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.AMPERE), flowAmpereTolerance(expectedFlow)); + assertEquals(expectedFlow, CommonTestData.getRaoResult().getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.AMPERE), flowAmpereTolerance(expectedFlow)); } @Then("the flow on cnec {string} after ARA should be {double} A on side {int}") public void afterAraFlowInABothSides(String cnecId, Double expectedFlow, Integer side) { - assertEquals(expectedFlow, raoResult.getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.AMPERE), flowAmpereTolerance(expectedFlow)); + assertEquals(expectedFlow, CommonTestData.getRaoResult().getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.AMPERE), flowAmpereTolerance(expectedFlow)); } @Then("the flow on cnec {string} after CRA should be {double} A on side {int}") @@ -559,13 +559,13 @@ public void afterCraFlowInABothSides(String cnecId, Double expectedFlow, Integer Instant lastCurativeInstant = crac.getInstants(InstantKind.CURATIVE).stream() .sorted(Comparator.comparingInt(instant -> -instant.getOrder())) .toList().get(0); - assertEquals(expectedFlow, raoResult.getFlow(lastCurativeInstant, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.AMPERE), flowAmpereTolerance(expectedFlow)); + assertEquals(expectedFlow, CommonTestData.getRaoResult().getFlow(lastCurativeInstant, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.AMPERE), flowAmpereTolerance(expectedFlow)); } @Then("the flow on cnec {string} after {string} instant remedial actions should be {double} A on side {int}") public void afterInstantFlowInABothSides(String cnecId, String instantId, Double expectedFlow, Integer side) { Instant instant = crac.getInstant(instantId); - assertEquals(expectedFlow, raoResult.getFlow(instant, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.AMPERE), flowAmpereTolerance(expectedFlow)); + assertEquals(expectedFlow, CommonTestData.getRaoResult().getFlow(instant, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.AMPERE), flowAmpereTolerance(expectedFlow)); } /* @@ -574,49 +574,49 @@ public void afterInstantFlowInABothSides(String cnecId, String instantId, Double @Then("the initial flow on cnec {string} should be {double} MW on side 1 and {double} MW on side 2") public void initialFlowInMW(String cnecId, Double expectedFlow1, Double expectedFlow2) { - assertEquals(expectedFlow1, raoResult.getFlow(null, crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow1)); - assertEquals(expectedFlow2, raoResult.getFlow(null, crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow2)); + assertEquals(expectedFlow1, CommonTestData.getRaoResult().getFlow(null, crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow1)); + assertEquals(expectedFlow2, CommonTestData.getRaoResult().getFlow(null, crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow2)); } @Then("the flow on cnec {string} after PRA should be {double} MW on side 1 and {double} MW on side 2") public void afterPraFlowInMW(String cnecId, Double expectedFlow1, Double expectedFlow2) { - assertEquals(expectedFlow1, raoResult.getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow1)); - assertEquals(expectedFlow2, raoResult.getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow2)); + assertEquals(expectedFlow1, CommonTestData.getRaoResult().getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow1)); + assertEquals(expectedFlow2, CommonTestData.getRaoResult().getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow2)); } @Then("the flow on cnec {string} after ARA should be {double} MW on side 1 and {double} MW on side 2") public void afterAraFlowInMW(String cnecId, Double expectedFlow1, Double expectedFlow2) { - assertEquals(expectedFlow1, raoResult.getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow1)); - assertEquals(expectedFlow2, raoResult.getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow2)); + assertEquals(expectedFlow1, CommonTestData.getRaoResult().getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow1)); + assertEquals(expectedFlow2, CommonTestData.getRaoResult().getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow2)); } @Then("the flow on cnec {string} after CRA should be {double} MW on side 1 and {double} MW on side 2") public void afterCraFlowInMW(String cnecId, Double expectedFlow1, Double expectedFlow2) { Instant lastCurativeInstant = crac.getInstants(InstantKind.CURATIVE).stream().sorted(Comparator.comparingInt(instant -> -instant.getOrder())).toList().get(0); - assertEquals(expectedFlow1, raoResult.getFlow(lastCurativeInstant, crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow1)); - assertEquals(expectedFlow2, raoResult.getFlow(lastCurativeInstant, crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow2)); + assertEquals(expectedFlow1, CommonTestData.getRaoResult().getFlow(lastCurativeInstant, crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow1)); + assertEquals(expectedFlow2, CommonTestData.getRaoResult().getFlow(lastCurativeInstant, crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow2)); } @Then("the flow on cnec {string} after {string} instant remedial actions should be {double} MW on side 1 and {double} MW on side 2") public void afterInstantFlowInMW(String cnecId, String instantId, Double expectedFlow1, Double expectedFlow2) { Instant instant = crac.getInstant(instantId); - assertEquals(expectedFlow1, raoResult.getFlow(instant, crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow1)); - assertEquals(expectedFlow2, raoResult.getFlow(instant, crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow2)); + assertEquals(expectedFlow1, CommonTestData.getRaoResult().getFlow(instant, crac.getFlowCnec(cnecId), TwoSides.ONE, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow1)); + assertEquals(expectedFlow2, CommonTestData.getRaoResult().getFlow(instant, crac.getFlowCnec(cnecId), TwoSides.TWO, Unit.MEGAWATT), flowMegawattTolerance(expectedFlow2)); } @Then("the initial flow on cnec {string} should be {double} MW on side {int}") public void initialFlowInMWBothSides(String cnecId, Double expectedFlow, Integer side) { - assertEquals(expectedFlow, raoResult.getFlow(null, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.MEGAWATT), flowMegawattTolerance(expectedFlow)); + assertEquals(expectedFlow, CommonTestData.getRaoResult().getFlow(null, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.MEGAWATT), flowMegawattTolerance(expectedFlow)); } @Then("the flow on cnec {string} after PRA should be {double} MW on side {int}") public void afterPraFlowInMWBothSides(String cnecId, Double expectedFlow, Integer side) { - assertEquals(expectedFlow, raoResult.getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.MEGAWATT), flowMegawattTolerance(expectedFlow)); + assertEquals(expectedFlow, CommonTestData.getRaoResult().getFlow(crac.getPreventiveInstant(), crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.MEGAWATT), flowMegawattTolerance(expectedFlow)); } @Then("the flow on cnec {string} after ARA should be {double} MW on side {int}") public void afterAraFlowInMWBothSides(String cnecId, Double expectedFlow, Integer side) { - assertEquals(expectedFlow, raoResult.getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.MEGAWATT), flowMegawattTolerance(expectedFlow)); + assertEquals(expectedFlow, CommonTestData.getRaoResult().getFlow(crac.getInstant(InstantKind.AUTO), crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.MEGAWATT), flowMegawattTolerance(expectedFlow)); } @Then("the flow on cnec {string} after CRA should be {double} MW on side {int}") @@ -624,13 +624,13 @@ public void afterCraFlowInMWBothSides(String cnecId, Double expectedFlow, Intege Instant lastCurativeInstant = crac.getInstants(InstantKind.CURATIVE).stream() .sorted(Comparator.comparingInt(instant -> -instant.getOrder())) .toList().get(0); - assertEquals(expectedFlow, raoResult.getFlow(lastCurativeInstant, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.MEGAWATT), flowMegawattTolerance(expectedFlow)); + assertEquals(expectedFlow, CommonTestData.getRaoResult().getFlow(lastCurativeInstant, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.MEGAWATT), flowMegawattTolerance(expectedFlow)); } @Then("the flow on cnec {string} after {string} instant remedial actions should be {double} MW on side {int}") public void afterInstantFlowInMWBothSides(String cnecId, String instantId, Double expectedFlow, Integer side) { Instant instant = crac.getInstant(instantId); - assertEquals(expectedFlow, raoResult.getFlow(instant, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.MEGAWATT), flowMegawattTolerance(expectedFlow)); + assertEquals(expectedFlow, CommonTestData.getRaoResult().getFlow(instant, crac.getFlowCnec(cnecId), getTwoSideFromInteger(side), Unit.MEGAWATT), flowMegawattTolerance(expectedFlow)); } /* @@ -733,13 +733,13 @@ public void loopflowThresholdInMW(String cnecId, Double expectedFlow) { @Then("the absolute PTDF sum on cnec {string} initially should be {double}") public void absPtdfSum(String cnecId, Double expectedPtdfSum) { FlowCnec cnec = crac.getFlowCnec(cnecId); - assertEquals(expectedPtdfSum, raoResult.getPtdfZonalSum(null, cnec, cnec.getMonitoredSides().iterator().next()), TOLERANCE_PTDF); + assertEquals(expectedPtdfSum, CommonTestData.getRaoResult().getPtdfZonalSum(null, cnec, cnec.getMonitoredSides().iterator().next()), TOLERANCE_PTDF); } @Then("the absolute PTDF sum on cnec {string} after {string} should be {double}") public void absPtdfSumAfterInstant(String cnecId, String instantKind, Double expectedPtdfSum) { FlowCnec cnec = crac.getFlowCnec(cnecId); - assertEquals(expectedPtdfSum, raoResult.getPtdfZonalSum(crac.getInstant(InstantKind.valueOf(instantKind.toUpperCase())), cnec, cnec.getMonitoredSides().iterator().next()), TOLERANCE_PTDF); + assertEquals(expectedPtdfSum, CommonTestData.getRaoResult().getPtdfZonalSum(crac.getInstant(InstantKind.valueOf(instantKind.toUpperCase())), cnec, cnec.getMonitoredSides().iterator().next()), TOLERANCE_PTDF); } private void launchRao(int timeLimit) { @@ -834,6 +834,6 @@ private Pair getWorstCnec(Unit unit, boolean relative) { @Then("the execution details should be {string}") public void getOptimizationSteps(String string) { - assertEquals(string, raoResult.getExecutionDetails()); + assertEquals(string, CommonTestData.getRaoResult().getExecutionDetails()); } } From 16e4120539d401ed406497107541cc5b1c0bed70 Mon Sep 17 00:00:00 2001 From: Thomas Bouquet Date: Fri, 20 Mar 2026 16:03:42 +0100 Subject: [PATCH 5/7] fix validate Signed-off-by: Thomas Bouquet --- .../searchtreerao/castor/algorithm/CastorFullOptimization.java | 1 - 1 file changed, 1 deletion(-) diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java index ec0096c7dd..faf3ca4027 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java @@ -8,7 +8,6 @@ package com.powsybl.openrao.searchtreerao.castor.algorithm; import com.powsybl.iidm.network.Network; -import com.powsybl.openrao.commons.OpenRaoException; import com.powsybl.openrao.data.crac.api.Crac; import com.powsybl.openrao.data.crac.api.Instant; import com.powsybl.openrao.data.crac.api.State; From ecff72efdd7a2c3d5819ef1c8e62e2d48c110406 Mon Sep 17 00:00:00 2001 From: Thomas Bouquet Date: Fri, 20 Mar 2026 16:24:47 +0100 Subject: [PATCH 6/7] move unit tests Signed-off-by: Thomas Bouquet --- pst-regulation/pom.xml | 55 +++- .../ElementaryPstRegulationInputTest.java | 2 +- .../pstregulation/PstRegulationTest.java | 25 +- .../pstregulation/PstRegulatorTest.java | 2 +- .../crac-3-psts-monitored-line-in-series.json | 0 .../src/test/resources/crac/crac-3-psts.json | 0 .../resources/crac/crac-for-regulation.json | 0 .../resources/crac/crac-regulation-1-PST.json | 0 .../network/2Nodes2ParallelLinesPST.uct | 12 + .../network/2Nodes4ParallelLines3PSTs.uct | 0 .../test/resources/network/4NodesSeries.uct | 0 .../RaoParameters_ac_3pstsRegulation.json | 0 .../raoResult/raoResultPreRegulation.json | 0 .../algorithm/CastorFullOptimization.java | 82 ----- .../pstregulation/CastorPstRegulation.java | 302 ------------------ .../ElementaryPstRegulationInput.java | 109 ------- .../pstregulation/PstRegulationInput.java | 19 -- .../pstregulation/PstRegulationResult.java | 19 -- .../algorithm/pstregulation/PstRegulator.java | 85 ----- 19 files changed, 74 insertions(+), 638 deletions(-) rename {ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm => pst-regulation/src/test/java/com/powsybl/openrao}/pstregulation/ElementaryPstRegulationInputTest.java (98%) rename ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulationTest.java => pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/PstRegulationTest.java (80%) rename {ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm => pst-regulation/src/test/java/com/powsybl/openrao}/pstregulation/PstRegulatorTest.java (97%) rename {ra-optimisation/search-tree-rao => pst-regulation}/src/test/resources/crac/crac-3-psts-monitored-line-in-series.json (100%) rename {ra-optimisation/search-tree-rao => pst-regulation}/src/test/resources/crac/crac-3-psts.json (100%) rename {ra-optimisation/search-tree-rao => pst-regulation}/src/test/resources/crac/crac-for-regulation.json (100%) rename {ra-optimisation/search-tree-rao => pst-regulation}/src/test/resources/crac/crac-regulation-1-PST.json (100%) create mode 100644 pst-regulation/src/test/resources/network/2Nodes2ParallelLinesPST.uct rename {ra-optimisation/search-tree-rao => pst-regulation}/src/test/resources/network/2Nodes4ParallelLines3PSTs.uct (100%) rename {ra-optimisation/search-tree-rao => pst-regulation}/src/test/resources/network/4NodesSeries.uct (100%) rename {ra-optimisation/search-tree-rao => pst-regulation}/src/test/resources/parameters/RaoParameters_ac_3pstsRegulation.json (100%) rename {ra-optimisation/search-tree-rao => pst-regulation}/src/test/resources/raoResult/raoResultPreRegulation.json (100%) delete mode 100644 ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulation.java delete mode 100644 ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/ElementaryPstRegulationInput.java delete mode 100644 ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulationInput.java delete mode 100644 ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulationResult.java delete mode 100644 ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulator.java diff --git a/pst-regulation/pom.xml b/pst-regulation/pom.xml index 77dfc0ef8c..e5c58028d2 100644 --- a/pst-regulation/pom.xml +++ b/pst-regulation/pom.xml @@ -26,12 +26,14 @@ ${project.version} - com.powsybl + ${project.groupId} open-rao-rao-api + ${project.version} - com.powsybl + ${project.groupId} open-rao-util + ${project.version} com.powsybl @@ -39,12 +41,57 @@ compile - com.powsybl + ${project.groupId} open-rao-sensitivity-analysis + ${project.version} - com.powsybl + ${project.groupId} open-rao-search-tree-rao + ${project.version} + + + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-core + test + + + ch.qos.logback + logback-core + 1.5.32 + test + + + ch.qos.logback + logback-classic + + + com.powsybl + powsybl-config-test + test + + + com.powsybl + powsybl-commons-test + ${powsybl.core.version} + test + + + com.powsybl + powsybl-iidm-impl + test + + + com.powsybl + powsybl-ucte-converter + test diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/ElementaryPstRegulationInputTest.java b/pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/ElementaryPstRegulationInputTest.java similarity index 98% rename from ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/ElementaryPstRegulationInputTest.java rename to pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/ElementaryPstRegulationInputTest.java index 15b6bc3bd0..d219e758cc 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/ElementaryPstRegulationInputTest.java +++ b/pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/ElementaryPstRegulationInputTest.java @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package com.powsybl.openrao.searchtreerao.castor.algorithm.pstregulation; +package com.powsybl.openrao.pstregulation; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.TwoSides; diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulationTest.java b/pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/PstRegulationTest.java similarity index 80% rename from ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulationTest.java rename to pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/PstRegulationTest.java index 7bd5fe44e1..d4443283d8 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulationTest.java +++ b/pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/PstRegulationTest.java @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package com.powsybl.openrao.searchtreerao.castor.algorithm.pstregulation; +package com.powsybl.openrao.pstregulation; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; @@ -37,7 +37,7 @@ /** * @author Thomas Bouquet {@literal } */ -class CastorPstRegulationTest { +class PstRegulationTest { @Test void testPstRegulationWithSeveralContingencyScenarios() throws IOException { Network network = Network.read("4NodesSeries.uct", getClass().getResourceAsStream("/network/4NodesSeries.uct")); @@ -68,12 +68,7 @@ void testPstRegulationWithSeveralContingencyScenarios() throws IOException { ListAppender listAppender = getBusinessLogs(); List logsList = listAppender.list; - Map pstsToRegulate = Map.of( - "FFR1AA1 FFR2AA1 2", "FFR1AA1 FFR2AA1 2", - "FFR2AA1 FFR3AA1 2", "FFR2AA1 FFR3AA1 2", - "FFR3AA1 FFR4AA1 2", "FFR3AA1 FFR4AA1 2" - ); - Set pstRegulationResults = CastorPstRegulation.regulatePsts(pstsToRegulate, postContingencyResults, network, crac, raoParameters, raoResult); + RaoResult raoResultWithPstRegulation = PstRegulation.regulatePsts(network, crac, raoResult, raoParameters); List logMessages = logsList.stream().map(ILoggingEvent::getFormattedMessage).sorted().toList(); assertEquals("2 PST(s) to regulate: pstFr12, pstFr34", logMessages.get(0)); @@ -82,11 +77,9 @@ void testPstRegulationWithSeveralContingencyScenarios() throws IOException { // PST FR2-FR3 is only preventive so it cannot be regulated assertEquals("PST FFR2AA1 FFR3AA1 2 cannot be regulated as no curative PST range action was defined for it.", logMessages.get(5)); - assertEquals(3, pstRegulationResults.size()); - // Contingency FR1-FR2 - PstRegulationResult pstRegulationResultCoFr12 = getPstRegulationResultForGivenContingency(pstRegulationResults, "Contingency FR 12"); - assertEquals(Map.of(pst12, -15, pst34, -5), pstRegulationResultCoFr12.regulatedTapPerPst()); + assertEquals(-15, raoResultWithPstRegulation.getOptimizedTapOnState(crac.getState("Contingency FR 12", crac.getLastInstant()), pst12)); + assertEquals(-5, raoResultWithPstRegulation.getOptimizedTapOnState(crac.getState("Contingency FR 12", crac.getLastInstant()), pst34)); assertEquals( "FlowCNEC 'cnecFr34PstCurative - Co12' of contingency scenario 'Contingency FR 12' is overloaded and is the most limiting element, " + "PST regulation has been triggered: pstFr12 (-10 -> -15), pstFr34 (0 -> -5)", @@ -94,8 +87,8 @@ void testPstRegulationWithSeveralContingencyScenarios() throws IOException { ); // Contingency FR2-FR3 - PstRegulationResult pstRegulationResultCoFr23 = getPstRegulationResultForGivenContingency(pstRegulationResults, "Contingency FR 23"); - assertEquals(Map.of(pst12, -5, pst34, -5), pstRegulationResultCoFr23.regulatedTapPerPst()); + assertEquals(-5, raoResultWithPstRegulation.getOptimizedTapOnState(crac.getState("Contingency FR 23", crac.getLastInstant()), pst12)); + assertEquals(-5, raoResultWithPstRegulation.getOptimizedTapOnState(crac.getState("Contingency FR 23", crac.getLastInstant()), pst34)); assertEquals( "FlowCNEC 'cnecFr23PstCurative - Co23' of contingency scenario 'Contingency FR 23' is overloaded and is the most limiting element, " + "PST regulation has been triggered: pstFr12 (0 -> -5), pstFr34 (0 -> -5)", @@ -103,8 +96,8 @@ void testPstRegulationWithSeveralContingencyScenarios() throws IOException { ); // Contingency FR3-FR4 - PstRegulationResult pstRegulationResultCoFr34 = getPstRegulationResultForGivenContingency(pstRegulationResults, "Contingency FR 34"); - assertEquals(Map.of(pst12, -5, pst34, -15), pstRegulationResultCoFr34.regulatedTapPerPst()); + assertEquals(-5, raoResultWithPstRegulation.getOptimizedTapOnState(crac.getState("Contingency FR 34", crac.getLastInstant()), pst12)); + assertEquals(-15, raoResultWithPstRegulation.getOptimizedTapOnState(crac.getState("Contingency FR 34", crac.getLastInstant()), pst34)); assertEquals( "FlowCNEC 'cnecFr12PstCurative - Co34' of contingency scenario 'Contingency FR 34' is overloaded and is the most limiting element, " + "PST regulation has been triggered: pstFr12 (0 -> -5)", diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulatorTest.java b/pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/PstRegulatorTest.java similarity index 97% rename from ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulatorTest.java rename to pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/PstRegulatorTest.java index 12451c7685..0b6e46499f 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulatorTest.java +++ b/pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/PstRegulatorTest.java @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package com.powsybl.openrao.searchtreerao.castor.algorithm.pstregulation; +package com.powsybl.openrao.pstregulation; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.TwoSides; diff --git a/ra-optimisation/search-tree-rao/src/test/resources/crac/crac-3-psts-monitored-line-in-series.json b/pst-regulation/src/test/resources/crac/crac-3-psts-monitored-line-in-series.json similarity index 100% rename from ra-optimisation/search-tree-rao/src/test/resources/crac/crac-3-psts-monitored-line-in-series.json rename to pst-regulation/src/test/resources/crac/crac-3-psts-monitored-line-in-series.json diff --git a/ra-optimisation/search-tree-rao/src/test/resources/crac/crac-3-psts.json b/pst-regulation/src/test/resources/crac/crac-3-psts.json similarity index 100% rename from ra-optimisation/search-tree-rao/src/test/resources/crac/crac-3-psts.json rename to pst-regulation/src/test/resources/crac/crac-3-psts.json diff --git a/ra-optimisation/search-tree-rao/src/test/resources/crac/crac-for-regulation.json b/pst-regulation/src/test/resources/crac/crac-for-regulation.json similarity index 100% rename from ra-optimisation/search-tree-rao/src/test/resources/crac/crac-for-regulation.json rename to pst-regulation/src/test/resources/crac/crac-for-regulation.json diff --git a/ra-optimisation/search-tree-rao/src/test/resources/crac/crac-regulation-1-PST.json b/pst-regulation/src/test/resources/crac/crac-regulation-1-PST.json similarity index 100% rename from ra-optimisation/search-tree-rao/src/test/resources/crac/crac-regulation-1-PST.json rename to pst-regulation/src/test/resources/crac/crac-regulation-1-PST.json diff --git a/pst-regulation/src/test/resources/network/2Nodes2ParallelLinesPST.uct b/pst-regulation/src/test/resources/network/2Nodes2ParallelLinesPST.uct new file mode 100644 index 0000000000..49add21201 --- /dev/null +++ b/pst-regulation/src/test/resources/network/2Nodes2ParallelLinesPST.uct @@ -0,0 +1,12 @@ +##C 2007.05.01 +##N +##ZBE +BBE1AA1 BE1 0 2 400.00 0.00000 0.00000 -1000.0 0.00000 9000.00 -9000.0 9000.00 -9000.0 +##ZFR +FFR1AA1 FR1 0 2 400.00 1000.00 0.00000 00000.0 0.00000 9000.00 -9000.0 9000.00 -9000.0 +##L +BBE1AA1 FFR1AA1 1 0 0.0000 10.000 0.000000 5000 +##T +BBE1AA1 FFR1AA1 2 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 500 PST +##R +BBE1AA1 FFR1AA1 2 -0.68 90.00 16 0 SYMM diff --git a/ra-optimisation/search-tree-rao/src/test/resources/network/2Nodes4ParallelLines3PSTs.uct b/pst-regulation/src/test/resources/network/2Nodes4ParallelLines3PSTs.uct similarity index 100% rename from ra-optimisation/search-tree-rao/src/test/resources/network/2Nodes4ParallelLines3PSTs.uct rename to pst-regulation/src/test/resources/network/2Nodes4ParallelLines3PSTs.uct diff --git a/ra-optimisation/search-tree-rao/src/test/resources/network/4NodesSeries.uct b/pst-regulation/src/test/resources/network/4NodesSeries.uct similarity index 100% rename from ra-optimisation/search-tree-rao/src/test/resources/network/4NodesSeries.uct rename to pst-regulation/src/test/resources/network/4NodesSeries.uct diff --git a/ra-optimisation/search-tree-rao/src/test/resources/parameters/RaoParameters_ac_3pstsRegulation.json b/pst-regulation/src/test/resources/parameters/RaoParameters_ac_3pstsRegulation.json similarity index 100% rename from ra-optimisation/search-tree-rao/src/test/resources/parameters/RaoParameters_ac_3pstsRegulation.json rename to pst-regulation/src/test/resources/parameters/RaoParameters_ac_3pstsRegulation.json diff --git a/ra-optimisation/search-tree-rao/src/test/resources/raoResult/raoResultPreRegulation.json b/pst-regulation/src/test/resources/raoResult/raoResultPreRegulation.json similarity index 100% rename from ra-optimisation/search-tree-rao/src/test/resources/raoResult/raoResultPreRegulation.json rename to pst-regulation/src/test/resources/raoResult/raoResultPreRegulation.json diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java index faf3ca4027..56aeefa6fe 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java @@ -12,7 +12,6 @@ import com.powsybl.openrao.data.crac.api.Instant; import com.powsybl.openrao.data.crac.api.State; import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; -import com.powsybl.openrao.data.crac.api.networkaction.NetworkAction; import com.powsybl.openrao.data.crac.api.rangeaction.RangeAction; import com.powsybl.openrao.data.raoresult.api.ComputationStatus; import com.powsybl.openrao.data.raoresult.api.OptimizationStepsExecuted; @@ -22,7 +21,6 @@ import com.powsybl.openrao.raoapi.parameters.RaoParameters; import com.powsybl.openrao.raoapi.parameters.extensions.LoadFlowAndSensitivityParameters; import com.powsybl.openrao.raoapi.parameters.extensions.OpenRaoSearchTreeParameters; -import com.powsybl.openrao.searchtreerao.castor.algorithm.pstregulation.PstRegulationResult; import com.powsybl.openrao.searchtreerao.commons.RaoLogger; import com.powsybl.openrao.searchtreerao.commons.RaoUtil; import com.powsybl.openrao.searchtreerao.commons.ToolProvider; @@ -30,16 +28,12 @@ import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.PreventiveOptimizationPerimeter; import com.powsybl.openrao.searchtreerao.commons.parameters.TreeParameters; import com.powsybl.openrao.searchtreerao.commons.parameters.UnoptimizedCnecParameters; -import com.powsybl.openrao.searchtreerao.result.api.FlowResult; import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; import com.powsybl.openrao.searchtreerao.result.api.PrePerimeterResult; import com.powsybl.openrao.searchtreerao.result.impl.FailedRaoResultImpl; -import com.powsybl.openrao.searchtreerao.result.impl.NetworkActionsResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.OneStateOnlyRaoResultImpl; -import com.powsybl.openrao.searchtreerao.result.impl.OptimizationResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.PostPerimeterResult; import com.powsybl.openrao.searchtreerao.result.impl.PreventiveAndCurativesRaoResultImpl; -import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.RemedialActionActivationResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.UnoptimizedRaoResultImpl; import com.powsybl.openrao.searchtreerao.searchtree.algorithms.SearchTree; @@ -56,7 +50,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_LOGS; import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS; @@ -421,81 +414,6 @@ private Pair> optimizePreventivePerimeter(Stat return Pair.of(optResult, optPerimeter.getFlowCnecs()); } - private Map mergeRaoAndPstRegulationResults(Set pstRegulationResults, - PostPerimeterResult postPraResult, - Map postContingencyResults, - PrePerimeterSensitivityAnalysis prePerimeterSensitivityAnalysis, - FlowResult initialFlowResult, - ToolProvider toolProvider) { - // create a new network variant from initial variant for performing the results merging - String variantName = "PSTRegulationResultsMerging"; - network.getVariantManager().setWorkingVariant(INITIAL_SCENARIO); - network.getVariantManager().cloneVariant(INITIAL_SCENARIO, variantName); - network.getVariantManager().setWorkingVariant(variantName); - - // apply PRAs - applyRemedialActions(network, postPraResult.optimizationResult(), crac.getPreventiveState()); - - Set regulatedStates = pstRegulationResults.stream() - .map(pstRegulationResult -> crac.getState(pstRegulationResult.contingency().getId(), crac.getLastInstant())) - .collect(Collectors.toSet()); - Map> appliedNetworkActions = new HashMap<>(); - - // gather all applied ARAs and CRAs - AppliedRemedialActions appliedRemedialActions = new AppliedRemedialActions(); - postContingencyResults.forEach((state, postPerimeterResult) -> { - appliedNetworkActions.put(state, postPerimeterResult.optimizationResult().getActivatedNetworkActions()); - appliedRemedialActions.addAppliedNetworkActions(state, postPerimeterResult.optimizationResult().getActivatedNetworkActions()); - appliedRemedialActions.addAppliedRangeActions(state, getAppliedRangeActionsAndSetPoint(state, postPraResult.optimizationResult())); - appliedRemedialActions.addAppliedRangeActions(state, getAppliedRangeActionsAndSetPoint(state, postPerimeterResult.optimizationResult())); - }); - - // overwrite PST range action results for regulated PSTs - pstRegulationResults.forEach(pstRegulationResult -> - pstRegulationResult.regulatedTapPerPst().forEach((pstRangeAction, regulatedTap) -> - appliedRemedialActions.addAppliedRangeAction( - crac.getState(pstRegulationResult.contingency().getId(), crac.getLastInstant()), - pstRangeAction, - pstRangeAction.convertTapToAngle(regulatedTap) - ) - ) - ); - - PrePerimeterResult postCraSensitivityAnalysisOutput = prePerimeterSensitivityAnalysis.runBasedOnInitialResults(network, initialFlowResult, Collections.emptySet(), appliedRemedialActions); - - Map postRegulationPostContingencyResults = new HashMap<>(); - - // override optimization result - RangeActionActivationResultImpl postRegulationRangeActionActivationResult = new RangeActionActivationResultImpl(postCraSensitivityAnalysisOutput); - postContingencyResults.keySet().forEach(state -> - appliedRemedialActions.getAppliedRangeActions(state).forEach((rangeAction, setPoint) -> - postRegulationRangeActionActivationResult.putResult(rangeAction, state, setPoint) - ) - ); - OptimizationResult newOptimizationResult = new OptimizationResultImpl( - postCraSensitivityAnalysisOutput, - postCraSensitivityAnalysisOutput, - postCraSensitivityAnalysisOutput, - new NetworkActionsResultImpl(appliedNetworkActions), - postRegulationRangeActionActivationResult - ); - - for (State state : postContingencyResults.keySet()) { - // For instants before pst regulation instant, keep previous results - if (state.getInstant().comesBefore(crac.getLastInstant())) { - postRegulationPostContingencyResults.put(state, postContingencyResults.get(state)); - } else { - // For curative instant, update regulatedStates with newly computed sensi result - postRegulationPostContingencyResults.put(state, new PostPerimeterResult( - regulatedStates.contains(state) ? newOptimizationResult : postContingencyResults.get(state).optimizationResult(), - postCraSensitivityAnalysisOutput - )); - } - } - - return postRegulationPostContingencyResults; - } - private static Map, Double> getAppliedRangeActionsAndSetPoint(State state, OptimizationResult optimizationResult) { Map, Double> optimizedRangeActions = new HashMap<>(); optimizationResult.getActivatedRangeActions(state).forEach(rangeAction -> optimizedRangeActions.put(rangeAction, optimizationResult.getOptimizedSetpoint(rangeAction, state))); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulation.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulation.java deleted file mode 100644 index 3cbfe2d52b..0000000000 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/CastorPstRegulation.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (c) 2025, 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.openrao.searchtreerao.castor.algorithm.pstregulation; - -import com.powsybl.contingency.Contingency; -import com.powsybl.iidm.network.Network; -import com.powsybl.loadflow.LoadFlowParameters; -import com.powsybl.openloadflow.OpenLoadFlowParameters; -import com.powsybl.openrao.commons.OpenRaoException; -import com.powsybl.openrao.commons.Unit; -import com.powsybl.openrao.data.crac.api.Crac; -import com.powsybl.openrao.data.crac.api.Identifiable; -import com.powsybl.openrao.data.crac.api.Instant; -import com.powsybl.openrao.data.crac.api.State; -import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; -import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; -import com.powsybl.openrao.data.raoresult.api.RaoResult; -import com.powsybl.openrao.raoapi.parameters.RaoParameters; -import com.powsybl.openrao.raoapi.parameters.extensions.OpenRaoSearchTreeParameters; -import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoPstRegulationParameters; -import com.powsybl.openrao.searchtreerao.result.impl.PostPerimeterResult; -import com.powsybl.openrao.searchtreerao.result.impl.SkippedOptimizationResultImpl; -import com.powsybl.openrao.util.AbstractNetworkPool; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ForkJoinTask; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_LOGS; -import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_WARNS; -import static com.powsybl.openrao.raoapi.parameters.extensions.MultithreadingParameters.getAvailableCPUs; -import static com.powsybl.openrao.searchtreerao.commons.RaoUtil.getFlowUnit; - -/** - * @author Thomas Bouquet {@literal } - */ -public final class CastorPstRegulation { - private CastorPstRegulation() { - } - - public static Set regulatePsts(Map pstsToRegulate, - Map postContingencyResults, - Network network, - Crac crac, - RaoParameters raoParameters, - RaoResult raoResult) { - // filter out non-curative PSTs - // currently, only PSTs with a usage rule for a given state are regulated - Set rangeActionsToRegulate = getPstRangeActionsForRegulation(pstsToRegulate.keySet(), crac); - if (rangeActionsToRegulate.isEmpty()) { - return Set.of(); - } - - Set statesToRegulate = getStatesToRegulate( - crac, - postContingencyResults, - getFlowUnit(raoParameters), - rangeActionsToRegulate, - SearchTreeRaoPstRegulationParameters.getPstsToRegulate(raoParameters), - network - ); - if (statesToRegulate.isEmpty()) { - return Set.of(); - } - - Set contingencies = statesToRegulate.stream() - .map(PstRegulationInput::curativeState) - .map(State::getContingency) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toSet()); - BUSINESS_LOGS.info( - "{} contingency scenario(s) to regulate: {}", - contingencies.size(), - String.join(", ", contingencies.stream() - .map(contingency -> contingency.getName().orElse(contingency.getId())) - .sorted() - .toList() - ) - ); - BUSINESS_LOGS.info("{} PST(s) to regulate: {}", rangeActionsToRegulate.size(), String.join(", ", rangeActionsToRegulate.stream().map(PstRangeAction::getName).sorted().toList())); - - // update loadflow parameters - LoadFlowParameters loadFlowParameters = getLoadFlowParameters(raoParameters); - boolean initialPhaseShifterRegulationOnValue = loadFlowParameters.isPhaseShifterRegulationOn(); - updateLoadFlowParametersForPstRegulation(loadFlowParameters); - - // apply optimal preventive remedial actions - applyOptimalRemedialActionsForState(network, raoResult, crac.getPreventiveState()); - - // regulate PSTs for each curative scenario in parallel - try (AbstractNetworkPool networkPool = AbstractNetworkPool.create(network, network.getVariantManager().getWorkingVariantId(), getNumberOfThreads(crac, raoParameters), true)) { - List> tasks = statesToRegulate.stream().map(pstRegulationInput -> - networkPool.submit(() -> regulatePstsForContingencyScenario(pstRegulationInput, crac, rangeActionsToRegulate, raoResult, loadFlowParameters, networkPool)) - ).toList(); - Set pstRegulationResults = new HashSet<>(); - for (ForkJoinTask task : tasks) { - try { - pstRegulationResults.add(task.get()); - } catch (ExecutionException e) { - throw new OpenRaoException(e); - } - } - networkPool.shutdownAndAwaitTermination(1000, TimeUnit.SECONDS); - return pstRegulationResults; - } catch (OpenRaoException | InterruptedException e) { - Thread.currentThread().interrupt(); - BUSINESS_WARNS.warn("An error occurred during PST regulation, pre-regulation RAO result will be kept."); - return Set.of(); - } finally { - loadFlowParameters.setPhaseShifterRegulationOn(initialPhaseShifterRegulationOnValue); - } - } - - /** - * Determines the states for which PST regulation must be applied. There are two conditions: - *
    - *
  1. the state must be unsecure;
  2. - *
  3. the limiting elements must be in series with a regulated PST.
  4. - *
- * For all such states, the associated PST regulation input is included in a set that is returned. - */ - private static Set getStatesToRegulate(Crac crac, - Map postContingencyResults, - Unit unit, - Set rangeActionsToRegulate, - Map linesInSeriesWithPst, - Network network) { - Instant lastInstant = crac.getLastInstant(); - return lastInstant.isCurative() ? - crac.getStates(lastInstant).stream() - .filter(postContingencyResults::containsKey) - .filter(curativeState -> !(postContingencyResults.get(curativeState).optimizationResult() instanceof SkippedOptimizationResultImpl)) - .map(curativeState -> getPstRegulationInput(curativeState, crac, postContingencyResults.get(curativeState), unit, rangeActionsToRegulate, linesInSeriesWithPst, network)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toSet()) - : Set.of(); - } - - private static Optional getPstRegulationInput(State curativeState, - Crac crac, - PostPerimeterResult postPerimeterResult, - Unit unit, - Set rangeActionsToRegulate, - Map linesInSeriesWithPst, - Network network) { - Optional limitingElement = getMostLimitingElementProtectedByPst(curativeState, crac, postPerimeterResult, unit, new HashSet<>(linesInSeriesWithPst.values())); - if (limitingElement.isPresent()) { - Set elementaryPstRegulationInputs = rangeActionsToRegulate.stream() - .filter(pstRangeAction -> linesInSeriesWithPst.containsKey(pstRangeAction.getNetworkElement().getId())) - .map(pstRangeAction -> ElementaryPstRegulationInput.of(pstRangeAction, linesInSeriesWithPst.get(pstRangeAction.getNetworkElement().getId()), curativeState, crac, network)) - .collect(Collectors.toSet()); - return Optional.of(new PstRegulationInput(curativeState, limitingElement.get(), elementaryPstRegulationInputs)); - } - return Optional.empty(); - } - - /** - * If the most limiting element of a curative state is overloaded and is in series with a PST, it is returned. - * If not, an empty optional value is returned instead. - */ - private static Optional getMostLimitingElementProtectedByPst(State curativeState, Crac crac, PostPerimeterResult postPerimeterResult, Unit unit, Set linesInSeriesWithPst) { - Map marginPerCnec = crac.getFlowCnecs(curativeState).stream() - .collect(Collectors.toMap( - Function.identity(), - flowCnec -> postPerimeterResult.optimizationResult().getMargin(flowCnec, unit) - )); - List> sortedNegativeMargins = marginPerCnec.entrySet().stream() - .filter(entry -> entry.getValue() < 0) - .sorted(Map.Entry.comparingByValue()).toList(); - if (sortedNegativeMargins.isEmpty()) { - return Optional.empty(); - } - double minMargin = sortedNegativeMargins.get(0).getValue(); - Set limitingElements = new HashSet<>(); - sortedNegativeMargins.stream().filter(entry -> entry.getValue() == minMargin).forEach(entry -> limitingElements.add(entry.getKey())); - return limitingElements.stream() - .filter(flowCnec -> linesInSeriesWithPst.contains(flowCnec.getNetworkElement().getId())) - .min(Comparator.comparing(Identifiable::getId)); - } - - private static LoadFlowParameters getLoadFlowParameters(RaoParameters raoParameters) { - return raoParameters.hasExtension(OpenRaoSearchTreeParameters.class) ? - raoParameters.getExtension(OpenRaoSearchTreeParameters.class).getLoadFlowAndSensitivityParameters().getSensitivityWithLoadFlowParameters().getLoadFlowParameters() : - new LoadFlowParameters(); - } - - private static void updateLoadFlowParametersForPstRegulation(LoadFlowParameters loadFlowParameters) { - loadFlowParameters.setPhaseShifterRegulationOn(true); - if (loadFlowParameters.getExtension(OpenLoadFlowParameters.class) == null) { - loadFlowParameters.addExtension(OpenLoadFlowParameters.class, new OpenLoadFlowParameters()); - } - loadFlowParameters.getExtension(OpenLoadFlowParameters.class).setMaxOuterLoopIterations(1000); - } - - private static void applyOptimalRemedialActionsForState(Network networkClone, RaoResult raoResult, State state) { - // network actions need to be applied BEFORE range actions because to apply HVDC range actions we need to apply AC emulation deactivation network actions beforehand - raoResult.getActivatedNetworkActionsDuringState(state).forEach(networkAction -> networkAction.apply(networkClone)); - raoResult.getActivatedRangeActionsDuringState(state).forEach(rangeAction -> rangeAction.apply(networkClone, raoResult.getOptimizedSetPointOnState(state, rangeAction))); - } - - private static Set getPstRangeActionsForRegulation(Set pstsToRegulate, Crac crac) { - Map rangeActionPerPst = getRangeActionPerPst(pstsToRegulate, crac); - Set rangeActionsToRegulate = new HashSet<>(); - for (String pstId : pstsToRegulate) { - if (rangeActionPerPst.containsKey(pstId)) { - rangeActionsToRegulate.add(rangeActionPerPst.get(pstId)); - } else { - BUSINESS_LOGS.info("PST {} cannot be regulated as no curative PST range action was defined for it.", pstId); - } - } - return rangeActionsToRegulate; - } - - private static Map getRangeActionPerPst(Set pstsToRegulate, Crac crac) { - // filter out crac's last instant range actions, as results reporting would be less relevant - return crac.getPstRangeActions().stream() - .filter(pstRangeAction -> pstRangeAction.getUsageRules().stream().anyMatch(usageRule -> usageRule.getInstant() == crac.getLastInstant())) - .filter(pstRangeAction -> pstsToRegulate.contains(pstRangeAction.getNetworkElement().getId())) - .collect(Collectors.toMap(pstRangeAction -> pstRangeAction.getNetworkElement().getId(), Function.identity())); - } - - private static int getNumberOfThreads(Crac crac, RaoParameters raoParameters) { - return Math.min(getAvailableCPUs(raoParameters), crac.getContingencies().size()); - } - - /** - * Performs PST regulation for a curative state. The taps are changed during the loadflow iterations. - */ - private static PstRegulationResult regulatePstsForContingencyScenario(PstRegulationInput pstRegulationInput, - Crac crac, - Set rangeActionsToRegulate, - RaoResult raoResult, - LoadFlowParameters loadFlowParameters, - AbstractNetworkPool networkPool) throws InterruptedException { - Network networkClone = networkPool.getAvailableNetwork(); - Contingency contingency = pstRegulationInput.curativeState().getContingency().orElseThrow(); - simulateContingencyAndApplyCurativeActions(contingency, networkClone, crac, raoResult); - Map initialTapPerPst = getInitialTapPerPst(rangeActionsToRegulate, networkClone); - Map regulatedTapPerPst = PstRegulator.regulatePsts(pstRegulationInput.elementaryPstRegulationInputs(), networkClone, loadFlowParameters); - logPstRegulationResultsForContingencyScenario(contingency, initialTapPerPst, regulatedTapPerPst, pstRegulationInput.limitingElement()); - networkPool.releaseUsedNetwork(networkClone); - return new PstRegulationResult(contingency, regulatedTapPerPst); - } - - private static void simulateContingencyAndApplyCurativeActions(Contingency contingency, Network networkClone, Crac crac, RaoResult raoResult) { - // simulate contingency - contingency.toModification().apply(networkClone); - - // apply optimal automatons and curative remedial actions - crac.getStates(contingency).stream() - .filter(state -> !state.getInstant().isOutage()) - .forEach(state -> applyOptimalRemedialActionsForState(networkClone, raoResult, state)); - } - - private static Map getInitialTapPerPst(Set rangeActionsToRegulate, Network networkClone) { - return rangeActionsToRegulate.stream() - .collect(Collectors.toMap( - Function.identity(), - pstRangeAction -> networkClone.getTwoWindingsTransformer(pstRangeAction.getNetworkElement().getId()).getPhaseTapChanger().getTapPosition() - )); - } - - private static void logPstRegulationResultsForContingencyScenario(Contingency contingency, - Map initialTapPerPst, - Map regulatedTapPerPst, - FlowCnec mostLimitingElement) { - List sortedPstRangeActions = initialTapPerPst.keySet().stream().sorted(Comparator.comparing(PstRangeAction::getId)).toList(); - List shiftDetails = new ArrayList<>(); - sortedPstRangeActions.forEach( - pstRangeAction -> { - int initialTap = initialTapPerPst.get(pstRangeAction); - int regulatedTap = regulatedTapPerPst.get(pstRangeAction); - if (initialTap != regulatedTap) { - shiftDetails.add("%s (%s -> %s)".formatted(pstRangeAction.getName(), initialTap, regulatedTap)); - } - } - ); - String allShiftedPstsDetails = shiftDetails.isEmpty() ? "no PST shifted" : String.join(", ", shiftDetails); - if (!shiftDetails.isEmpty()) { - BUSINESS_LOGS.info( - "FlowCNEC '{}' of contingency scenario '{}' is overloaded and is the most limiting element, PST regulation has been triggered: {}", - mostLimitingElement.getId(), contingency.getName().orElse(contingency.getId()), allShiftedPstsDetails - ); - } - } -} diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/ElementaryPstRegulationInput.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/ElementaryPstRegulationInput.java deleted file mode 100644 index d94d89f1dd..0000000000 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/ElementaryPstRegulationInput.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2025, 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.openrao.searchtreerao.castor.algorithm.pstregulation; - -import com.powsybl.iidm.network.Branch; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.TwoSides; -import com.powsybl.iidm.network.TwoWindingsTransformer; -import com.powsybl.openrao.commons.OpenRaoException; -import com.powsybl.openrao.commons.Unit; -import com.powsybl.openrao.data.crac.api.Crac; -import com.powsybl.openrao.data.crac.api.State; -import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; -import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; -import org.apache.commons.lang3.tuple.Pair; - -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * Helper class to store all the data required for the regulation of a PST. It contains the PST range action with the - * most limiting threshold of the FlowCNEC monitored by the PST and its associated side. The record representation - * allows a more elegant and convenient manipulation of the data to configure the PST regulation for OpenLoadFlow. - * - * @author Thomas Bouquet {@literal } - */ -public record ElementaryPstRegulationInput(PstRangeAction pstRangeAction, TwoSides limitingSide, double limitingThreshold) { - public static ElementaryPstRegulationInput of(PstRangeAction pstRangeAction, String monitoredNetworkElement, State state, Crac crac, Network network) { - Set curativeFlowCnecs = crac.getFlowCnecs(state).stream() - .filter(flowCnec -> monitoredNetworkElement.equals(flowCnec.getNetworkElement().getId())) - .collect(Collectors.toSet()); - if (curativeFlowCnecs.isEmpty()) { - return null; - } - - // if the PST monitors itself, the most limiting terminal is used for regulation - if (pstRangeAction.getNetworkElement().getId().equals(monitoredNetworkElement)) { - double thresholdOne = getMostLimitingThreshold(curativeFlowCnecs, TwoSides.ONE); - double thresholdTwo = getMostLimitingThreshold(curativeFlowCnecs, TwoSides.TWO); - return thresholdOne <= thresholdTwo ? - new ElementaryPstRegulationInput(pstRangeAction, TwoSides.ONE, thresholdOne) : - new ElementaryPstRegulationInput(pstRangeAction, TwoSides.TWO, thresholdTwo); - } - - // otherwise, the terminal in common with the element in series it monitors is used - Pair commonTerminalSides = getSidesOfCommonTerminal(pstRangeAction, monitoredNetworkElement, network); - return new ElementaryPstRegulationInput(pstRangeAction, commonTerminalSides.getLeft(), getMostLimitingThreshold(curativeFlowCnecs, commonTerminalSides.getRight())); - } - - private static double getMostLimitingThreshold(Set curativeFlowCnecs, TwoSides twoSides) { - return curativeFlowCnecs.stream().mapToDouble(flowCnec -> getMostLimitingThreshold(flowCnec, twoSides)).min().orElse(Double.MAX_VALUE); - } - - /** - * Retrieves the most limiting current threshold of a FlowCnec (in Amperes) on a given side. - * The returned threshold in always positive since it accounts for a line loading (sign is just for direction). - */ - private static double getMostLimitingThreshold(FlowCnec flowCnec, TwoSides twoSides) { - double mostLimitingThreshold = Double.MAX_VALUE; - - Optional upperBound = flowCnec.getUpperBound(twoSides, Unit.AMPERE); - // current threshold -> sign is used for current direction so upper bound is expected to be positive - if (upperBound.isPresent() && upperBound.get() >= 0) { - mostLimitingThreshold = upperBound.get(); - } - - Optional lowerBound = flowCnec.getLowerBound(twoSides, Unit.AMPERE); - // current threshold -> sign is used for current direction so lower bound is expected to be negative - if (lowerBound.isPresent() && lowerBound.get() <= 0) { - mostLimitingThreshold = Math.min(mostLimitingThreshold, -lowerBound.get()); - } - - return mostLimitingThreshold; - } - - /** - * If the PST monitors a line connected in series, returns a pair that contains the respective side of the terminal - * they share in common. - */ - private static Pair getSidesOfCommonTerminal(PstRangeAction pstRangeAction, String monitoredNetworkElement, Network network) { - Branch branch = network.getBranch(monitoredNetworkElement); - if (branch == null) { - throw new OpenRaoException("No branch with id '%s' found in network.".formatted(monitoredNetworkElement)); - } - - String twoWindingsTransformerId = pstRangeAction.getNetworkElement().getId(); - TwoWindingsTransformer twoWindingsTransformer = network.getTwoWindingsTransformer(twoWindingsTransformerId); - if (twoWindingsTransformer == null) { - throw new OpenRaoException("No two-windings transformer with id '%s' found in network.".formatted(twoWindingsTransformerId)); - } - - for (TwoSides twtSide : TwoSides.values()) { - for (TwoSides branchSide : TwoSides.values()) { - if (twoWindingsTransformer.getTerminal(twtSide).getVoltageLevel().getId().equals(branch.getTerminal(branchSide).getVoltageLevel().getId())) { - return Pair.of(twtSide, branchSide); - } - } - } - - throw new OpenRaoException("Two-windings transformer '%s' and branch '%s' do not share a common terminal so PST regulation cannot be performed." - .formatted(twoWindingsTransformerId, monitoredNetworkElement)); - } -} diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulationInput.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulationInput.java deleted file mode 100644 index 1d41bb1818..0000000000 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulationInput.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2025, 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.openrao.searchtreerao.castor.algorithm.pstregulation; - -import com.powsybl.openrao.data.crac.api.State; -import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; - -import java.util.Set; - -/** - * @author Thomas Bouquet {@literal } - */ -public record PstRegulationInput(State curativeState, FlowCnec limitingElement, Set elementaryPstRegulationInputs) { -} diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulationResult.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulationResult.java deleted file mode 100644 index 282c7df212..0000000000 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulationResult.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2025, 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.openrao.searchtreerao.castor.algorithm.pstregulation; - -import com.powsybl.contingency.Contingency; -import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; - -import java.util.Map; - -/** - * @author Thomas Bouquet {@literal } - */ -public record PstRegulationResult(Contingency contingency, Map regulatedTapPerPst) { -} diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulator.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulator.java deleted file mode 100644 index 355910a484..0000000000 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/pstregulation/PstRegulator.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2025, 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.openrao.searchtreerao.castor.algorithm.pstregulation; - -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.PhaseTapChanger; -import com.powsybl.iidm.network.TwoWindingsTransformer; -import com.powsybl.loadflow.LoadFlow; -import com.powsybl.loadflow.LoadFlowParameters; -import com.powsybl.openrao.commons.OpenRaoException; -import com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider; -import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; - -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * @author Thomas Bouquet {@literal } - */ -public final class PstRegulator { - private PstRegulator() { - } - - public static Map regulatePsts(Set elementaryPstRegulationInputs, Network network, LoadFlowParameters loadFlowParameters) { - elementaryPstRegulationInputs.forEach(elementaryPstRegulationInput -> setRegulationForPst(network, elementaryPstRegulationInput)); - LoadFlow.find("OpenLoadFlow").run(network, loadFlowParameters); - return elementaryPstRegulationInputs.stream() - .collect(Collectors.toMap( - ElementaryPstRegulationInput::pstRangeAction, - pstRegulationInput -> getRegulatedTap(network, pstRegulationInput.pstRangeAction()) - )); - } - - private static void setRegulationForPst(Network network, ElementaryPstRegulationInput elementaryPstRegulationInput) { - TwoWindingsTransformer twt = getTwoWindingsTransformer(network, elementaryPstRegulationInput.pstRangeAction()); - PhaseTapChanger phaseTapChanger = twt.getPhaseTapChanger(); - phaseTapChanger.setRegulationValue(elementaryPstRegulationInput.limitingThreshold()); - setRegulationTerminal(twt, elementaryPstRegulationInput); - phaseTapChanger.setRegulationMode(PhaseTapChanger.RegulationMode.CURRENT_LIMITER); - setTargetDeadband(twt); - phaseTapChanger.setRegulating(true); - } - - private static TwoWindingsTransformer getTwoWindingsTransformer(Network network, PstRangeAction pstRangeAction) { - String pstId = pstRangeAction.getNetworkElement().getId(); - TwoWindingsTransformer twt = network.getTwoWindingsTransformer(pstId); - if (twt == null) { - throw new OpenRaoException("No two-windings transformer with id %s found in network.".formatted(pstId)); - } - return twt; - } - - private static void setRegulationTerminal(TwoWindingsTransformer twt, ElementaryPstRegulationInput elementaryPstRegulationInput) { - PhaseTapChanger phaseTapChanger = twt.getPhaseTapChanger(); - if (phaseTapChanger.getRegulationTerminal() == null) { - OpenRaoLoggerProvider.TECHNICAL_LOGS.info( - "No default regulation terminal defined for phase tap changer of two-windings transformer %s, terminal on side %s will be used." - .formatted(twt.getId(), elementaryPstRegulationInput.limitingSide()) - ); - phaseTapChanger.setRegulationTerminal(twt.getTerminal(elementaryPstRegulationInput.limitingSide())); - } - } - - private static void setTargetDeadband(TwoWindingsTransformer twt) { - PhaseTapChanger phaseTapChanger = twt.getPhaseTapChanger(); - if (Double.isNaN(phaseTapChanger.getTargetDeadband())) { - OpenRaoLoggerProvider.TECHNICAL_LOGS.info("No default target deadband defined for phase tap changer of two-windings transformer %s, a value of 0.0 will be used.".formatted(twt.getId())); - phaseTapChanger.setTargetDeadband(0.0); // value is not used by OpenLoadFlow in CURRENT_LIMITER mode - } - } - - private static int getRegulatedTap(Network network, PstRangeAction pstRangeAction) { - Integer tapPosition = getTwoWindingsTransformer(network, pstRangeAction).getPhaseTapChanger().getSolvedTapPosition(); - if (tapPosition == null) { - throw new OpenRaoException("Could not retrieve regulated tap position for PST range action %s.".formatted(pstRangeAction.getName())); - } - return getTwoWindingsTransformer(network, pstRangeAction).getPhaseTapChanger().getSolvedTapPosition(); - } -} From e030f0044f95b3b476ba6bc5188e02289a7dc85b Mon Sep 17 00:00:00 2001 From: Thomas Bouquet Date: Fri, 20 Mar 2026 16:33:09 +0100 Subject: [PATCH 7/7] fix unit tests Signed-off-by: Thomas Bouquet --- .../openrao/pstregulation/PstRegulation.java | 49 ++++++++++--------- .../pstregulation/PstRegulationTest.java | 28 ++--------- 2 files changed, 28 insertions(+), 49 deletions(-) diff --git a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java index 6b1c62c456..10b9352535 100644 --- a/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java +++ b/pst-regulation/src/main/java/com/powsybl/openrao/pstregulation/PstRegulation.java @@ -314,31 +314,32 @@ private static RaoResult mergePstRegulationResultsWithRaoResult(Set appliedRemedialActions.addAppliedRangeAction(state, pstRangeAction, pstRangeAction.convertTapToAngle(regulatedTap))); + if (state != null) { + appliedRemedialActions.addAppliedNetworkActions(state, raoResult.getActivatedNetworkActionsDuringState(state)); + appliedRemedialActions.addAppliedRangeActions(state, raoResult.getOptimizedSetPointsOnState(state)); + + if (resultsPerState.containsKey(state)) { + PstRegulationResult pstRegulationResult = resultsPerState.get(state); + pstRegulationResult.regulatedTapPerPst().forEach((pstRangeAction, regulatedTap) -> appliedRemedialActions.addAppliedRangeAction(state, pstRangeAction, pstRangeAction.convertTapToAngle(regulatedTap))); + } + + appliedRemedialActions.getAppliedNetworkActions(state).forEach(networkAction -> networkAction.apply(network)); + appliedRemedialActions.getAppliedRangeActions(state).forEach((rangeAction, setPoint) -> rangeAction.apply(network, setPoint)); + + PrePerimeterResult postInstantPerimeterResult = prePerimeterSensitivityAnalysis.runBasedOnInitialResults(network, initialFlowResult, Collections.emptySet(), new AppliedRemedialActions()); + + OptimizationResult newOptimizationResult = new OptimizationResultImpl( + postInstantPerimeterResult, + postInstantPerimeterResult, + postInstantPerimeterResult, + new NetworkActionsResultImpl(Map.of(state, raoResult.getActivatedNetworkActionsDuringState(state))), + new RangeActionActivationResultImpl(postInstantPerimeterResult) + ); + PostPerimeterResult postPerimeterStateResult = new PostPerimeterSensitivityAnalysis(crac, crac.getFlowCnecs(), crac.getRangeActions(), raoParameters, toolProvider, true).runBasedOnInitialPreviousAndOptimizationResults(network, initialFlowResult, prePerimeterResult, Set.of(), newOptimizationResult, new AppliedRemedialActions()); + postRegulationPostContingencyResults.put(state, postPerimeterStateResult); + + prePerimeterResult = postInstantPerimeterResult; } - - appliedRemedialActions.getAppliedNetworkActions(state).forEach(networkAction -> networkAction.apply(network)); - appliedRemedialActions.getAppliedRangeActions(state).forEach((rangeAction, setPoint) -> rangeAction.apply(network, setPoint)); - - PrePerimeterResult postInstantPerimeterResult = prePerimeterSensitivityAnalysis.runBasedOnInitialResults(network, initialFlowResult, Collections.emptySet(), new AppliedRemedialActions()); - - OptimizationResult newOptimizationResult = new OptimizationResultImpl( - postInstantPerimeterResult, - postInstantPerimeterResult, - postInstantPerimeterResult, - new NetworkActionsResultImpl(Map.of(state, raoResult.getActivatedNetworkActionsDuringState(state))), - new RangeActionActivationResultImpl(postInstantPerimeterResult) - ); - PostPerimeterResult postPerimeterStateResult = new PostPerimeterSensitivityAnalysis(crac, crac.getFlowCnecs(), crac.getRangeActions(), raoParameters, toolProvider, true).runBasedOnInitialPreviousAndOptimizationResults(network, initialFlowResult, prePerimeterResult, Set.of(), newOptimizationResult, new AppliedRemedialActions()); - postRegulationPostContingencyResults.put(state, postPerimeterStateResult); - - prePerimeterResult = postInstantPerimeterResult; } } diff --git a/pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/PstRegulationTest.java b/pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/PstRegulationTest.java index d4443283d8..72b9141863 100644 --- a/pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/PstRegulationTest.java +++ b/pst-regulation/src/test/java/com/powsybl/openrao/pstregulation/PstRegulationTest.java @@ -11,25 +11,17 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; import com.powsybl.iidm.network.Network; -import com.powsybl.openrao.commons.Unit; import com.powsybl.openrao.commons.logs.RaoBusinessLogs; import com.powsybl.openrao.data.crac.api.Crac; -import com.powsybl.openrao.data.crac.api.Instant; -import com.powsybl.openrao.data.crac.api.State; import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; import com.powsybl.openrao.data.raoresult.api.RaoResult; import com.powsybl.openrao.raoapi.json.JsonRaoParameters; import com.powsybl.openrao.raoapi.parameters.RaoParameters; -import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; -import com.powsybl.openrao.searchtreerao.result.impl.PostPerimeterResult; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import org.slf4j.LoggerFactory; import java.io.IOException; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -41,30 +33,16 @@ class PstRegulationTest { @Test void testPstRegulationWithSeveralContingencyScenarios() throws IOException { Network network = Network.read("4NodesSeries.uct", getClass().getResourceAsStream("/network/4NodesSeries.uct")); + network.getVariantManager().cloneVariant(network.getVariantManager().getWorkingVariantId(), "InitialScenario"); + network.getVariantManager().setWorkingVariant("InitialScenario"); + Crac crac = Crac.read("crac-for-regulation.json", getClass().getResourceAsStream("/crac/crac-for-regulation.json"), network); RaoResult raoResult = RaoResult.read(getClass().getResourceAsStream("/raoResult/raoResultPreRegulation.json"), crac); RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/parameters/RaoParameters_ac_3pstsRegulation.json")); - Instant curativeInstant = crac.getLastInstant(); PstRangeAction pst12 = crac.getPstRangeAction("pstFr12"); PstRangeAction pst34 = crac.getPstRangeAction("pstFr34"); - // mock optimization result to give the same values as RAO result - Map postContingencyResults = new HashMap<>(); - crac.getStates(curativeInstant).forEach( - curativeState -> { - OptimizationResult optimizationResult = Mockito.mock(OptimizationResult.class); - crac.getFlowCnecs(curativeState).forEach( - flowCnec -> Mockito.when(optimizationResult.getMargin(flowCnec, Unit.AMPERE)).thenReturn(raoResult.getMargin(curativeInstant, flowCnec, Unit.AMPERE)) - ); - - PostPerimeterResult postPerimeterResult = Mockito.mock(PostPerimeterResult.class); - Mockito.when(postPerimeterResult.optimizationResult()).thenReturn(optimizationResult); - - postContingencyResults.put(curativeState, postPerimeterResult); - } - ); - ListAppender listAppender = getBusinessLogs(); List logsList = listAppender.list;