diff --git a/docs/castor/linear-problem/core-problem-filler.md b/docs/castor/linear-problem/core-problem-filler.md index ced5ce6e95..b8b98b3b21 100644 --- a/docs/castor/linear-problem/core-problem-filler.md +++ b/docs/castor/linear-problem/core-problem-filler.md @@ -2,17 +2,20 @@ ## Used input data -| Name | Symbol | Details | -|-----------------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| FlowCnecs | $c \in \mathcal{C}$ | set of FlowCnecs[^1]. Note that FlowCnecs are all the CBCO for which we compute the flow in the MILP, either:
- because we are optimizing their flow (optimized flowCnec = CNEC)
- because we are monitoring their flow, and ensuring it does not exceed its threshold (monitored flowCnec = MNEC)
- or both | -| RangeActions | $r,s \in \mathcal{RA}$ | set of RangeActions and state on which they are applied, could be PSTs, HVDCs, or injection range actions | -| RangeActions | $r \in \mathcal{RA(s)}$ | set of RangeActions available on state $s$, could be PSTs, HVDCs, or injection range actions | -| Iteration number | $n$ | number of current iteration | -| ReferenceFlow | $f_{n}(c)$ | reference flow, for FlowCnec $c$.
The reference flow is the flow at the beginning of the current iteration of the MILP, around which the sensitivities are computed | -| PrePerimeterSetpoints | $\alpha _0(r)$ | setpoint of RangeAction $r$ at the beginning of the optimization | -| ReferenceSetpoints | $\alpha _n(r)$ | setpoint of RangeAction $r$ at the beginning of the current iteration of the MILP, around which the sensitivities are computed | -| Sensitivities | $\sigma _{n}(r,c,s)$ | sensitivity of RangeAction $r$ on FlowCnec $c$ for state $s$ | -| Previous RA setpoint | $A_{n-1}(r,s)$ | optimal setpoint of RangeAction $r$ on state $s$ in previous iteration ($n-1$) | +| Name | Symbol | Details | +|-------------------------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| FlowCnecs | $c \in \mathcal{C}$ | set of FlowCnecs[^1]. Note that FlowCnecs are all the CBCO for which we compute the flow in the MILP, either:
- because we are optimizing their flow (optimized flowCnec = CNEC)
- because we are monitoring their flow, and ensuring it does not exceed its threshold (monitored flowCnec = MNEC)
- or both | +| RangeActions | $r,s \in \mathcal{RA}$ | set of RangeActions and state on which they are applied, could be PSTs, HVDCs, or injection range actions | +| RangeActions | $r \in \mathcal{RA(s)}$ | set of RangeActions available on state $s$, could be PSTs, HVDCs, or injection range actions | +| Iteration number | $n$ | number of current iteration | +| ReferenceFlow | $f_{n}(c)$ | reference flow, for FlowCnec $c$.
The reference flow is the flow at the beginning of the current iteration of the MILP, around which the sensitivities are computed | +| PrePerimeterSetpoints | $\alpha _0(r)$ | setpoint of RangeAction $r$ at the beginning of the optimization | +| ReferenceSetpoints | $\alpha _n(r)$ | setpoint of RangeAction $r$ at the beginning of the current iteration of the MILP, around which the sensitivities are computed | +| Sensitivities | $\sigma _{n}(r,c,s)$ | sensitivity of RangeAction $r$ on FlowCnec $c$ for state $s$ | +| Previous RA setpoint | $A_{n-1}(r,s)$ | optimal setpoint of RangeAction $r$ on state $s$ in previous iteration ($n-1$) | +| Activation cost of RA | $c_{act}(r)$ | cost to spend to activate the range action | +| Upward variation cost of RA | $c_{\Delta}^{+}(r)$ | cost to spend for each MW (resp. tap) changed in the upward direction for a standard range action (resp. PST range action) | +| Downward variation cost of RA | $c_{\Delta}^{-}(r)$ | cost to spend for each MW (resp. tap) changed in the downward direction for a standard range action (resp. PST range action) | [^1]: CNECs that belong to a state for which sensitivity computations failed are ignored in the MILP @@ -25,13 +28,14 @@ ## Defined optimization variables -| Name | Symbol | Details | Type | Index | Unit | Lower bound | Upper bound | -|---------------------------------|-------------------|-----------------------------------------------------------------------------------------------------------------------|---------------------|--------------------------------------------------|-----------------------------------------------------------|-----------------------|-----------------------| -| Flow | $F(c)$ | flow of FlowCnec $c$ | Real value | One variable for every element of (FlowCnecs) | MW | $-\infty$ | $+\infty$ | -| RA set-point | $A(r,s)$ | set-point of RangeAction $r$ on state $s$ | Real value | One variable for every element of (RangeActions) | Degrees for PST range actions; MW for other range actions | Range lower bound[^2] | Range upper bound[^2] | -| RA set-point absolute variation | $\Delta A(r,s)$ | The absolute set-point variation of RangeAction $r$ on state $s$, from setpoint on previous state to "RA setpoint" | Real positive value | One variable for every element of (RangeActions) | Degrees for PST range actions; MW for other range actions | 0 | $+\infty$ | -| RA upward set-point variation | $\Delta^{+}(r,s)$ | The upward set-point variation of RangeAction $r$ on state $s$, from set-point on previous state to "RA set-point" | Real positive value | One variable for every element of (RangeActions) | Degrees for PST range actions; MW for other range actions | 0 | $+\infty$ | -| RA downward set-point variation | $\Delta^{-}(r,s)$ | The downward set-point variation of RangeAction $r$ on state $s$, from set-point on previous state to "RA set-point" | Real positive value | One variable for every element of (RangeActions) | Degrees for PST range actions; MW for other range actions | 0 | $+\infty$ | +| Name | Symbol | Details | Type | Index | Unit | Lower bound | Upper bound | +|--------------------------------|-------------------|-------------------------------------------------------------------------------------------------------------------|---------------------|--------------------------------------------------|-----------------------------------------------------------|-----------------------|-----------------------| +| Flow | $F(c)$ | flow of FlowCnec $c$ | Real value | One variable for every element of (FlowCnecs) | MW | $-\infty$ | $+\infty$ | +| RA setpoint | $A(r,s)$ | setpoint of RangeAction $r$ on state $s$ | Real value | One variable for every element of (RangeActions) | Degrees for PST range actions; MW for other range actions | Range lower bound[^2] | Range upper bound[^2] | +| RA setpoint absolute variation | $\Delta A(r,s)$ | The absolute setpoint variation of RangeAction $r$ on state $s$, from setpoint on previous state to "RA setpoint" | Real positive value | One variable for every element of (RangeActions) | Degrees for PST range actions; MW for other range actions | 0 | $+\infty$ | +| RA setpoint upward variation | $\Delta^{+}(r,s)$ | The upward setpoint variation of RangeAction $r$ on state $s$, from setpoint on previous state to "RA setpoint" | Real positive value | One variable for every element of (RangeActions) | Degrees for PST range actions; MW for other range actions | 0 | $+\infty$ | +| RA setpoint downward variation | $\Delta^{-}(r,s)$ | The downward setpoint variation of RangeAction $r$ on state $s$, from setpoint on previous state to "RA setpoint" | Real positive value | One variable for every element of (RangeActions) | Degrees for PST range actions; MW for other range actions | 0 | $+\infty$ | +| RA activation | $\delta(r,s)$ | Binary variable that indicates whether the range action $r$ is activated at state $s$ | Binary | One variable for every element of (RangeActions) | Degrees for PST range actions; MW for other range actions | 0 | 1 | [^2]: Range actions' lower & upper bounds are computed using CRAC + network + previous RAO results, depending on the types of their ranges: ABSOLUTE, RELATIVE_TO_INITIAL_NETWORK, RELATIVE_TO_PREVIOUS_INSTANT (more @@ -52,7 +56,11 @@ with $s$ the state on $c$ which is evaluated
-### Definition of the setpoint variations of the RangeActions +### Definition of the set-point variations of the RangeActions + +#### Using the absolute variation variable + +> The following equations are used if the RAO is used in (relative) minimum margin optimization mode. $$ \begin{equation} @@ -81,6 +89,24 @@ $$ \end{equation} $$ +#### Using the upward and downward variation variables + +> The following equations are used if the RAO is used in remedial actions' cost optimization mode. + +$$A(r,s) = \Delta^{+}(r,s) - \Delta^{-}(r,s) + A(r,s') , \forall (r,s) \in \mathcal{RA}$$ + +with $A(r,s')$ the setpoint of the last range action on the same element as $r$ but a state preceding $s$. If none such +range actions exists, then $A(r,s') = \alpha_{0}(r)$ + +### Range action activation variable + +> The following equations are used if the RAO is used in remedial actions' cost optimization mode. + +$$\left ( \alpha_{\max}(r, s) - \alpha_{\min}(r, s) \right ) \delta(r,s) \geq \Delta^{+}(r,s) + \Delta^{-}(r,s) , \forall (r,s) \in \mathcal{RA}$$ + +where $\alpha_{\max}(r, s)$ and $\alpha_{\min}(r, s)$ are respectively the maximum and minimum reachable set-points for +range action $r$ at state $s$. + ### Shrinking the allowed range If parameter [ra-range-shrinking](/parameters.md#ra-range-shrinking) is enabled, the allowed range for range actions @@ -109,6 +135,8 @@ back to its initial solution if needed. ## Contribution to the objective function +### Margin optimization + Small penalisation for the use of RangeActions: $$ @@ -116,3 +144,14 @@ $$ \min \sum_{r,s \in \mathcal{RA}} (c^{penalty}_{ra}(r) \Delta A(r,s)) \end{equation} $$ + +### Remedial actions' cost optimization + +$$ +\begin{equation} +\min \sum_{r,s \in \mathcal{RA}} c^{act}(r) \delta(r,s) + c_{\Delta}^{+}(r) \Delta^{+}(r,s) + c_{\Delta}^{-}(r) \Delta^{-}(r,s) +\end{equation} +$$ + +> - For PST range actions, the tap variation is used instead. +> - If the variation costs are null, the penalties defined in the RAO parameters ($c_{ra}^{penalty}$) are used instead to force the RAO to change as few taps as possible (the value of the penalty depends on the type of range action: [PST](/parameters.md#ra-pst-penalty-cost), [injection](/parameters.md#injection-ra-penalty-cost) of [HVDC](/parameters.md#hvdc-penalty-cost)) diff --git a/docs/castor/linear-problem/discrete-pst-tap-filler.md b/docs/castor/linear-problem/discrete-pst-tap-filler.md index b3367e881d..4e1a75a857 100644 --- a/docs/castor/linear-problem/discrete-pst-tap-filler.md +++ b/docs/castor/linear-problem/discrete-pst-tap-filler.md @@ -23,12 +23,15 @@ information [here](/input-data/crac/json.md#range-actions)) ## Defined optimization variables -| Name | Symbol | Details | Type | Index | Unit | Lower bound | Upper bound | -|----------------------------------------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------|---------|-----------------------------------------------------------------------------------------------|--------------------------|-------------|-------------| -| PstRangeAction tap upward variation | $\Delta t^{+} (r, s)$ | upward tap variation of PstRangeAction $r$, at state $s$, between two iterations of the optimisation | Integer | One variable for every element of PstRangeActions and for evey state in which it is optimized | No unit (number of taps) | 0 | $+\infty$ | -| PstRangeAction tap downward variation | $\Delta t^{-} (r, s)$ | downward tap variation of PstRangeAction $r$, at state $s$, between two iterations of the optimisation | Integer | One variable for every element of PstRangeActions and for evey state in which it is optimized | No unit (number of taps) | 0 | $+\infty$ | -| PstRangeAction tap upward variation binary | $\delta ^{+} (r, s)$ | indicates whether the tap of PstRangeAction $r$ has increased, at state $s$, between two iterations of the optimisation | Binary | One variable for every element of PstRangeActions and for evey state in which it is optimized | No unit | 0 | 1 | -| PstRangeAction tap downward variation binary | $\delta ^{-} (r, s)$ | indicates whether the tap of PstRangeAction $r$ has decreased, at state $s$, between two iterations of the optimisation | Binary | One variable for every element of PstRangeActions and for evey state in which it is optimized | No unit | 0 | 1 | +| Name | Symbol | Details | Type | Index | Unit | Lower bound | Upper bound | +|----------------------------------------------|-------------------------------|-------------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------|--------------------------|-------------|-------------| +| PstRangeAction tap upward variation | $\Delta t^{+} (r, s)$ | upward tap variation of PstRangeAction $r$, at state $s$, between two iterations of the optimisation | Integer | One variable for every element of PstRangeActions and for evey state in which it is optimized | No unit (number of taps) | 0 | $+\infty$ | +| PstRangeAction tap downward variation | $\Delta t^{-} (r, s)$ | downward tap variation of PstRangeAction $r$, at state $s$, between two iterations of the optimisation | Integer | One variable for every element of PstRangeActions and for evey state in which it is optimized | No unit (number of taps) | 0 | $+\infty$ | +| PstRangeAction tap upward variation binary | $\delta ^{+} (r, s)$ | indicates whether the tap of PstRangeAction $r$ has increased, at state $s$, between two iterations of the optimisation | Binary | One variable for every element of PstRangeActions and for evey state in which it is optimized | No unit | 0 | 1 | +| PstRangeAction tap downward variation binary | $\delta ^{-} (r, s)$ | indicates whether the tap of PstRangeAction $r$ has decreased, at state $s$, between two iterations of the optimisation | Binary | One variable for every element of PstRangeActions and for evey state in which it is optimized | No unit | 0 | 1 | +| PstRangeAction tap | $\tau (r, s)$ | tap position of the PST of range action $r$ at state $s$ | Integer | One variable for every element of PstRangeActions and for evey state in which it is optimized | No unit | min PST tap | max PST tap | +| Total PstRangeAction upward tap variation | $\Delta_{total} t^{+} (r, s)$ | total upward tap variation of PstRangeAction $r$, at state $s$, from the pre-perimeter tap position | Integer | One variable for every element of PstRangeActions and for evey state in which it is optimized | No unit | 0 | $+\infty$ | +| Total PstRangeAction downward tap variation | $\Delta_{total} t^{-} (r, s)$ | total downward tap variation of PstRangeAction $r$, at state $s$, from the pre-perimeter tap position | Integer | One variable for every element of PstRangeActions and for evey state in which it is optimized | No unit | 0 | $+\infty$ | ## Used optimization variables @@ -88,6 +91,18 @@ $c^{+}_{tap \rightarrow a}(r, s)$ (resp. $c^{-}_{tap \rightarrow a}(r, s)$) is s
+### Tap variable + +$$\tau(r, s) = \Delta t^{+} - \Delta t^{-} + t_{n}(r, s)$$ + +### Total tap variation + +$$\Delta_{total} t^{+} (r, s) - \Delta_{total} t^{-} (r, s) = \tau(r, s) - +\begin{cases} + \tau(r, s') & \text{if $r$ was previously available at state $s'$}\\ + t_{0}(r, s) & \text{otherwise} +\end{cases}$$ + ### Tap variation can only be in one direction, upward or downward $$ diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorSecondPreventive.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorSecondPreventive.java index 9d3a817cbb..c119dec975 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorSecondPreventive.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorSecondPreventive.java @@ -206,7 +206,7 @@ RaoResult runSecondPreventiveAndAutoRao(CastorContingencyScenarios castorConting if (entry.getValue() instanceof SkippedOptimizationResultImpl) { newPostContingencyResults.put(state, new SkippedOptimizationResultImpl(state, new HashSet<>(), new HashSet<>(), postCraSensitivityAnalysisOutput.getSensitivityStatus(entry.getKey()), raoParameters.getLoadFlowAndSensitivityParameters().getSensitivityFailureOvercost())); } else { - newPostContingencyResults.put(state, new CurativeWithSecondPraoResult(state, entry.getValue(), secondPreventiveRaoResult.perimeterResult(), secondPreventiveRaoResult.remedialActionsExcluded(), postCraSensitivityAnalysisOutput)); + newPostContingencyResults.put(state, new CurativeWithSecondPraoResult(state, entry.getValue(), secondPreventiveRaoResult.perimeterResult(), secondPreventiveRaoResult.remedialActionsExcluded(), postCraSensitivityAnalysisOutput, raoParameters.getObjectiveFunctionParameters().getType().costOptimization())); } } RaoLogger.logMostLimitingElementsResults(BUSINESS_LOGS, postCraSensitivityAnalysisOutput, raoParameters.getObjectiveFunctionParameters().getType(), NUMBER_LOGGED_ELEMENTS_END_RAO); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/BestTapFinder.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/BestTapFinder.java index 256df7febe..cbc1a433df 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/BestTapFinder.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/BestTapFinder.java @@ -40,7 +40,7 @@ private BestTapFinder() { /** * This function computes the best tap positions for PstRangeActions that were optimized in the linear problem. * It is a little smarter than just rounding the optimal angle to the closest tap position: - * if the optimal angle is close to the limit between two tap positions, it will chose the one that maximizes the + * if the optimal angle is close to the limit between two tap positions, it will choose the one that maximizes the * minimum margin on the 10 most limiting elements (pre-optim) * If virtual costs are an important part of the optimization, it is highly recommended to use APPROXIMATED_INTEGERS * taps in the linear optimization, rather than relying on the best tap finder to round the taps. @@ -157,7 +157,7 @@ static Map computeMinMarginsForBestTaps(Network network, double approxLimitAngle = 0.5 * (closestAngle + otherAngle); if (Math.abs(angle - approxLimitAngle) / Math.abs(closestAngle - otherAngle) < 0.15) { // Angle is too close to the limit between two tap positions - // Chose the tap that maximizes the margin on the most limiting element + // Choose the tap that maximizes the margin on the most limiting element Pair margins = computeMinMargins(network, pstRangeAction, closestAngle, otherAngle, linearOptimizationResult, unit); if (margins.getRight() > margins.getLeft()) { return Map.of(closestTap, margins.getLeft(), otherTap, margins.getRight()); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CoreProblemFiller.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/AbstractCoreProblemFiller.java similarity index 84% rename from ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CoreProblemFiller.java rename to ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/AbstractCoreProblemFiller.java index d56827a8fd..3a6d661ada 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CoreProblemFiller.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/AbstractCoreProblemFiller.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, RTE (http://www.rte-france.com) + * Copyright (c) 2024, 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/. @@ -7,12 +7,12 @@ package com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.fillers; +import com.powsybl.iidm.network.TwoSides; import com.powsybl.openrao.commons.OpenRaoException; import com.powsybl.openrao.commons.Unit; import com.powsybl.openrao.data.crac.api.Identifiable; import com.powsybl.openrao.data.crac.api.State; import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; -import com.powsybl.iidm.network.TwoSides; import com.powsybl.openrao.data.crac.api.range.RangeType; import com.powsybl.openrao.data.crac.api.range.StandardRange; import com.powsybl.openrao.data.crac.api.range.TapRange; @@ -24,9 +24,9 @@ import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters; import com.powsybl.openrao.searchtreerao.commons.RaoUtil; import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.LinearProblem; import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPConstraint; import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPVariable; -import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.LinearProblem; import com.powsybl.openrao.searchtreerao.result.api.FlowResult; import com.powsybl.openrao.searchtreerao.result.api.RangeActionActivationResult; import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; @@ -34,37 +34,40 @@ import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.tuple.Pair; -import java.util.*; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; /** * @author Pengbo Wang {@literal } * @author Baptiste Seguinot {@literal } + * @author Thomas Bouquet {@literal } */ -public class CoreProblemFiller implements ProblemFiller { - - private static final double RANGE_ACTION_SETPOINT_EPSILON = 1e-5; - - private final OptimizationPerimeter optimizationContext; - private final Set flowCnecs; - private final RangeActionSetpointResult prePerimeterRangeActionSetpoints; - private final RangeActionsOptimizationParameters rangeActionParameters; - private final Unit unit; - private int iteration = 0; - private static final double RANGE_SHRINK_RATE = 0.667; - private final boolean raRangeShrinking; - - private final RangeActionsOptimizationParameters.PstModel pstModel; - - public CoreProblemFiller(OptimizationPerimeter optimizationContext, - RangeActionSetpointResult prePerimeterRangeActionSetpoints, - RangeActionsOptimizationParameters rangeActionParameters, - Unit unit, - boolean raRangeShrinking, - RangeActionsOptimizationParameters.PstModel pstModel) { +public abstract class AbstractCoreProblemFiller implements ProblemFiller { + protected static final double RANGE_ACTION_SETPOINT_EPSILON = 1e-5; + protected final OptimizationPerimeter optimizationContext; + protected final RangeActionSetpointResult prePerimeterRangeActionSetpoints; + protected final Set flowCnecs; + protected final RangeActionsOptimizationParameters rangeActionParameters; + protected final Unit unit; + protected int iteration = 0; + protected static final double RANGE_SHRINK_RATE = 0.667; + protected final boolean raRangeShrinking; + protected final RangeActionsOptimizationParameters.PstModel pstModel; + + protected AbstractCoreProblemFiller(OptimizationPerimeter optimizationContext, + RangeActionSetpointResult prePerimeterRangeActionSetpoints, + RangeActionsOptimizationParameters rangeActionParameters, + Unit unit, + boolean raRangeShrinking, + RangeActionsOptimizationParameters.PstModel pstModel) { this.optimizationContext = optimizationContext; + this.prePerimeterRangeActionSetpoints = prePerimeterRangeActionSetpoints; this.flowCnecs = new TreeSet<>(Comparator.comparing(Identifiable::getId)); this.flowCnecs.addAll(optimizationContext.getFlowCnecs()); - this.prePerimeterRangeActionSetpoints = prePerimeterRangeActionSetpoints; this.rangeActionParameters = rangeActionParameters; this.unit = unit; this.raRangeShrinking = raRangeShrinking; @@ -85,7 +88,7 @@ public void fill(LinearProblem linearProblem, FlowResult flowResult, Sensitivity checkAndActivateRangeShrinking(linearProblem, rangeActionActivationResult); // complete objective - fillObjectiveWithRangeActionPenaltyCost(linearProblem); + fillObjective(linearProblem); } @@ -119,15 +122,21 @@ private void buildFlowVariables(LinearProblem linearProblem, Set valid */ private void buildRangeActionVariables(LinearProblem linearProblem) { optimizationContext.getRangeActionsPerState().forEach((state, rangeActions) -> - rangeActions.forEach(rangeAction -> { - linearProblem.addRangeActionSetpointVariable(-linearProblem.infinity(), linearProblem.infinity(), rangeAction, state); - linearProblem.addAbsoluteRangeActionVariationVariable(0, linearProblem.infinity(), rangeAction, state); - linearProblem.addRangeActionVariationVariable(linearProblem.infinity(), rangeAction, state, LinearProblem.VariationDirectionExtension.UPWARD); - linearProblem.addRangeActionVariationVariable(linearProblem.infinity(), rangeAction, state, LinearProblem.VariationDirectionExtension.DOWNWARD); - }) + rangeActions.forEach(rangeAction -> addAllRangeActionVariables(linearProblem, rangeAction, state)) ); } + protected void addAllRangeActionVariables(LinearProblem linearProblem, RangeAction rangeAction, State state) { + addBasicRangeActionVariables(linearProblem, rangeAction, state); + } + + private void addBasicRangeActionVariables(LinearProblem linearProblem, RangeAction rangeAction, State state) { + linearProblem.addRangeActionSetpointVariable(-linearProblem.infinity(), linearProblem.infinity(), rangeAction, state); + linearProblem.addAbsoluteRangeActionVariationVariable(0, linearProblem.infinity(), rangeAction, state); + linearProblem.addRangeActionVariationVariable(linearProblem.infinity(), rangeAction, state, LinearProblem.VariationDirectionExtension.UPWARD); + linearProblem.addRangeActionVariationVariable(linearProblem.infinity(), rangeAction, state, LinearProblem.VariationDirectionExtension.DOWNWARD); + } + /** * Build one flow constraint for each Cnec c. * These constraints link the estimated flow on a Cnec with the impact of the RangeActions @@ -237,13 +246,9 @@ private static void updateConstraintsForRangeAction(LinearProblem linearProblem, } } - /** - * Build range action constraints for each RangeAction r. - * These constraints link the set-point variable of the RangeAction with its - * variation variables, and bounds the set-point in an admissible range. - * S[r] = initialSetPoint[r] + upwardVariation[r] - downwardVariation[r] - */ - private void buildConstraintsForRangeActionAndState(LinearProblem linearProblem, RangeAction rangeAction, State state) { + protected abstract void buildConstraintsForRangeActionAndState(LinearProblem linearProblem, RangeAction rangeAction, State state); + + protected void addSetPointConstraints(LinearProblem linearProblem, RangeAction rangeAction, State state) { OpenRaoMPVariable setPointVariable = linearProblem.getRangeActionSetpointVariable(rangeAction, state); OpenRaoMPVariable absoluteVariationVariable = linearProblem.getAbsoluteRangeActionVariationVariable(rangeAction, state); OpenRaoMPVariable upwardVariationVariable = linearProblem.getRangeActionVariationVariable(rangeAction, state, LinearProblem.VariationDirectionExtension.UPWARD); @@ -302,7 +307,7 @@ private void buildConstraintsForRangeActionAndState(LinearProblem linearProblem, } } - private static List getMinAndMaxAbsoluteAndRelativeSetpoints(RangeAction rangeAction, double infinity) { + protected static List getMinAndMaxAbsoluteAndRelativeSetpoints(RangeAction rangeAction, double infinity) { // if relative to previous instant range double minAbsoluteSetpoint = -infinity; @@ -385,26 +390,17 @@ private Set> getAvailableRangeActionsOnSameAction(RangeAction return rangeActions; } - /** - * Add in the objective function a penalty cost associated to the RangeAction - * activations. This penalty cost prioritizes the solutions which change as little - * as possible the set points of the RangeActions. - *

- * min( sum{r in RangeAction} penaltyCost[r] - AV[r] ) - */ - private void fillObjectiveWithRangeActionPenaltyCost(LinearProblem linearProblem) { - optimizationContext.getRangeActionsPerState().forEach((state, rangeActions) -> rangeActions.forEach(ra -> { - OpenRaoMPVariable absoluteVariationVariable = linearProblem.getAbsoluteRangeActionVariationVariable(ra, state); - - // If the range action has been filtered out, then absoluteVariationVariable is null - if (absoluteVariationVariable != null && ra instanceof PstRangeAction) { - linearProblem.getObjective().setCoefficient(absoluteVariationVariable, rangeActionParameters.getPstPenaltyCost()); - } else if (absoluteVariationVariable != null && ra instanceof HvdcRangeAction) { - linearProblem.getObjective().setCoefficient(absoluteVariationVariable, rangeActionParameters.getHvdcPenaltyCost()); - } else if (absoluteVariationVariable != null && ra instanceof InjectionRangeAction) { - linearProblem.getObjective().setCoefficient(absoluteVariationVariable, rangeActionParameters.getInjectionRaPenaltyCost()); - } - } - )); + protected abstract void fillObjective(LinearProblem linearProblem); + + protected static double getRangeActionPenaltyCost(RangeAction rangeAction, RangeActionsOptimizationParameters rangeActionParameters) { + if (rangeAction instanceof PstRangeAction) { + return rangeActionParameters.getPstPenaltyCost(); + } else if (rangeAction instanceof HvdcRangeAction) { + return rangeActionParameters.getHvdcPenaltyCost(); + } else if (rangeAction instanceof InjectionRangeAction) { + return rangeActionParameters.getInjectionRaPenaltyCost(); + } else { + throw new OpenRaoException("Unexpected type of range action: '%s'.".formatted(rangeAction.getClass().getSimpleName())); + } } } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CostCoreProblemFiller.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CostCoreProblemFiller.java new file mode 100644 index 0000000000..c77a10ee49 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CostCoreProblemFiller.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2024, 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.linearoptimisation.algorithms.fillers; + +import com.powsybl.openrao.commons.OpenRaoException; +import com.powsybl.openrao.commons.Unit; +import com.powsybl.openrao.data.crac.api.State; +import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; +import com.powsybl.openrao.data.crac.api.rangeaction.RangeAction; +import com.powsybl.openrao.data.crac.api.rangeaction.VariationDirection; +import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters; +import com.powsybl.openrao.searchtreerao.commons.RaoUtil; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.LinearProblem; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPConstraint; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPVariable; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.List; +import java.util.Optional; + +/** + * @author Thomas Bouquet {@literal } + */ +public class CostCoreProblemFiller extends AbstractCoreProblemFiller { + + public CostCoreProblemFiller(OptimizationPerimeter optimizationContext, + RangeActionSetpointResult prePerimeterRangeActionSetpoints, + RangeActionsOptimizationParameters rangeActionParameters, + Unit unit, + boolean raRangeShrinking, + RangeActionsOptimizationParameters.PstModel pstModel) { + super(optimizationContext, prePerimeterRangeActionSetpoints, rangeActionParameters, unit, raRangeShrinking, pstModel); + if (pstModel.equals(RangeActionsOptimizationParameters.PstModel.CONTINUOUS)) { + throw new OpenRaoException("Costly remedial action optimization is only available for the APPROXIMATED_INTEGERS mode of PST range actions."); + } + } + + @Override + protected void addAllRangeActionVariables(LinearProblem linearProblem, RangeAction rangeAction, State state) { + super.addAllRangeActionVariables(linearProblem, rangeAction, state); + Optional activationCost = rangeAction.getActivationCost(); + if (activationCost.isPresent() && activationCost.get() > 0) { + linearProblem.addRangeActionVariationBinary(rangeAction, state); + } + } + + /** + * Build range action constraints for each RangeAction r. + * These constraints link the set-point variable of the RangeAction with its + * variation variables, and bounds the set-point in an admissible range. + * S[r] = initialSetPoint[r] + upwardVariation[r] - downwardVariation[r] + */ + @Override + protected void buildConstraintsForRangeActionAndState(LinearProblem linearProblem, RangeAction rangeAction, State state) { + addSetPointConstraints(linearProblem, rangeAction, state); + addIsVariationConstraint(linearProblem, rangeAction, state); + } + + private void addIsVariationConstraint(LinearProblem linearProblem, RangeAction rangeAction, State state) { + Optional activationCost = rangeAction.getActivationCost(); + if (activationCost.isPresent() && activationCost.get() > 0) { + OpenRaoMPConstraint activationConstraint = linearProblem.addIsVariationConstraint(0, linearProblem.infinity(), rangeAction, state); + OpenRaoMPVariable upwardVariationVariable = linearProblem.getRangeActionVariationVariable(rangeAction, state, LinearProblem.VariationDirectionExtension.UPWARD); + OpenRaoMPVariable downwardVariationVariable = linearProblem.getRangeActionVariationVariable(rangeAction, state, LinearProblem.VariationDirectionExtension.DOWNWARD); + OpenRaoMPVariable variationBinaryVariable = linearProblem.getRangeActionVariationBinary(rangeAction, state); + + double minSetPoint; + double maxSetPoint; + + Pair, State> lastAvailableRangeAction = RaoUtil.getLastAvailableRangeActionOnSameNetworkElement(optimizationContext, rangeAction, state); + + if (lastAvailableRangeAction == null) { + // if state is equal to masterState, + // or if rangeAction is not available for a previous state + // then, rangeAction could not have been activated in a previous instant + + double prePerimeterSetPoint = prePerimeterRangeActionSetpoints.getSetpoint(rangeAction); + minSetPoint = rangeAction.getMinAdmissibleSetpoint(prePerimeterSetPoint); + maxSetPoint = rangeAction.getMaxAdmissibleSetpoint(prePerimeterSetPoint); + } else { + // range action have been activated in a previous instant + // getRangeActionSetpointVariable from previous instant + List minAndMaxAbsoluteAndRelativeSetpoints = getMinAndMaxAbsoluteAndRelativeSetpoints(rangeAction, linearProblem.infinity()); + minSetPoint = minAndMaxAbsoluteAndRelativeSetpoints.get(0); + maxSetPoint = minAndMaxAbsoluteAndRelativeSetpoints.get(1); + } + + activationConstraint.setCoefficient(variationBinaryVariable, maxSetPoint - minSetPoint + RANGE_ACTION_SETPOINT_EPSILON); + activationConstraint.setCoefficient(upwardVariationVariable, -1.0); + activationConstraint.setCoefficient(downwardVariationVariable, -1.0); + } + } + + /** + * Add in the objective function the costs associated to the range actions that + * is the sum of two factors: + *

    + *
  • An activation cost if the range action is used;
  • + *
  • Variation costs that depend on how much the set-point was shifted.
  • + *
+ */ + @Override + protected void fillObjective(LinearProblem linearProblem) { + optimizationContext.getRangeActionsPerState().forEach((state, rangeActions) -> rangeActions.forEach(ra -> { + OpenRaoMPVariable upwardVariationVariable = linearProblem.getRangeActionVariationVariable(ra, state, LinearProblem.VariationDirectionExtension.UPWARD); + OpenRaoMPVariable downwardVariationVariable = linearProblem.getRangeActionVariationVariable(ra, state, LinearProblem.VariationDirectionExtension.DOWNWARD); + + double defaultVariationCost = getRangeActionPenaltyCost(ra, rangeActionParameters); + if (!(ra instanceof PstRangeAction)) { + linearProblem.getObjective().setCoefficient(upwardVariationVariable, ra.getVariationCost(VariationDirection.UP).orElse(defaultVariationCost)); + linearProblem.getObjective().setCoefficient(downwardVariationVariable, ra.getVariationCost(VariationDirection.DOWN).orElse(defaultVariationCost)); + } + + if (ra.getActivationCost().isPresent() && ra.getActivationCost().get() > 0) { + OpenRaoMPVariable activationVariable = linearProblem.getRangeActionVariationBinary(ra, state); + linearProblem.getObjective().setCoefficient(activationVariable, ra.getActivationCost().get()); + } + } + )); + } +} diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstTapFiller.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstTapFiller.java index 0c073a6c34..c9e5c32aaa 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstTapFiller.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstTapFiller.java @@ -12,9 +12,12 @@ import com.powsybl.openrao.data.crac.api.range.TapRange; import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction; import com.powsybl.openrao.data.crac.api.rangeaction.RangeAction; +import com.powsybl.openrao.data.crac.api.rangeaction.VariationDirection; +import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters; import com.powsybl.openrao.searchtreerao.commons.RaoUtil; import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPConstraint; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPObjective; import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPVariable; import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.LinearProblem; import com.powsybl.openrao.searchtreerao.result.api.FlowResult; @@ -33,14 +36,20 @@ public class DiscretePstTapFiller implements ProblemFiller { private final OptimizationPerimeter optimizationPerimeter; private final Map> rangeActions; private final RangeActionSetpointResult prePerimeterRangeActionSetpoints; + private final RangeActionsOptimizationParameters rangeActionsParameters; + private final boolean costOptimization; private int iteration = 0; public DiscretePstTapFiller(OptimizationPerimeter optimizationPerimeter, Map> rangeActions, - RangeActionSetpointResult prePerimeterRangeActionSetpoints) { + RangeActionSetpointResult prePerimeterRangeActionSetpoints, + RangeActionsOptimizationParameters rangeActionsParameters, + boolean costOptimization) { this.optimizationPerimeter = optimizationPerimeter; this.rangeActions = rangeActions; this.prePerimeterRangeActionSetpoints = prePerimeterRangeActionSetpoints; + this.rangeActionsParameters = rangeActionsParameters; + this.costOptimization = costOptimization; } @Override @@ -52,6 +61,7 @@ public void fill(LinearProblem linearProblem, FlowResult flowResult, Sensitivity if (iteration > 1) { update(linearProblem, rangeActionActivationResult); } + fillObjective(linearProblem); } @Override @@ -69,12 +79,12 @@ private void update(LinearProblem linearProblem, RangeActionActivationResult ran } private void buildPstTapVariablesAndConstraints(LinearProblem linearProblem, PstRangeAction pstRangeAction, State state, RangeActionActivationResult rangeActionActivationResult) { + Pair, State> lastAvailableRangeAction = RaoUtil.getLastAvailableRangeActionOnSameNetworkElement(optimizationPerimeter, pstRangeAction, state); // compute a few values on PST taps and angle double currentAngle = rangeActionActivationResult.getOptimizedSetpoint(pstRangeAction, state); int currentTap = rangeActionActivationResult.getOptimizedTap(pstRangeAction, state); - Pair, State> lastAvailableRangeAction = RaoUtil.getLastAvailableRangeActionOnSameNetworkElement(optimizationPerimeter, pstRangeAction, state); Pair admissibleTaps = getMinAndMaxAdmissibleTaps(pstRangeAction, lastAvailableRangeAction); int minAdmissibleTap = admissibleTaps.getLeft(); int maxAdmissibleTap = admissibleTaps.getRight(); @@ -89,7 +99,7 @@ private void buildPstTapVariablesAndConstraints(LinearProblem linearProblem, Pst OpenRaoMPVariable pstTapDownwardVariationBinary = linearProblem.addPstTapVariationBinary(pstRangeAction, state, LinearProblem.VariationDirectionExtension.DOWNWARD); OpenRaoMPVariable pstTapUpwardVariationBinary = linearProblem.addPstTapVariationBinary(pstRangeAction, state, LinearProblem.VariationDirectionExtension.UPWARD); - // build integer constraint as it wasn't built in CoreProblemFiller + // build integer constraint as it wasn't built in MarginCoreProblemFiller if (lastAvailableRangeAction != null) { RangeAction preventiveRangeAction = lastAvailableRangeAction.getKey(); Pair pstLimits = getMinAndMaxRelativeTaps(pstRangeAction, linearProblem.infinity()); @@ -145,6 +155,33 @@ private void buildPstTapVariablesAndConstraints(LinearProblem linearProblem, Pst OpenRaoMPConstraint upAuthorizationConstraint = linearProblem.addIsVariationInDirectionConstraint(-linearProblem.infinity(), 0, pstRangeAction, state, LinearProblem.VariationReferenceExtension.PREVIOUS_ITERATION, LinearProblem.VariationDirectionExtension.UPWARD); upAuthorizationConstraint.setCoefficient(pstTapUpwardVariationVariable, 1); upAuthorizationConstraint.setCoefficient(pstTapUpwardVariationBinary, -maxUpwardTapVariation); + + int initialTap = prePerimeterRangeActionSetpoints.getTap(pstRangeAction); + + OpenRaoMPVariable tapVariable = linearProblem.addTapVariable(pstRangeAction, state); + OpenRaoMPConstraint tapConstraint = linearProblem.addTapConstraint(pstRangeAction, state); + tapConstraint.setCoefficient(tapVariable, 1.0); + tapConstraint.setCoefficient(pstTapUpwardVariationVariable, -1.0); + tapConstraint.setCoefficient(pstTapDownwardVariationVariable, 1.0); + tapConstraint.setLb(currentTap); + tapConstraint.setUb(currentTap); + + if (costOptimization) { + OpenRaoMPConstraint totalTapVariationConstraint = linearProblem.addTotalPstRangeActionTapVariationConstraint(pstRangeAction, state); + OpenRaoMPVariable totalUpwardTapVariationVariable = linearProblem.addTotalPstRangeActionTapVariationVariable(pstRangeAction, state, LinearProblem.VariationDirectionExtension.UPWARD); + OpenRaoMPVariable totalDownwardTapVariationVariable = linearProblem.addTotalPstRangeActionTapVariationVariable(pstRangeAction, state, LinearProblem.VariationDirectionExtension.DOWNWARD); + + totalTapVariationConstraint.setCoefficient(totalUpwardTapVariationVariable, 1.0); + totalTapVariationConstraint.setCoefficient(totalDownwardTapVariationVariable, -1.0); + totalTapVariationConstraint.setCoefficient(tapVariable, -1.0); + + if (lastAvailableRangeAction == null) { + totalTapVariationConstraint.setLb(-initialTap); + totalTapVariationConstraint.setUb(-initialTap); + } else { + totalTapVariationConstraint.setCoefficient(linearProblem.getTapVariable((PstRangeAction) lastAvailableRangeAction.getLeft(), lastAvailableRangeAction.getRight()), 1.0); + } + } } private void updateRelativeRangeConstraints(LinearProblem linearProblem, PstRangeAction pstRangeAction, State state, RangeActionActivationResult rangeActionActivationResult) { @@ -165,12 +202,12 @@ private void updateRelativeRangeConstraints(LinearProblem linearProblem, PstRang } private void refineTapToAngleConversionCoefficientAndUpdateBounds(LinearProblem linearProblem, PstRangeAction pstRangeAction, RangeActionActivationResult rangeActionActivationResult, State state) { + Pair, State> lastAvailableRangeAction = RaoUtil.getLastAvailableRangeActionOnSameNetworkElement(optimizationPerimeter, pstRangeAction, state); // compute a few values on PST taps and angle double newAngle = rangeActionActivationResult.getOptimizedSetpoint(pstRangeAction, state); int newTapPosition = rangeActionActivationResult.getOptimizedTap(pstRangeAction, state); - Pair, State> lastAvailableRangeAction = RaoUtil.getLastAvailableRangeActionOnSameNetworkElement(optimizationPerimeter, pstRangeAction, state); Pair admissibleTaps = getMinAndMaxAdmissibleTaps(pstRangeAction, lastAvailableRangeAction); int minAdmissibleTap = admissibleTaps.getLeft(); int maxAdmissibleTap = admissibleTaps.getRight(); @@ -207,6 +244,11 @@ private void refineTapToAngleConversionCoefficientAndUpdateBounds(LinearProblem // update the coefficient on the min/max tap variations of the isVariationInDirectionConstraints downAuthorizationConstraint.setCoefficient(pstTapDownwardVariationBinary, -maxDownwardTapVariation); upAuthorizationConstraint.setCoefficient(pstTapUpwardVariationBinary, -maxUpwardTapVariation); + + // update tap position constraint bounds + OpenRaoMPConstraint tapConstraint = linearProblem.getTapConstraint(pstRangeAction, state); + tapConstraint.setLb(newTapPosition); + tapConstraint.setUb(newTapPosition); } /** @@ -246,4 +288,15 @@ private Pair getMinAndMaxRelativeTaps(PstRangeAction pstRangeAct maxRelativeTap = Math.max(0, maxRelativeTap); return Pair.of(minRelativeTap, maxRelativeTap); } + + private void fillObjective(LinearProblem linearProblem) { + if (costOptimization) { + double defaultCost = rangeActionsParameters.getPstPenaltyCost(); + OpenRaoMPObjective objective = linearProblem.getObjective(); + rangeActions.forEach((state, pstRangeActions) -> pstRangeActions.forEach(pstRangeAction -> { + objective.setCoefficient(linearProblem.getTotalPstRangeActionTapVariationVariable(pstRangeAction, state, LinearProblem.VariationDirectionExtension.UPWARD), pstRangeAction.getVariationCost(VariationDirection.UP).orElse(defaultCost)); + objective.setCoefficient(linearProblem.getTotalPstRangeActionTapVariationVariable(pstRangeAction, state, LinearProblem.VariationDirectionExtension.DOWNWARD), pstRangeAction.getVariationCost(VariationDirection.DOWN).orElse(defaultCost)); + })); + } + } } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MarginCoreProblemFiller.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MarginCoreProblemFiller.java new file mode 100644 index 0000000000..b1013af755 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MarginCoreProblemFiller.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024, 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.linearoptimisation.algorithms.fillers; + +import com.powsybl.openrao.commons.Unit; +import com.powsybl.openrao.data.crac.api.State; +import com.powsybl.openrao.data.crac.api.rangeaction.RangeAction; +import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPVariable; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.LinearProblem; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; + +/** + * @author Thomas Bouquet {@literal } + */ +public class MarginCoreProblemFiller extends AbstractCoreProblemFiller { + + public MarginCoreProblemFiller(OptimizationPerimeter optimizationContext, + RangeActionSetpointResult prePerimeterRangeActionSetpoints, + RangeActionsOptimizationParameters rangeActionParameters, + Unit unit, + boolean raRangeShrinking, + RangeActionsOptimizationParameters.PstModel pstModel) { + super(optimizationContext, prePerimeterRangeActionSetpoints, rangeActionParameters, unit, raRangeShrinking, pstModel); + } + + /** + * Build range action constraints for each RangeAction r. + * These constraints link the set-point variable of the RangeAction with its + * variation variables, and bounds the set-point in an admissible range. + * S[r] = initialSetPoint[r] + upwardVariation[r] - downwardVariation[r] + */ + @Override + protected void buildConstraintsForRangeActionAndState(LinearProblem linearProblem, RangeAction rangeAction, State state) { + addSetPointConstraints(linearProblem, rangeAction, state); + } + + /** + * Add in the objective function a penalty cost associated to the RangeAction + * activations. This penalty cost prioritizes the solutions which change as little + * as possible the set points of the RangeActions. + *

+ * min( sum{r in RangeAction} penaltyCost[r] - AV[r] ) + */ + @Override + protected void fillObjective(LinearProblem linearProblem) { + optimizationContext.getRangeActionsPerState().forEach((state, rangeActions) -> rangeActions.forEach(ra -> { + OpenRaoMPVariable absoluteVariationVariable = linearProblem.getAbsoluteRangeActionVariationVariable(ra, state); + if (absoluteVariationVariable != null) { + linearProblem.getObjective().setCoefficient(absoluteVariationVariable, getRangeActionPenaltyCost(ra, rangeActionParameters)); + } + })); + } +} diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinMarginFiller.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinMarginFiller.java index e30d22509c..12c2785f5a 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinMarginFiller.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinMarginFiller.java @@ -30,14 +30,17 @@ * @author Baptiste Seguinot {@literal } */ public class MaxMinMarginFiller implements ProblemFiller { + private static final double OVERLOAD_PENALTY = 10000.0; // TODO: put this in Rao Parameters and mutualize with evaluator protected final Set optimizedCnecs; private final Unit unit; + private final boolean costOptimization; public MaxMinMarginFiller(Set optimizedCnecs, - Unit unit) { + Unit unit, boolean costOptimization) { this.optimizedCnecs = new TreeSet<>(Comparator.comparing(Identifiable::getId)); this.optimizedCnecs.addAll(optimizedCnecs); this.unit = unit; + this.costOptimization = costOptimization; } @Override @@ -49,11 +52,18 @@ public void fill(LinearProblem linearProblem, FlowResult flowResult, Sensitivity // build constraints buildMinimumMarginConstraints(linearProblem, validFlowCnecs); + if (costOptimization) { + forceMinMarginToBeNegative(linearProblem); + } // complete objective fillObjectiveWithMinMargin(linearProblem); } + private static void forceMinMarginToBeNegative(LinearProblem linearProblem) { + linearProblem.getMinimumMarginVariable().setUb(0.0); + } + @Override public void updateBetweenMipIteration(LinearProblem linearProblem, RangeActionActivationResult rangeActionActivationResult) { // Objective does not change, nothing to do @@ -122,8 +132,7 @@ private void buildMinimumMarginConstraints(LinearProblem linearProblem, Set optimizedCnecs, FlowResult preOptimFlowResult, Unit unit, RelativeMarginsParametersExtension maxMinRelativeMarginParameters) { - super(optimizedCnecs, unit); + super(optimizedCnecs, unit, false); this.preOptimFlowResult = preOptimFlowResult; this.ptdfApproximationLevel = maxMinRelativeMarginParameters.getPtdfApproximation(); this.unit = unit; diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/RaUsageLimitsFiller.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/RaUsageLimitsFiller.java index 69a03eb206..2807f5b13e 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/RaUsageLimitsFiller.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/RaUsageLimitsFiller.java @@ -44,17 +44,19 @@ public class RaUsageLimitsFiller implements ProblemFiller { private final boolean arePstSetpointsApproximated; private static final double RANGE_ACTION_SETPOINT_EPSILON = 1e-4; private final Network network; + private final boolean costOptimization; public RaUsageLimitsFiller(Map>> rangeActions, RangeActionSetpointResult prePerimeterRangeActionSetpoints, RangeActionLimitationParameters rangeActionLimitationParameters, boolean arePstSetpointsApproximated, - Network network) { + Network network, boolean costOptimization) { this.rangeActions = rangeActions; this.prePerimeterRangeActionSetpoints = prePerimeterRangeActionSetpoints; this.rangeActionLimitationParameters = rangeActionLimitationParameters; this.arePstSetpointsApproximated = arePstSetpointsApproximated; this.network = network; + this.costOptimization = costOptimization; } @Override @@ -63,7 +65,10 @@ public void fill(LinearProblem linearProblem, FlowResult flowResult, Sensitivity if (!rangeActionLimitationParameters.areRangeActionLimitedForState(state)) { return; } - rangeActionSet.forEach(ra -> buildIsVariationVariableAndConstraints(linearProblem, ra, state)); + // if cost optimization, variation variables are already defined + if (!costOptimization) { + rangeActionSet.forEach(ra -> buildIsVariationVariableAndConstraints(linearProblem, ra, state)); + } if (rangeActionLimitationParameters.getMaxRangeActions(state) != null) { addMaxRaConstraint(linearProblem, state); } @@ -129,19 +134,21 @@ private double getInitialSetpointRelaxation(RangeAction rangeAction) { } private void buildIsVariationVariableAndConstraints(LinearProblem linearProblem, RangeAction rangeAction, State state) { - OpenRaoMPVariable isVariationVariable = linearProblem.addRangeActionVariationBinary(rangeAction, state); + if (!costOptimization) { + OpenRaoMPVariable isVariationVariable = linearProblem.addRangeActionVariationBinary(rangeAction, state); - OpenRaoMPVariable absoluteVariationVariable = linearProblem.getAbsoluteRangeActionVariationVariable(rangeAction, state); + OpenRaoMPVariable absoluteVariationVariable = linearProblem.getAbsoluteRangeActionVariationVariable(rangeAction, state); - double initialSetpointRelaxation = getInitialSetpointRelaxation(rangeAction); + double initialSetpointRelaxation = getInitialSetpointRelaxation(rangeAction); - // range action absolute variation <= isVariationVariable * (max setpoint - min setpoint) + initialSetpointRelaxation - // RANGE_ACTION_SETPOINT_EPSILON is used to mitigate rounding issues, ensuring that the maximum setpoint is feasible - // initialSetpointRelaxation is used to ensure that the initial setpoint is feasible - OpenRaoMPConstraint constraint = linearProblem.addIsVariationConstraint(-linearProblem.infinity(), initialSetpointRelaxation, rangeAction, state); - constraint.setCoefficient(absoluteVariationVariable, 1); - double initialSetpoint = prePerimeterRangeActionSetpoints.getSetpoint(rangeAction); - constraint.setCoefficient(isVariationVariable, -(rangeAction.getMaxAdmissibleSetpoint(initialSetpoint) + RANGE_ACTION_SETPOINT_EPSILON - rangeAction.getMinAdmissibleSetpoint(initialSetpoint))); + // range action absolute variation <= isVariationVariable * (max setpoint - min setpoint) + initialSetpointRelaxation + // RANGE_ACTION_SETPOINT_EPSILON is used to mitigate rounding issues, ensuring that the maximum setpoint is feasible + // initialSetpointRelaxation is used to ensure that the initial setpoint is feasible + OpenRaoMPConstraint constraint = linearProblem.addIsVariationConstraint(-linearProblem.infinity(), initialSetpointRelaxation, rangeAction, state); + constraint.setCoefficient(absoluteVariationVariable, 1); + double initialSetpoint = prePerimeterRangeActionSetpoints.getSetpoint(rangeAction); + constraint.setCoefficient(isVariationVariable, -(rangeAction.getMaxAdmissibleSetpoint(initialSetpoint) + RANGE_ACTION_SETPOINT_EPSILON - rangeAction.getMinAdmissibleSetpoint(initialSetpoint))); + } } private void addMaxRaConstraint(LinearProblem linearProblem, State state) { diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblem.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblem.java index 7c01284a28..0c868cb51f 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblem.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblem.java @@ -468,6 +468,40 @@ public OpenRaoMPConstraint getRangeActionAbsoluteVariationConstraint(RangeAction return solver.getConstraint(rangeActionAbsoluteVariationConstraintId(rangeAction, state)); } + public OpenRaoMPVariable addTotalPstRangeActionTapVariationVariable(PstRangeAction pstRangeAction, State state, LinearProblem.VariationDirectionExtension variationDirection) { + return solver.makeIntVar(0, infinity(), totalPstRangeActionTapVariationVariableId(pstRangeAction, state, variationDirection)); + } + + public OpenRaoMPVariable getTotalPstRangeActionTapVariationVariable(PstRangeAction pstRangeAction, State state, LinearProblem.VariationDirectionExtension variationDirection) { + return solver.getVariable(totalPstRangeActionTapVariationVariableId(pstRangeAction, state, variationDirection)); + } + + public OpenRaoMPConstraint addTotalPstRangeActionTapVariationConstraint(PstRangeAction pstRangeAction, State state) { + return solver.makeConstraint(0, 0, totalPstRangeActionTapVariationConstraintId(pstRangeAction, state)); + } + + public OpenRaoMPConstraint getTotalPstRangeActionTapVariationConstraint(PstRangeAction pstRangeAction, State state) { + return solver.getConstraint(totalPstRangeActionTapVariationConstraintId(pstRangeAction, state)); + } + + public OpenRaoMPVariable addTapVariable(PstRangeAction pstRangeAction, State state) { + int minTap = pstRangeAction.getTapToAngleConversionMap().keySet().stream().min(Integer::compareTo).orElseThrow(); + int maxTap = pstRangeAction.getTapToAngleConversionMap().keySet().stream().max(Integer::compareTo).orElseThrow(); + return solver.makeIntVar(minTap, maxTap, tapVariableId(pstRangeAction, state)); + } + + public OpenRaoMPVariable getTapVariable(PstRangeAction pstRangeAction, State state) { + return solver.getVariable(tapVariableId(pstRangeAction, state)); + } + + public OpenRaoMPConstraint addTapConstraint(PstRangeAction pstRangeAction, State state) { + return solver.makeConstraint(0, 0, tapConstraintId(pstRangeAction, state)); + } + + public OpenRaoMPConstraint getTapConstraint(PstRangeAction pstRangeAction, State state) { + return solver.getConstraint(tapConstraintId(pstRangeAction, state)); + } + public double infinity() { return solver.infinity(); } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemBuilder.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemBuilder.java index 91e94a828e..d5ea4cc2db 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemBuilder.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemBuilder.java @@ -118,10 +118,17 @@ public LinearProblemBuilder withInitialRangeActionActivationResult(RangeActionAc } private ProblemFiller buildCoreProblemFiller() { - return new CoreProblemFiller( + return parameters.getObjectiveFunction().costOptimization() ? new CostCoreProblemFiller( inputs.optimizationPerimeter(), inputs.prePerimeterSetpoints(), - parameters.getRangeActionParameters(), + parameters.getRangeActionParameters(), + parameters.getObjectiveFunctionUnit(), + parameters.getRaRangeShrinking(), + parameters.getRangeActionParameters().getPstModel() + ) : new MarginCoreProblemFiller( + inputs.optimizationPerimeter(), + inputs.prePerimeterSetpoints(), + parameters.getRangeActionParameters(), parameters.getObjectiveFunctionUnit(), parameters.getRaRangeShrinking(), parameters.getRangeActionParameters().getPstModel() @@ -140,8 +147,8 @@ private ProblemFiller buildMaxMinRelativeMarginFiller() { private ProblemFiller buildMaxMinMarginFiller() { return new MaxMinMarginFiller( inputs.optimizationPerimeter().getOptimizedFlowCnecs(), - parameters.getObjectiveFunctionUnit() - ); + parameters.getObjectiveFunctionUnit(), + parameters.getObjectiveFunction().costOptimization()); } private ProblemFiller buildMnecFiller() { @@ -163,9 +170,9 @@ private ProblemFiller buildLoopFlowFiller() { private ProblemFiller buildUnoptimizedCnecFiller() { return new UnoptimizedCnecFiller( - inputs.optimizationPerimeter().getFlowCnecs(), - inputs.prePerimeterFlowResult(), - parameters.getUnoptimizedCnecParameters() + inputs.optimizationPerimeter().getFlowCnecs(), + inputs.prePerimeterFlowResult(), + parameters.getUnoptimizedCnecParameters() ); } @@ -173,7 +180,9 @@ private ProblemFiller buildIntegerPstTapFiller(Map> p return new DiscretePstTapFiller( inputs.optimizationPerimeter(), pstRangeActions, - inputs.prePerimeterSetpoints() + inputs.prePerimeterSetpoints(), + parameters.getRangeActionParameters(), + parameters.getObjectiveFunction().costOptimization() ); } @@ -194,7 +203,7 @@ private ProblemFiller buildRaUsageLimitsFiller() { inputs.prePerimeterSetpoints(), parameters.getRaLimitationParameters(), parameters.getRangeActionParameters().getPstModel() == RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS, - inputs.network()); + inputs.network(), parameters.getObjectiveFunction().costOptimization()); } private Map>> copyWithoutPstRangeActions(Map>> inRangeActions) { diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemIdGenerator.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemIdGenerator.java index 35345d76ed..e21ebd1bb0 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemIdGenerator.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemIdGenerator.java @@ -49,9 +49,9 @@ public final class LinearProblemIdGenerator { private static final String PST_ABSOLUTE_VARIATION_FROM_INITIAL_TAP = "pstabsolutevariationfrominitialtap"; private static final String MAX_ELEMENTARY_ACTIONS_PER_TSO = "maxelementaryactionspertso"; private static final String RANGE_ACTION_VARIATION = "rangeactionvariation"; - private static final String RANGE_ACTION_ACTIVATION = "rangeactionactivation"; private static final String RANGE_ACTION_SET_POINT_VARIATION = "rangeactionsetpointvariation"; private static final String RANGE_ACTION_ABSOLUTE_VARIATION = "rangeactionabsolutevariation"; + private static final String TOTAL_PST_RANGE_ACTION_TAP_VARIATION = "totalpstrangeactiontapvariation"; private LinearProblemIdGenerator() { // Should not be instantiated @@ -228,4 +228,20 @@ public static String rangeActionSetPointVariationConstraintId(RangeAction ran public static String rangeActionAbsoluteVariationConstraintId(RangeAction rangeAction, State state) { return RANGE_ACTION_ABSOLUTE_VARIATION + SEPARATOR + rangeAction.getId() + SEPARATOR + state.getId() + SEPARATOR + CONSTRAINT_SUFFIX; } + + public static String totalPstRangeActionTapVariationVariableId(PstRangeAction pstRangeAction, State state, LinearProblem.VariationDirectionExtension variationDirection) { + return TOTAL_PST_RANGE_ACTION_TAP_VARIATION + SEPARATOR + pstRangeAction.getId() + SEPARATOR + state.getId() + SEPARATOR + VARIABLE_SUFFIX + SEPARATOR + variationDirection; + } + + public static String totalPstRangeActionTapVariationConstraintId(PstRangeAction pstRangeAction, State state) { + return TOTAL_PST_RANGE_ACTION_TAP_VARIATION + SEPARATOR + pstRangeAction.getId() + SEPARATOR + state.getId() + SEPARATOR + CONSTRAINT_SUFFIX; + } + + public static String tapVariableId(PstRangeAction pstRangeAction, State state) { + return TAP + SEPARATOR + pstRangeAction.getId() + SEPARATOR + state.getId() + SEPARATOR + VARIABLE_SUFFIX; + } + + public static String tapConstraintId(PstRangeAction pstRangeAction, State state) { + return TAP + SEPARATOR + pstRangeAction.getId() + SEPARATOR + state.getId() + SEPARATOR + CONSTRAINT_SUFFIX; + } } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/AbstractFunctionalCostComputer.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/AbstractFunctionalCostComputer.java new file mode 100644 index 0000000000..bfcdb039a5 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/AbstractFunctionalCostComputer.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 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.result.functionalcostcomputer; + +import com.powsybl.openrao.data.crac.api.*; +import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; + +import java.util.Map; +import java.util.stream.DoubleStream; + +/** + * @author Thomas Bouquet {@literal } + */ +public abstract class AbstractFunctionalCostComputer { + protected final OptimizationResult secondPreventivePerimeterResult; + protected final Map postContingencyResults; + + protected AbstractFunctionalCostComputer(OptimizationResult secondPreventivePerimeterResult, Map postContingencyResults) { + this.secondPreventivePerimeterResult = secondPreventivePerimeterResult; + this.postContingencyResults = postContingencyResults; + } + + protected DoubleStream streamPostContingencyResultsBeforeInstant(Instant instant) { + return postContingencyResults.entrySet().stream() + .filter(entry -> !entry.getKey().getInstant().comesAfter(instant)) + .map(Map.Entry::getValue) + .filter(AbstractFunctionalCostComputer::hasActualFunctionalCost) + .mapToDouble(OptimizationResult::getFunctionalCost); + } + + /** + * Returns true if the perimeter has an actual functional cost, ie has CNECs + * (as opposed to a perimeter with pure MNECs only) + */ + private static boolean hasActualFunctionalCost(OptimizationResult perimeterResult) { + return !perimeterResult.getMostLimitingElements(1).isEmpty(); + } + + public abstract double computeFunctionalCost(Instant instant); +} diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/MaximumFunctionalCostComputer.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/MaximumFunctionalCostComputer.java new file mode 100644 index 0000000000..b28272c014 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/MaximumFunctionalCostComputer.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, 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.result.functionalcostcomputer; + +import com.powsybl.openrao.data.crac.api.Instant; +import com.powsybl.openrao.data.crac.api.State; +import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; + +import java.util.Map; + +/** + * @author Thomas Bouquet {@literal } + */ +public class MaximumFunctionalCostComputer extends AbstractFunctionalCostComputer { + public MaximumFunctionalCostComputer(OptimizationResult secondPreventivePerimeterResult, Map postContingencyResults) { + super(secondPreventivePerimeterResult, postContingencyResults); + } + + @Override + public double computeFunctionalCost(Instant instant) { + return Math.max(secondPreventivePerimeterResult.getFunctionalCost(), streamPostContingencyResultsBeforeInstant(instant).max().orElse(-Double.MAX_VALUE)); + } +} diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/TotalFunctionalCostComputer.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/TotalFunctionalCostComputer.java new file mode 100644 index 0000000000..0ea9ef1731 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/TotalFunctionalCostComputer.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, 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.result.functionalcostcomputer; + +import com.powsybl.openrao.data.crac.api.Instant; +import com.powsybl.openrao.data.crac.api.State; +import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; + +import java.util.Map; + +/** + * @author Thomas Bouquet {@literal } + */ +public class TotalFunctionalCostComputer extends AbstractFunctionalCostComputer { + public TotalFunctionalCostComputer(OptimizationResult secondPreventivePerimeterResult, Map postContingencyResults) { + super(secondPreventivePerimeterResult, postContingencyResults); + } + + @Override + public double computeFunctionalCost(Instant instant) { + return instant == null ? 0.0 : secondPreventivePerimeterResult.getFunctionalCost() + streamPostContingencyResultsBeforeInstant(instant).sum(); + } +} diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResult.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResult.java index 5dd6246b47..b28d9c7cf1 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResult.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResult.java @@ -40,8 +40,9 @@ public class CurativeWithSecondPraoResult implements OptimizationResult { private final FlowResult postCraSensitivityFlowResult; // contains final flows private final ObjectiveFunctionResult postCraSensitivityObjectiveResult; // contains final flows private final SensitivityResult postCraSensitivitySensitivityResult; // contains final flows + private final boolean costOptimization; - private CurativeWithSecondPraoResult(State state, OptimizationResult firstCraoResult, OptimizationResult secondPraoResult, Set> remedialActionsExcludedFromSecondPreventive, FlowResult postCraSensitivityFlowResult, ObjectiveFunctionResult postCraSensitivityObjectiveResult, SensitivityResult postCraSensitivitySensitivityResult) { + private CurativeWithSecondPraoResult(State state, OptimizationResult firstCraoResult, OptimizationResult secondPraoResult, Set> remedialActionsExcludedFromSecondPreventive, FlowResult postCraSensitivityFlowResult, ObjectiveFunctionResult postCraSensitivityObjectiveResult, SensitivityResult postCraSensitivitySensitivityResult, boolean costOptimization) { this.state = state; this.firstCraoResult = firstCraoResult; this.secondPraoResult = secondPraoResult; @@ -49,10 +50,11 @@ private CurativeWithSecondPraoResult(State state, OptimizationResult firstCraoRe this.postCraSensitivityFlowResult = postCraSensitivityFlowResult; this.postCraSensitivityObjectiveResult = postCraSensitivityObjectiveResult; this.postCraSensitivitySensitivityResult = postCraSensitivitySensitivityResult; + this.costOptimization = costOptimization; } - public CurativeWithSecondPraoResult(State state, OptimizationResult firstCraoResult, OptimizationResult secondPraoResult, Set> remedialActionsExcludedFromSecondPreventive, PrePerimeterResult postCraPrePerimeterResult) { - this(state, firstCraoResult, secondPraoResult, remedialActionsExcludedFromSecondPreventive, postCraPrePerimeterResult, postCraPrePerimeterResult, postCraPrePerimeterResult); + public CurativeWithSecondPraoResult(State state, OptimizationResult firstCraoResult, OptimizationResult secondPraoResult, Set> remedialActionsExcludedFromSecondPreventive, PrePerimeterResult postCraPrePerimeterResult, boolean costOptimization) { + this(state, firstCraoResult, secondPraoResult, remedialActionsExcludedFromSecondPreventive, postCraPrePerimeterResult, postCraPrePerimeterResult, postCraPrePerimeterResult, costOptimization); } private void checkState(State stateToCheck) { @@ -123,9 +125,13 @@ public Set getActivatedNetworkActions() { @Override public double getFunctionalCost() { - // Careful : this returns functional cost over all curative perimeters, but it should be enough for normal use - // since we never really need functional cost per perimeter at the end of the RAO - return postCraSensitivityObjectiveResult.getFunctionalCost(); + if (costOptimization) { + return getActivatedNetworkActions().stream().mapToDouble(networkAction -> networkAction.getActivationCost().orElse(0.0)).sum(); + } else { + // Careful : this returns functional cost over all curative perimeters, but it should be enough for normal use + // since we never really need functional cost per perimeter at the end of the RAO + return postCraSensitivityObjectiveResult.getFunctionalCost(); + } } @Override diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/LinearProblemResult.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/LinearProblemResult.java index d1e1852808..3da997ce45 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/LinearProblemResult.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/LinearProblemResult.java @@ -22,8 +22,8 @@ public LinearProblemResult(LinearProblem linearProblem, RangeActionSetpointResul optimizationContext.getRangeActionsPerState().forEach((state, rangeActions) -> rangeActions.forEach(rangeAction -> { if (linearProblem.getAbsoluteRangeActionVariationVariable(rangeAction, state).solutionValue() > 1e-6) { - double setpoint = linearProblem.getRangeActionSetpointVariable(rangeAction, state).solutionValue(); - putResult(rangeAction, state, setpoint); + double setPoint = linearProblem.getRangeActionSetpointVariable(rangeAction, state).solutionValue(); + putResult(rangeAction, state, setPoint); } }) ); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/PreventiveAndCurativesRaoResultImpl.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/PreventiveAndCurativesRaoResultImpl.java index a192c51bfc..903259a4e1 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/PreventiveAndCurativesRaoResultImpl.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/PreventiveAndCurativesRaoResultImpl.java @@ -26,6 +26,8 @@ import com.powsybl.openrao.searchtreerao.castor.algorithm.Perimeter; import com.powsybl.openrao.searchtreerao.result.api.*; import com.powsybl.openrao.searchtreerao.castor.algorithm.StateTree; +import com.powsybl.openrao.searchtreerao.result.functionalcostcomputer.MaximumFunctionalCostComputer; +import com.powsybl.openrao.searchtreerao.result.functionalcostcomputer.TotalFunctionalCostComputer; import java.util.*; @@ -242,6 +244,9 @@ public OptimizationResult getOptimizationResult(Instant optimizedInstant, State @Override public double getFunctionalCost(Instant optimizedInstant) { + if (objectiveFunctionParameters.getType().costOptimization()) { + return new TotalFunctionalCostComputer(secondPreventivePerimeterResult, postContingencyResults).computeFunctionalCost(optimizedInstant); + } if (optimizedInstant == null) { return initialResult.getFunctionalCost(); } else if (optimizedInstant.isPreventive() || optimizedInstant.isOutage() || postContingencyResults.isEmpty() || @@ -254,7 +259,7 @@ public double getFunctionalCost(Instant optimizedInstant) { } else { // No second preventive was run => use CRAO1 results // OR ARA - return objectiveFunctionParameters.getType().costOptimization() ? getTotalFunctionalCostForInstant(optimizedInstant) : getHighestFunctionalForInstant(optimizedInstant); + return new MaximumFunctionalCostComputer(secondPreventivePerimeterResult, postContingencyResults).computeFunctionalCost(optimizedInstant); } } diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/LinearProblemBuilderTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/LinearProblemBuilderTest.java index c9d0aa100d..3fcc6e2c46 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/LinearProblemBuilderTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/LinearProblemBuilderTest.java @@ -75,7 +75,7 @@ void testBuildMaxMarginContinuous() { assertNotNull(linearProblem); List fillers = linearProblem.getFillers(); assertEquals(3, fillers.size()); - assertInstanceOf(CoreProblemFiller.class, fillers.get(0)); + assertInstanceOf(MarginCoreProblemFiller.class, fillers.get(0)); assertInstanceOf(MaxMinMarginFiller.class, fillers.get(1)); assertInstanceOf(ContinuousRangeActionGroupFiller.class, fillers.get(2)); } @@ -89,7 +89,7 @@ void testBuildMaxMarginDiscrete() { assertNotNull(linearProblem); List fillers = linearProblem.getFillers(); assertEquals(5, fillers.size()); - assertInstanceOf(CoreProblemFiller.class, fillers.get(0)); + assertInstanceOf(MarginCoreProblemFiller.class, fillers.get(0)); assertInstanceOf(MaxMinMarginFiller.class, fillers.get(1)); assertInstanceOf(DiscretePstTapFiller.class, fillers.get(2)); assertInstanceOf(DiscretePstGroupFiller.class, fillers.get(3)); @@ -105,7 +105,7 @@ void testBuildMaxRelativeMarginContinuous() { assertNotNull(linearProblem); List fillers = linearProblem.getFillers(); assertEquals(3, fillers.size()); - assertInstanceOf(CoreProblemFiller.class, fillers.get(0)); + assertInstanceOf(MarginCoreProblemFiller.class, fillers.get(0)); assertInstanceOf(MaxMinRelativeMarginFiller.class, fillers.get(1)); assertInstanceOf(ContinuousRangeActionGroupFiller.class, fillers.get(2)); } @@ -122,7 +122,7 @@ void testBuildMaxMarginContinuousMnecLoopflowUnoptimized() { assertNotNull(linearProblem); List fillers = linearProblem.getFillers(); assertEquals(6, fillers.size()); - assertInstanceOf(CoreProblemFiller.class, fillers.get(0)); + assertInstanceOf(MarginCoreProblemFiller.class, fillers.get(0)); assertInstanceOf(MaxMinMarginFiller.class, fillers.get(1)); assertInstanceOf(MnecFiller.class, fillers.get(2)); assertInstanceOf(MaxLoopFlowFiller.class, fillers.get(3)); @@ -143,7 +143,7 @@ void testBuildMaxMarginContinuousRaLimitation() { assertNotNull(linearProblem); List fillers = linearProblem.getFillers(); assertEquals(4, fillers.size()); - assertInstanceOf(CoreProblemFiller.class, fillers.get(0)); + assertInstanceOf(MarginCoreProblemFiller.class, fillers.get(0)); assertInstanceOf(MaxMinMarginFiller.class, fillers.get(1)); assertInstanceOf(ContinuousRangeActionGroupFiller.class, fillers.get(2)); assertInstanceOf(RaUsageLimitsFiller.class, fillers.get(3)); diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/ContinuousRangeActionGroupFillerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/ContinuousRangeActionGroupFillerTest.java index 897456d3e0..9b8d62d4d6 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/ContinuousRangeActionGroupFillerTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/ContinuousRangeActionGroupFillerTest.java @@ -58,7 +58,7 @@ void testFillAndUpdateMethods() throws IOException { RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(new RaoParameters()); - CoreProblemFiller coreProblemFiller = new CoreProblemFiller( + MarginCoreProblemFiller coreProblemFiller = new MarginCoreProblemFiller( optimizationPerimeter, initialRangeActionSetpointResult, rangeActionParameters, diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CostCoreProblemFillerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CostCoreProblemFillerTest.java new file mode 100644 index 0000000000..4e27cd3036 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CostCoreProblemFillerTest.java @@ -0,0 +1,781 @@ +/* + * Copyright (c) 2024, 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.linearoptimisation.algorithms.fillers; + +import com.powsybl.iidm.network.TwoSides; +import com.powsybl.openrao.commons.OpenRaoException; +import com.powsybl.openrao.commons.Unit; +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.RangeAction; +import com.powsybl.openrao.data.raoresult.api.ComputationStatus; +import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters; +import com.powsybl.openrao.raoapi.parameters.RaoParameters; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.LinearProblem; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.LinearProblemBuilder; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPConstraint; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPVariable; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +/** + * @author Thomas Bouquet {@literal } + */ +class CostCoreProblemFillerTest extends AbstractFillerTest { + private LinearProblem linearProblem; + private CostCoreProblemFiller coreProblemFiller; + private RangeActionSetpointResult initialRangeActionSetpointResult; + // some additional data + private double minAlpha; + private double maxAlpha; + private double initialAlpha; + + @BeforeEach + public void setUp() throws IOException { + init(); + // arrange some additional data + network.getTwoWindingsTransformer(RANGE_ACTION_ELEMENT_ID).getPhaseTapChanger().setTapPosition(TAP_INITIAL); + minAlpha = crac.getRangeAction(RANGE_ACTION_ID).getMinAdmissibleSetpoint(0); + maxAlpha = crac.getRangeAction(RANGE_ACTION_ID).getMaxAdmissibleSetpoint(0); + initialAlpha = pstRangeAction.convertTapToAngle(network.getTwoWindingsTransformer(RANGE_ACTION_ELEMENT_ID).getPhaseTapChanger().getTapPosition()); + + initialRangeActionSetpointResult = new RangeActionSetpointResultImpl(Map.of(pstRangeAction, initialAlpha)); + } + + private void buildLinearProblem() { + linearProblem = new LinearProblemBuilder() + .withProblemFiller(coreProblemFiller) + .withSolver(RangeActionsOptimizationParameters.Solver.SCIP) + .withInitialRangeActionActivationResult(getInitialRangeActionActivationResult()) + .build(); + linearProblem.fill(flowResult, sensitivityResult); + } + + private void initializeForPreventive(double pstSensitivityThreshold, double hvdcSensitivityThreshold, double injectionSensitivityThreshold) { + initialize(Set.of(cnec1), pstSensitivityThreshold, hvdcSensitivityThreshold, injectionSensitivityThreshold, crac.getPreventiveState(), false, RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); + } + + private void initializeForGlobal(RangeActionsOptimizationParameters.PstModel pstModel) { + initialize(Set.of(cnec1, cnec2), 1e-6, 1e-6, 1e-6, crac.getPreventiveState(), false, pstModel); + } + + private void initialize(Set cnecs, double pstSensitivityThreshold, double hvdcSensitivityThreshold, double injectionSensitivityThreshold, State mainState, boolean raRangeShrinking, RangeActionsOptimizationParameters.PstModel pstModel) { + OptimizationPerimeter optimizationPerimeter = Mockito.mock(OptimizationPerimeter.class); + Mockito.when(optimizationPerimeter.getFlowCnecs()).thenReturn(cnecs); + Mockito.when(optimizationPerimeter.getMainOptimizationState()).thenReturn(mainState); + + Map>> rangeActions = new HashMap<>(); + cnecs.forEach(cnec -> rangeActions.put(cnec.getState(), Set.of(pstRangeAction))); + Mockito.when(optimizationPerimeter.getRangeActionsPerState()).thenReturn(rangeActions); + + RaoParameters raoParameters = new RaoParameters(); + raoParameters.getRangeActionsOptimizationParameters().setPstSensitivityThreshold(pstSensitivityThreshold); + raoParameters.getRangeActionsOptimizationParameters().setHvdcSensitivityThreshold(hvdcSensitivityThreshold); + raoParameters.getRangeActionsOptimizationParameters().setInjectionRaSensitivityThreshold(injectionSensitivityThreshold); + RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(raoParameters); + + coreProblemFiller = new CostCoreProblemFiller( + optimizationPerimeter, + initialRangeActionSetpointResult, + rangeActionParameters, + Unit.MEGAWATT, raRangeShrinking, pstModel); + buildLinearProblem(); + } + + @Test + void fillTestOnPreventive() { + initializeForPreventive(1e-6, 1e-6, 1e-6); + State state = cnec1.getState(); + + // check range action setpoint variable + OpenRaoMPVariable setPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, state); + assertNotNull(setPointVariable); + assertEquals(minAlpha, setPointVariable.lb(), DOUBLE_TOLERANCE); + assertEquals(maxAlpha, setPointVariable.ub(), DOUBLE_TOLERANCE); + + // check upward variation variable + OpenRaoMPVariable upwardVariationVariable = linearProblem.getRangeActionVariationVariable(pstRangeAction, state, LinearProblem.VariationDirectionExtension.UPWARD); + assertNotNull(upwardVariationVariable); + assertEquals(0, upwardVariationVariable.lb(), 0.01); + assertEquals(linearProblem.infinity(), upwardVariationVariable.ub(), linearProblem.infinity() * 1e-3); + + // check downward variation variable + OpenRaoMPVariable downwardVariationVariable = linearProblem.getRangeActionVariationVariable(pstRangeAction, state, LinearProblem.VariationDirectionExtension.DOWNWARD); + assertNotNull(downwardVariationVariable); + assertEquals(0, downwardVariationVariable.lb(), 0.01); + assertEquals(linearProblem.infinity(), downwardVariationVariable.ub(), linearProblem.infinity() * 1e-3); + + // check binary activation variable + OpenRaoMPVariable activationVariable = linearProblem.getRangeActionVariationBinary(pstRangeAction, state); + assertNotNull(activationVariable); + assertEquals(0, activationVariable.lb(), 0.01); + assertEquals(1, activationVariable.ub(), 0.01); + + // check flow variable for cnec1 + OpenRaoMPVariable flowVariable = linearProblem.getFlowVariable(cnec1, TwoSides.ONE); + assertNotNull(flowVariable); + assertEquals(-linearProblem.infinity(), flowVariable.lb(), linearProblem.infinity() * 1e-3); + assertEquals(linearProblem.infinity(), flowVariable.ub(), linearProblem.infinity() * 1e-3); + + // check flow constraint for cnec1 + OpenRaoMPConstraint flowConstraint = linearProblem.getFlowConstraint(cnec1, TwoSides.ONE); + assertNotNull(flowConstraint); + assertEquals(REF_FLOW_CNEC1_IT1 - initialAlpha * SENSI_CNEC1_IT1, flowConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(REF_FLOW_CNEC1_IT1 - initialAlpha * SENSI_CNEC1_IT1, flowConstraint.ub(), DOUBLE_TOLERANCE); + assertEquals(1, flowConstraint.getCoefficient(flowVariable), 0.1); + assertEquals(-SENSI_CNEC1_IT1, flowConstraint.getCoefficient(setPointVariable), DOUBLE_TOLERANCE); + + // check flow variable for cnec2 does not exist + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowVariable(cnec2, TwoSides.TWO)); + assertEquals("Variable Tieline BE FR - Defaut - N-1 NL1-NL3_two_flow_variable has not been created yet", e.getMessage()); + + // check flow constraint for cnec2 does not exist + e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowConstraint(cnec2, TwoSides.TWO)); + assertEquals("Constraint Tieline BE FR - Defaut - N-1 NL1-NL3_two_flow_constraint has not been created yet", e.getMessage()); + + // check set-point variation constraint + OpenRaoMPConstraint setPointVariationConstraint = linearProblem.getRangeActionSetPointVariationConstraint(pstRangeAction, state); + assertNotNull(setPointVariationConstraint); + assertEquals(1.9479, setPointVariationConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(1.9479, setPointVariationConstraint.ub(), DOUBLE_TOLERANCE); + assertEquals(1, setPointVariationConstraint.getCoefficient(setPointVariable)); + assertEquals(-1, setPointVariationConstraint.getCoefficient(upwardVariationVariable)); + assertEquals(1, setPointVariationConstraint.getCoefficient(downwardVariationVariable)); + + // check activation constraint + OpenRaoMPConstraint activationConstraint = linearProblem.getIsVariationConstraint(pstRangeAction, state); + assertNotNull(activationConstraint); + assertEquals(0, activationConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(linearProblem.infinity(), activationConstraint.ub(), linearProblem.infinity() * 1e-3); + assertEquals(-1, activationConstraint.getCoefficient(upwardVariationVariable)); + assertEquals(-1, activationConstraint.getCoefficient(downwardVariationVariable)); + assertEquals(11.6782, activationConstraint.getCoefficient(activationVariable), DOUBLE_TOLERANCE); + + // check the number of variables and constraints + // total number of variables 4 : + // - 1 per CNEC (flow) + // - 5 per range action (set-point, absolute variation, activation and variation up/down) + // total number of constraints 4 : + // - 1 per CNEC (flow constraint) + // - 3 per range action (activation and set-point + absolute variation) + assertEquals(6, linearProblem.numVariables()); + assertEquals(4, linearProblem.numConstraints()); + + // check objective + assertEquals(15.0, linearProblem.getObjective().getCoefficient(activationVariable)); + } + + @Test + void fillTestOnPreventiveFiltered() { + initializeForPreventive(2.5, 2.5, 2.5); + State state = cnec1.getState(); + + // check range action setpoint variable + OpenRaoMPVariable setPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, state); + assertNotNull(setPointVariable); + assertEquals(minAlpha, setPointVariable.lb(), DOUBLE_TOLERANCE); + assertEquals(maxAlpha, setPointVariable.ub(), DOUBLE_TOLERANCE); + + // check upward variation variable + OpenRaoMPVariable upwardVariationVariable = linearProblem.getRangeActionVariationVariable(pstRangeAction, state, LinearProblem.VariationDirectionExtension.UPWARD); + assertNotNull(upwardVariationVariable); + assertEquals(0, upwardVariationVariable.lb(), 0.01); + assertEquals(linearProblem.infinity(), upwardVariationVariable.ub(), linearProblem.infinity() * 1e-3); + + // check downward variation variable + OpenRaoMPVariable downwardVariationVariable = linearProblem.getRangeActionVariationVariable(pstRangeAction, state, LinearProblem.VariationDirectionExtension.DOWNWARD); + assertNotNull(downwardVariationVariable); + assertEquals(0, downwardVariationVariable.lb(), 0.01); + assertEquals(linearProblem.infinity(), downwardVariationVariable.ub(), linearProblem.infinity() * 1e-3); + + // check binary activation variable + OpenRaoMPVariable activationVariable = linearProblem.getRangeActionVariationBinary(pstRangeAction, state); + assertNotNull(activationVariable); + assertEquals(0, activationVariable.lb(), 0.01); + assertEquals(1, activationVariable.ub(), 0.01); + + // check flow variable for cnec1 + OpenRaoMPVariable flowVariable = linearProblem.getFlowVariable(cnec1, TwoSides.ONE); + assertNotNull(flowVariable); + assertEquals(-linearProblem.infinity(), flowVariable.lb(), linearProblem.infinity() * 1e-3); + assertEquals(linearProblem.infinity(), flowVariable.ub(), linearProblem.infinity() * 1e-3); + + // check flow constraint for cnec1 + OpenRaoMPConstraint flowConstraint = linearProblem.getFlowConstraint(cnec1, TwoSides.ONE); + assertNotNull(flowConstraint); + assertEquals(REF_FLOW_CNEC1_IT1 - initialAlpha * 0, flowConstraint.lb(), DOUBLE_TOLERANCE); // sensitivity filtered (= 0) + assertEquals(REF_FLOW_CNEC1_IT1 - initialAlpha * 0, flowConstraint.ub(), DOUBLE_TOLERANCE); // sensitivity filtered (= 0) + assertEquals(1, flowConstraint.getCoefficient(flowVariable), 0.1); + assertEquals(0, flowConstraint.getCoefficient(setPointVariable), DOUBLE_TOLERANCE); // sensitivity filtered (= 0) + + // check flow variable for cnec2 does not exist + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowVariable(cnec2, TwoSides.TWO)); + assertEquals("Variable Tieline BE FR - Defaut - N-1 NL1-NL3_two_flow_variable has not been created yet", e.getMessage()); + + // check flow constraint for cnec2 does not exist + e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowConstraint(cnec2, TwoSides.TWO)); + assertEquals("Constraint Tieline BE FR - Defaut - N-1 NL1-NL3_two_flow_constraint has not been created yet", e.getMessage()); + + // check set-point variation constraint + OpenRaoMPConstraint setPointVariationConstraint = linearProblem.getRangeActionSetPointVariationConstraint(pstRangeAction, state); + assertNotNull(setPointVariationConstraint); + assertEquals(1.9479, setPointVariationConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(1.9479, setPointVariationConstraint.ub(), DOUBLE_TOLERANCE); + assertEquals(1, setPointVariationConstraint.getCoefficient(setPointVariable)); + assertEquals(-1, setPointVariationConstraint.getCoefficient(upwardVariationVariable)); + assertEquals(1, setPointVariationConstraint.getCoefficient(downwardVariationVariable)); + + // check activation constraint + OpenRaoMPConstraint activationConstraint = linearProblem.getIsVariationConstraint(pstRangeAction, state); + assertNotNull(activationConstraint); + assertEquals(0, activationConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(linearProblem.infinity(), activationConstraint.ub(), linearProblem.infinity() * 1e-3); + assertEquals(-1, activationConstraint.getCoefficient(upwardVariationVariable)); + assertEquals(-1, activationConstraint.getCoefficient(downwardVariationVariable)); + assertEquals(11.6782, activationConstraint.getCoefficient(activationVariable), DOUBLE_TOLERANCE); + + // check the number of variables and constraints + // total number of variables 4 : + // - 1 per CNEC (flow) + // - 5 per range action (set-point, absolute variation, activation and variation up/down) + // total number of constraints 4 : + // - 1 per CNEC (flow constraint) + // - 3 per range action (activation and set-point + absolute variation) + assertEquals(6, linearProblem.numVariables()); + assertEquals(4, linearProblem.numConstraints()); + + // check objective + assertEquals(15.0, linearProblem.getObjective().getCoefficient(activationVariable)); + } + + @Test + void fillTestOnCurative() { + initialize(Set.of(cnec2), 1e-6, 1e-6, 1e-6, cnec2.getState(), false, RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); + State state = cnec2.getState(); + + // check range action setpoint variable + OpenRaoMPVariable setPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, state); + assertNotNull(setPointVariable); + assertEquals(minAlpha, setPointVariable.lb(), DOUBLE_TOLERANCE); + assertEquals(maxAlpha, setPointVariable.ub(), DOUBLE_TOLERANCE); + + // check upward variation variable + OpenRaoMPVariable upwardVariationVariable = linearProblem.getRangeActionVariationVariable(pstRangeAction, state, LinearProblem.VariationDirectionExtension.UPWARD); + assertNotNull(upwardVariationVariable); + assertEquals(0, upwardVariationVariable.lb(), 0.01); + assertEquals(linearProblem.infinity(), upwardVariationVariable.ub(), linearProblem.infinity() * 1e-3); + + // check downward variation variable + OpenRaoMPVariable downwardVariationVariable = linearProblem.getRangeActionVariationVariable(pstRangeAction, state, LinearProblem.VariationDirectionExtension.DOWNWARD); + assertNotNull(downwardVariationVariable); + assertEquals(0, downwardVariationVariable.lb(), 0.01); + assertEquals(linearProblem.infinity(), downwardVariationVariable.ub(), linearProblem.infinity() * 1e-3); + + // check binary activation variable + OpenRaoMPVariable activationVariable = linearProblem.getRangeActionVariationBinary(pstRangeAction, state); + assertNotNull(activationVariable); + assertEquals(0, activationVariable.lb(), 0.01); + assertEquals(1, activationVariable.ub(), 0.01); + + // check flow variable for cnec1 does not exist + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowVariable(cnec1, TwoSides.ONE)); + assertEquals("Variable Tieline BE FR - N - preventive_one_flow_variable has not been created yet", e.getMessage()); + + // check flow constraint for cnec1 does not exist + e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowConstraint(cnec1, TwoSides.ONE)); + assertEquals("Constraint Tieline BE FR - N - preventive_one_flow_constraint has not been created yet", e.getMessage()); + + // check flow variable for cnec2 + OpenRaoMPVariable flowVariable2 = linearProblem.getFlowVariable(cnec2, TwoSides.TWO); + assertNotNull(flowVariable2); + assertEquals(-linearProblem.infinity(), flowVariable2.lb(), linearProblem.infinity() * 1e-3); + assertEquals(linearProblem.infinity(), flowVariable2.ub(), linearProblem.infinity() * 1e-3); + + // check flow constraint for cnec2 + OpenRaoMPConstraint flowConstraint2 = linearProblem.getFlowConstraint(cnec2, TwoSides.TWO); + assertNotNull(flowConstraint2); + assertEquals(REF_FLOW_CNEC2_IT1 - initialAlpha * SENSI_CNEC2_IT1, flowConstraint2.lb(), DOUBLE_TOLERANCE); + assertEquals(REF_FLOW_CNEC2_IT1 - initialAlpha * SENSI_CNEC2_IT1, flowConstraint2.ub(), DOUBLE_TOLERANCE); + assertEquals(1, flowConstraint2.getCoefficient(flowVariable2), DOUBLE_TOLERANCE); + assertEquals(-SENSI_CNEC2_IT1, flowConstraint2.getCoefficient(setPointVariable), DOUBLE_TOLERANCE); + + // check set-point variation constraint + OpenRaoMPConstraint setPointVariationConstraint = linearProblem.getRangeActionSetPointVariationConstraint(pstRangeAction, state); + assertNotNull(setPointVariationConstraint); + assertEquals(1.9479, setPointVariationConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(1.9479, setPointVariationConstraint.ub(), DOUBLE_TOLERANCE); + assertEquals(1, setPointVariationConstraint.getCoefficient(setPointVariable)); + assertEquals(-1, setPointVariationConstraint.getCoefficient(upwardVariationVariable)); + assertEquals(1, setPointVariationConstraint.getCoefficient(downwardVariationVariable)); + + // check activation constraint + OpenRaoMPConstraint activationConstraint = linearProblem.getIsVariationConstraint(pstRangeAction, state); + assertNotNull(activationConstraint); + assertEquals(0, activationConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(linearProblem.infinity(), activationConstraint.ub(), linearProblem.infinity() * 1e-3); + assertEquals(-1, activationConstraint.getCoefficient(upwardVariationVariable)); + assertEquals(-1, activationConstraint.getCoefficient(downwardVariationVariable)); + assertEquals(11.6782, activationConstraint.getCoefficient(activationVariable), DOUBLE_TOLERANCE); + + // check the number of variables and constraints + // total number of variables 4 : + // - 1 per CNEC (flow) + // - 5 per range action (set-point, absolute variation, activation and variation up/down) + // total number of constraints 4 : + // - 1 per CNEC (flow constraint) + // - 3 per range action (activation and set-point + absolute variation) + assertEquals(6, linearProblem.numVariables()); + assertEquals(4, linearProblem.numConstraints()); + + // check objective + assertEquals(15.0, linearProblem.getObjective().getCoefficient(activationVariable)); + } + + @Test + void testContinuousPstMode() { + OpenRaoException exception = assertThrows(OpenRaoException.class, () -> initializeForGlobal(RangeActionsOptimizationParameters.PstModel.CONTINUOUS)); + assertEquals("Costly remedial action optimization is only available for the APPROXIMATED_INTEGERS mode of PST range actions.", exception.getMessage()); + } + + @Test + void fillTestOnGlobal() { + initializeForGlobal(RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); + State prevState = cnec1.getState(); + State curState = cnec2.getState(); + + // check relative setpoint constraint for PRA_PST_BE has not been created in curative. + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.getRangeActionRelativeSetpointConstraint(pstRangeAction, curState, LinearProblem.RaRangeShrinking.FALSE)); + assertEquals("Constraint PRA_PST_BE_N-1 NL1-NL3 - curative_relative_setpoint_constraint has not been created yet", e.getMessage()); + + // check range action setpoint variable for preventive state + OpenRaoMPVariable prevSetPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, prevState); + assertNotNull(prevSetPointVariable); + assertEquals(minAlpha, prevSetPointVariable.lb(), DOUBLE_TOLERANCE); + assertEquals(maxAlpha, prevSetPointVariable.ub(), DOUBLE_TOLERANCE); + + // check upward variation variable for preventive state + OpenRaoMPVariable prevUpwardVariationVariable = linearProblem.getRangeActionVariationVariable(pstRangeAction, prevState, LinearProblem.VariationDirectionExtension.UPWARD); + assertNotNull(prevUpwardVariationVariable); + assertEquals(0, prevUpwardVariationVariable.lb(), 0.01); + assertEquals(linearProblem.infinity(), prevUpwardVariationVariable.ub(), linearProblem.infinity() * 1e-3); + + // check downward variation variable for preventive state + OpenRaoMPVariable prevDownwardVariationVariable = linearProblem.getRangeActionVariationVariable(pstRangeAction, prevState, LinearProblem.VariationDirectionExtension.DOWNWARD); + assertNotNull(prevDownwardVariationVariable); + assertEquals(0, prevDownwardVariationVariable.lb(), 0.01); + assertEquals(linearProblem.infinity(), prevDownwardVariationVariable.ub(), linearProblem.infinity() * 1e-3); + + // check binary activation variable for preventive state + OpenRaoMPVariable prevActivationVariable = linearProblem.getRangeActionVariationBinary(pstRangeAction, prevState); + assertNotNull(prevActivationVariable); + assertEquals(0, prevActivationVariable.lb(), 0.01); + assertEquals(1, prevActivationVariable.ub(), 0.01); + + // check range action setpoint variable for curative state + OpenRaoMPVariable curSetPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, curState); + assertNotNull(curSetPointVariable); + assertEquals(minAlpha, curSetPointVariable.lb(), DOUBLE_TOLERANCE); + assertEquals(maxAlpha, curSetPointVariable.ub(), DOUBLE_TOLERANCE); + + // check upward variation variable for curative state + OpenRaoMPVariable curUpwardVariationVariable = linearProblem.getRangeActionVariationVariable(pstRangeAction, curState, LinearProblem.VariationDirectionExtension.UPWARD); + assertNotNull(curUpwardVariationVariable); + assertEquals(0, curUpwardVariationVariable.lb(), 0.01); + assertEquals(linearProblem.infinity(), curUpwardVariationVariable.ub(), linearProblem.infinity() * 1e-3); + + // check downward variation variable for curative state + OpenRaoMPVariable curDownwardVariationVariable = linearProblem.getRangeActionVariationVariable(pstRangeAction, curState, LinearProblem.VariationDirectionExtension.DOWNWARD); + assertNotNull(curDownwardVariationVariable); + assertEquals(0, curDownwardVariationVariable.lb(), 0.01); + assertEquals(linearProblem.infinity(), curDownwardVariationVariable.ub(), linearProblem.infinity() * 1e-3); + + // check binary activation variable for curative state + OpenRaoMPVariable curActivationVariable = linearProblem.getRangeActionVariationBinary(pstRangeAction, curState); + assertNotNull(curActivationVariable); + assertEquals(0, curActivationVariable.lb(), 0.01); + assertEquals(1, curActivationVariable.ub(), 0.01); + + // check flow variable for cnec1 + OpenRaoMPVariable flowVariable = linearProblem.getFlowVariable(cnec1, TwoSides.ONE); + assertNotNull(flowVariable); + assertEquals(-linearProblem.infinity(), flowVariable.lb(), linearProblem.infinity() * 1e-3); + assertEquals(linearProblem.infinity(), flowVariable.ub(), linearProblem.infinity() * 1e-3); + + // check flow constraint for cnec1 + OpenRaoMPConstraint flowConstraint = linearProblem.getFlowConstraint(cnec1, TwoSides.ONE); + assertNotNull(flowConstraint); + assertEquals(REF_FLOW_CNEC1_IT1 - initialAlpha * SENSI_CNEC1_IT1, flowConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(REF_FLOW_CNEC1_IT1 - initialAlpha * SENSI_CNEC1_IT1, flowConstraint.ub(), DOUBLE_TOLERANCE); + assertEquals(1, flowConstraint.getCoefficient(flowVariable), 0.1); + assertEquals(-SENSI_CNEC1_IT1, flowConstraint.getCoefficient(prevSetPointVariable), DOUBLE_TOLERANCE); + + // check flow variable for cnec2 + OpenRaoMPVariable flowVariable2 = linearProblem.getFlowVariable(cnec2, TwoSides.TWO); + assertNotNull(flowVariable2); + assertEquals(-linearProblem.infinity(), flowVariable2.lb(), linearProblem.infinity() * 1e-3); + assertEquals(linearProblem.infinity(), flowVariable2.ub(), linearProblem.infinity() * 1e-3); + + // check flow constraint for cnec2 + OpenRaoMPConstraint flowConstraint2 = linearProblem.getFlowConstraint(cnec2, TwoSides.TWO); + assertNotNull(flowConstraint2); + assertEquals(REF_FLOW_CNEC2_IT1 - initialAlpha * SENSI_CNEC2_IT1, flowConstraint2.lb(), DOUBLE_TOLERANCE); + assertEquals(REF_FLOW_CNEC2_IT1 - initialAlpha * SENSI_CNEC2_IT1, flowConstraint2.ub(), DOUBLE_TOLERANCE); + assertEquals(1, flowConstraint2.getCoefficient(flowVariable2), DOUBLE_TOLERANCE); + assertEquals(-SENSI_CNEC2_IT1, flowConstraint2.getCoefficient(curSetPointVariable), DOUBLE_TOLERANCE); + + // check set-point variation constraint for preventive state + OpenRaoMPConstraint prevSetPointVariationConstraint = linearProblem.getRangeActionSetPointVariationConstraint(pstRangeAction, prevState); + assertNotNull(prevSetPointVariationConstraint); + assertEquals(1.9479, prevSetPointVariationConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(1.9479, prevSetPointVariationConstraint.ub(), DOUBLE_TOLERANCE); + assertEquals(1, prevSetPointVariationConstraint.getCoefficient(prevSetPointVariable)); + assertEquals(-1, prevSetPointVariationConstraint.getCoefficient(prevUpwardVariationVariable)); + assertEquals(1, prevSetPointVariationConstraint.getCoefficient(prevDownwardVariationVariable)); + + // check activation constraint for preventive state + OpenRaoMPConstraint prevActivationConstraint = linearProblem.getIsVariationConstraint(pstRangeAction, prevState); + assertNotNull(prevActivationConstraint); + assertEquals(0, prevActivationConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(linearProblem.infinity(), prevActivationConstraint.ub(), linearProblem.infinity() * 1e-3); + assertEquals(-1, prevActivationConstraint.getCoefficient(prevUpwardVariationVariable)); + assertEquals(-1, prevActivationConstraint.getCoefficient(prevDownwardVariationVariable)); + assertEquals(11.6782, prevActivationConstraint.getCoefficient(prevActivationVariable), DOUBLE_TOLERANCE); + + // check set-point variation constraint for curative state + OpenRaoMPConstraint curSetPointVariationConstraint = linearProblem.getRangeActionSetPointVariationConstraint(pstRangeAction, curState); + assertNotNull(curSetPointVariationConstraint); + assertEquals(0.0, curSetPointVariationConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(0.0, curSetPointVariationConstraint.ub(), DOUBLE_TOLERANCE); + assertEquals(1, curSetPointVariationConstraint.getCoefficient(curSetPointVariable)); + assertEquals(-1, curSetPointVariationConstraint.getCoefficient(curUpwardVariationVariable)); + assertEquals(1, curSetPointVariationConstraint.getCoefficient(curDownwardVariationVariable)); + assertEquals(-1, curSetPointVariationConstraint.getCoefficient(prevSetPointVariable)); + + // check activation constraint for curative state + OpenRaoMPConstraint curActivationConstraint = linearProblem.getIsVariationConstraint(pstRangeAction, curState); + assertNotNull(curActivationConstraint); + assertEquals(0, curActivationConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(linearProblem.infinity(), curActivationConstraint.ub(), linearProblem.infinity() * 1e-3); + assertEquals(-1, curActivationConstraint.getCoefficient(curUpwardVariationVariable)); + assertEquals(-1, curActivationConstraint.getCoefficient(curDownwardVariationVariable)); + assertEquals(11.6782, curActivationConstraint.getCoefficient(curActivationVariable), DOUBLE_TOLERANCE); + + // check the number of variables and constraints + // total number of variables 10 : + // - 1 per CNEC (flow) + // - 5 per range action (set-point, absolute variation, activation and variation up/down) + // total number of constraints 6 or 7: + // - 1 per CNEC (flow constraint) + // - 3 per range action (activation and set-point + absolute variation) + // - 0 or 1 for curative range action (relative variation constraint) + assertEquals(12, linearProblem.numVariables()); + assertEquals(8, linearProblem.numConstraints()); + } + + private void updateLinearProblem() { + // arrange some additional data + network.getTwoWindingsTransformer(RANGE_ACTION_ELEMENT_ID).getPhaseTapChanger().setTapPosition(TAP_IT2); + initialAlpha = network.getTwoWindingsTransformer(RANGE_ACTION_ELEMENT_ID).getPhaseTapChanger().getCurrentStep().getAlpha(); + + when(flowResult.getFlow(cnec1, TwoSides.ONE, Unit.MEGAWATT)).thenReturn(REF_FLOW_CNEC1_IT2); + when(flowResult.getFlow(cnec2, TwoSides.TWO, Unit.MEGAWATT)).thenReturn(REF_FLOW_CNEC2_IT2); + when(sensitivityResult.getSensitivityValue(cnec1, TwoSides.ONE, pstRangeAction, Unit.MEGAWATT)).thenReturn(SENSI_CNEC1_IT2); + when(sensitivityResult.getSensitivityValue(cnec2, TwoSides.TWO, pstRangeAction, Unit.MEGAWATT)).thenReturn(SENSI_CNEC2_IT2); + + // update the problem + RangeActionSetpointResult rangeActionSetpointResult = new RangeActionSetpointResultImpl(Map.of(pstRangeAction, initialAlpha)); + linearProblem.updateBetweenSensiIteration(flowResult, sensitivityResult, new RangeActionActivationResultImpl(rangeActionSetpointResult)); + } + + @Test + void updateTestOnPreventive() { + initializeForPreventive(1e-6, 1e-6, 1e-6); + State state = cnec1.getState(); + // update the problem with new data + updateLinearProblem(); + + // some additional data + final double currentAlpha = pstRangeAction.convertTapToAngle(network.getTwoWindingsTransformer(RANGE_ACTION_ELEMENT_ID).getPhaseTapChanger().getTapPosition()); + + OpenRaoMPVariable setPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, state); + + // check flow variable for cnec1 + OpenRaoMPVariable flowVariable = linearProblem.getFlowVariable(cnec1, TwoSides.ONE); + assertNotNull(flowVariable); + assertEquals(-linearProblem.infinity(), flowVariable.lb(), linearProblem.infinity() * 1e-3); + assertEquals(linearProblem.infinity(), flowVariable.ub(), linearProblem.infinity() * 1e-3); + + // check flow constraint for cnec1 + OpenRaoMPConstraint flowConstraint = linearProblem.getFlowConstraint(cnec1, TwoSides.ONE); + assertNotNull(flowConstraint); + assertEquals(REF_FLOW_CNEC1_IT2 - currentAlpha * SENSI_CNEC1_IT2, flowConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(REF_FLOW_CNEC1_IT2 - currentAlpha * SENSI_CNEC1_IT2, flowConstraint.ub(), DOUBLE_TOLERANCE); + assertEquals(1, flowConstraint.getCoefficient(flowVariable), DOUBLE_TOLERANCE); + assertEquals(-SENSI_CNEC1_IT2, flowConstraint.getCoefficient(setPointVariable), DOUBLE_TOLERANCE); + + // check flow variable for cnec2 does not exist + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowVariable(cnec2, TwoSides.TWO)); + assertEquals("Variable Tieline BE FR - Defaut - N-1 NL1-NL3_two_flow_variable has not been created yet", e.getMessage()); + + // check flow constraint for cnec2 does not exist + e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowConstraint(cnec2, TwoSides.TWO)); + assertEquals("Constraint Tieline BE FR - Defaut - N-1 NL1-NL3_two_flow_constraint has not been created yet", e.getMessage()); + + // check the number of variables and constraints + // No iterative relative variation constraint should be created since MarginCoreProblemFiller.raRangeShrinking = false + // total number of variables 3 : + // - 1 per CNEC (flow) + // - 5 per range action (set-point, absolute variation, activation and variation up/down) + // total number of constraints 3 : + // - 1 per CNEC (flow constraint) + // - 3 per range action (activation and set-point + absolute variation) + + assertEquals(6, linearProblem.numVariables()); + assertEquals(4, linearProblem.numConstraints()); + } + + @Test + void updateTestOnPreventiveWithRaRangeShrinking() { + initialize(Set.of(cnec1), 1e-6, 1e-6, 1e-6, crac.getPreventiveState(), true, RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); + State state = cnec1.getState(); + + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.getRangeActionRelativeSetpointConstraint(pstRangeAction, state, LinearProblem.RaRangeShrinking.TRUE)); + assertEquals("Constraint PRA_PST_BE_preventive_relative_setpoint_iterative-shrinkconstraint has not been created yet", e.getMessage()); + + // 1st update + updateLinearProblem(); + + assertEquals(6, linearProblem.numVariables()); + assertEquals(5, linearProblem.numConstraints()); + + OpenRaoMPVariable setPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, state); + OpenRaoMPConstraint shrinkingConstraint = linearProblem.getRangeActionRelativeSetpointConstraint(pstRangeAction, state, LinearProblem.RaRangeShrinking.TRUE); + assertNotNull(shrinkingConstraint); + assertEquals(1, shrinkingConstraint.getCoefficient(setPointVariable)); + assertEquals(-10.5161, shrinkingConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(5.0626, shrinkingConstraint.ub(), DOUBLE_TOLERANCE); + + // 2nd update + updateLinearProblem(); + + assertEquals(6, linearProblem.numVariables()); + assertEquals(5, linearProblem.numConstraints()); + + setPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, state); + shrinkingConstraint = linearProblem.getRangeActionRelativeSetpointConstraint(pstRangeAction, state, LinearProblem.RaRangeShrinking.TRUE); + assertNotNull(shrinkingConstraint); + assertEquals(1, shrinkingConstraint.getCoefficient(setPointVariable)); + assertEquals(-7.9222, shrinkingConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(2.4687, shrinkingConstraint.ub(), DOUBLE_TOLERANCE); + } + + @Test + void updateTestOnCurativeWithRaRangeShrinking() { + initialize(Set.of(cnec2), 1e-6, 1e-6, 1e-6, cnec2.getState(), true, RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); + State state = cnec2.getState(); + // update the problem with new data + updateLinearProblem(); + + // some additional data + final double currentAlpha = pstRangeAction.convertTapToAngle(network.getTwoWindingsTransformer(RANGE_ACTION_ELEMENT_ID).getPhaseTapChanger().getTapPosition()); + + OpenRaoMPVariable setPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, state); + + // check flow variable for cnec1 does not exist + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowVariable(cnec1, TwoSides.ONE)); + assertEquals("Variable Tieline BE FR - N - preventive_one_flow_variable has not been created yet", e.getMessage()); + + // check flow constraint for cnec1 does not exist + e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowConstraint(cnec1, TwoSides.ONE)); + assertEquals("Constraint Tieline BE FR - N - preventive_one_flow_constraint has not been created yet", e.getMessage()); + + // check flow variable for cnec2 + OpenRaoMPVariable flowVariable2 = linearProblem.getFlowVariable(cnec2, TwoSides.TWO); + assertNotNull(flowVariable2); + assertEquals(-linearProblem.infinity(), flowVariable2.lb(), linearProblem.infinity() * 1e-3); + assertEquals(linearProblem.infinity(), flowVariable2.ub(), linearProblem.infinity() * 1e-3); + + // check flow constraint for cnec2 + OpenRaoMPConstraint flowConstraint2 = linearProblem.getFlowConstraint(cnec2, TwoSides.TWO); + assertNotNull(flowConstraint2); + assertEquals(REF_FLOW_CNEC2_IT2 - currentAlpha * SENSI_CNEC2_IT2, flowConstraint2.lb(), DOUBLE_TOLERANCE); + assertEquals(REF_FLOW_CNEC2_IT2 - currentAlpha * SENSI_CNEC2_IT2, flowConstraint2.ub(), DOUBLE_TOLERANCE); + assertEquals(1, flowConstraint2.getCoefficient(flowVariable2), DOUBLE_TOLERANCE); + assertEquals(-SENSI_CNEC2_IT2, flowConstraint2.getCoefficient(setPointVariable), DOUBLE_TOLERANCE); + + // check the number of variables and constraints + // total number of variables 3 : + // - 1 per CNEC (flow) + // - 5 per range action (set-point, absolute variation, activation and variation up/down) + // total number of constraints 4 : + // - 1 per CNEC (flow constraint) + // - 3 per range action (activation, absolute variation, set-point variation and iterative relative variation constraint: created before 2nd iteration) + assertEquals(6, linearProblem.numVariables()); + assertEquals(5, linearProblem.numConstraints()); + + // assert that no other constraint is created after 2nd iteration + updateLinearProblem(); + assertEquals(5, linearProblem.numConstraints()); + } + + @Test + void testSensitivityFilter1() { + OpenRaoMPConstraint flowConstraint; + OpenRaoMPVariable rangeActionSetpoint; + when(flowResult.getPtdfZonalSum(cnec1, TwoSides.ONE)).thenReturn(0.5); + + // (sensi = 2) < 2.5 should be filtered + when(flowResult.getMargin(cnec1, Unit.MEGAWATT)).thenReturn(-1.0); + initialize(Set.of(cnec1), 2.5, 2.5, 2.5, crac.getPreventiveState(), false, RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); + flowConstraint = linearProblem.getFlowConstraint(cnec1, TwoSides.ONE); + rangeActionSetpoint = linearProblem.getRangeActionSetpointVariable(pstRangeAction, cnec1.getState()); + assertEquals(0, flowConstraint.getCoefficient(rangeActionSetpoint), DOUBLE_TOLERANCE); + assertEquals(500., flowConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(500., flowConstraint.ub(), DOUBLE_TOLERANCE); + } + + @Test + void testSensitivityFilter2() { + OpenRaoMPConstraint flowConstraint; + OpenRaoMPVariable rangeActionSetpoint; + when(flowResult.getPtdfZonalSum(cnec1, TwoSides.ONE)).thenReturn(0.5); + Map tapToAngle = pstRangeAction.getTapToAngleConversionMap(); + + // (sensi = 2) > 1/.5 should not be filtered + when(flowResult.getMargin(cnec1, TwoSides.ONE, Unit.MEGAWATT)).thenReturn(-1.0); + initialize(Set.of(cnec1), 1.5, 1.5, 1.5, crac.getPreventiveState(), false, RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); + flowConstraint = linearProblem.getFlowConstraint(cnec1, TwoSides.ONE); + rangeActionSetpoint = linearProblem.getRangeActionSetpointVariable(pstRangeAction, cnec1.getState()); + assertEquals(-2, flowConstraint.getCoefficient(rangeActionSetpoint), DOUBLE_TOLERANCE); + assertEquals(500. - 2 * tapToAngle.get(TAP_INITIAL), flowConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(500. - 2 * tapToAngle.get(TAP_INITIAL), flowConstraint.ub(), DOUBLE_TOLERANCE); + } + + @Test + void testFilterCnecWithSensiFailure() { + // cnec1 has a failed state, cnec2 has a succeeded state + // only cnec2's flow variables & constraints must be added to MIP + when(sensitivityResult.getSensitivityStatus(cnec1.getState())).thenReturn(ComputationStatus.FAILURE); + when(sensitivityResult.getSensitivityStatus(cnec2.getState())).thenReturn(ComputationStatus.DEFAULT); + initialize(Set.of(cnec1, cnec2), 1e-6, 1e-6, 1e-6, cnec1.getState(), false, RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); + + OpenRaoMPVariable setPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, cnec2.getState()); + + // check flow variable for cnec1 does not exist + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowVariable(cnec1, TwoSides.ONE)); + assertEquals("Variable Tieline BE FR - N - preventive_one_flow_variable has not been created yet", e.getMessage()); + + // check flow constraint for cnec1 does not exist + e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowConstraint(cnec1, TwoSides.ONE)); + assertEquals("Constraint Tieline BE FR - N - preventive_one_flow_constraint has not been created yet", e.getMessage()); + + // check flow variable for cnec2 + OpenRaoMPVariable flowVariable2 = linearProblem.getFlowVariable(cnec2, TwoSides.TWO); + assertNotNull(flowVariable2); + assertEquals(-linearProblem.infinity(), flowVariable2.lb(), linearProblem.infinity() * 1e-3); + assertEquals(linearProblem.infinity(), flowVariable2.ub(), linearProblem.infinity() * 1e-3); + + // check flow constraint for cnec2 + OpenRaoMPConstraint flowConstraint2 = linearProblem.getFlowConstraint(cnec2, TwoSides.TWO); + assertNotNull(flowConstraint2); + assertEquals(REF_FLOW_CNEC2_IT1 - initialAlpha * SENSI_CNEC2_IT1, flowConstraint2.lb(), DOUBLE_TOLERANCE); + assertEquals(REF_FLOW_CNEC2_IT1 - initialAlpha * SENSI_CNEC2_IT1, flowConstraint2.ub(), DOUBLE_TOLERANCE); + assertEquals(1, flowConstraint2.getCoefficient(flowVariable2), DOUBLE_TOLERANCE); + assertEquals(-SENSI_CNEC2_IT1, flowConstraint2.getCoefficient(setPointVariable), DOUBLE_TOLERANCE); + } + + @Test + void testFilterCnecWithSensiFailureAndUpdateWithoutChange() { + // cnec1 has a failed state, cnec2 has a succeeded state + // only cnec2's flow variables & constraints must be added to MIP + when(sensitivityResult.getSensitivityStatus(cnec1.getState())).thenReturn(ComputationStatus.FAILURE); + when(sensitivityResult.getSensitivityStatus(cnec2.getState())).thenReturn(ComputationStatus.DEFAULT); + initialize(Set.of(cnec1, cnec2), 1e-6, 1e-6, 1e-6, cnec1.getState(), false, RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); + + updateLinearProblem(); + + OpenRaoMPVariable setPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, cnec2.getState()); + + // check flow variable for cnec1 does not exist + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowVariable(cnec1, TwoSides.ONE)); + assertEquals("Variable Tieline BE FR - N - preventive_one_flow_variable has not been created yet", e.getMessage()); + + // check flow constraint for cnec1 does not exist + e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowConstraint(cnec1, TwoSides.ONE)); + assertEquals("Constraint Tieline BE FR - N - preventive_one_flow_constraint has not been created yet", e.getMessage()); + + // check flow variable for cnec2 + OpenRaoMPVariable flowVariable2 = linearProblem.getFlowVariable(cnec2, TwoSides.TWO); + assertNotNull(flowVariable2); + assertEquals(-linearProblem.infinity(), flowVariable2.lb(), linearProblem.infinity() * 1e-3); + assertEquals(linearProblem.infinity(), flowVariable2.ub(), linearProblem.infinity() * 1e-3); + + // check flow constraint for cnec2 + final double currentAlpha = pstRangeAction.convertTapToAngle(network.getTwoWindingsTransformer(RANGE_ACTION_ELEMENT_ID).getPhaseTapChanger().getTapPosition()); + OpenRaoMPConstraint flowConstraint2 = linearProblem.getFlowConstraint(cnec2, TwoSides.TWO); + assertEquals(REF_FLOW_CNEC2_IT2 - currentAlpha * SENSI_CNEC2_IT2, flowConstraint2.lb(), DOUBLE_TOLERANCE); + assertEquals(REF_FLOW_CNEC2_IT2 - currentAlpha * SENSI_CNEC2_IT2, flowConstraint2.ub(), DOUBLE_TOLERANCE); + assertEquals(1, flowConstraint2.getCoefficient(flowVariable2), DOUBLE_TOLERANCE); + assertEquals(-SENSI_CNEC2_IT2, flowConstraint2.getCoefficient(setPointVariable), DOUBLE_TOLERANCE); + } + + @Test + void testFilterCnecWithSensiFailureAndUpdateWithChange() { + // cnec1 has a failed state, cnec2 has a succeeded state + // only cnec2's flow variables & constraints must be added to MIP + when(sensitivityResult.getSensitivityStatus(cnec1.getState())).thenReturn(ComputationStatus.FAILURE); + when(sensitivityResult.getSensitivityStatus(cnec2.getState())).thenReturn(ComputationStatus.DEFAULT); + initialize(Set.of(cnec1, cnec2), 1e-6, 1e-6, 1e-6, cnec1.getState(), false, RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); + + // invert sensitivity failure statuses & update + // only cnec1's flow variables & constraints must be added to MIP + when(sensitivityResult.getSensitivityStatus(cnec1.getState())).thenReturn(ComputationStatus.DEFAULT); + when(sensitivityResult.getSensitivityStatus(cnec2.getState())).thenReturn(ComputationStatus.FAILURE); + updateLinearProblem(); + + // check flow variable for cnec2 does not exist + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowVariable(cnec2, TwoSides.TWO)); + assertEquals("Variable Tieline BE FR - Defaut - N-1 NL1-NL3_two_flow_variable has not been created yet", e.getMessage()); + + // check flow constraint for cnec2 does not exist + e = assertThrows(OpenRaoException.class, () -> linearProblem.getFlowConstraint(cnec2, TwoSides.TWO)); + assertEquals("Constraint Tieline BE FR - Defaut - N-1 NL1-NL3_two_flow_constraint has not been created yet", e.getMessage()); + + // check flow variable for cnec1 + OpenRaoMPVariable flowVariable1 = linearProblem.getFlowVariable(cnec1, TwoSides.ONE); + assertNotNull(flowVariable1); + assertEquals(-linearProblem.infinity(), flowVariable1.lb(), linearProblem.infinity() * 1e-3); + assertEquals(linearProblem.infinity(), flowVariable1.ub(), linearProblem.infinity() * 1e-3); + + final double currentAlpha = pstRangeAction.convertTapToAngle(network.getTwoWindingsTransformer(RANGE_ACTION_ELEMENT_ID).getPhaseTapChanger().getTapPosition()); + OpenRaoMPVariable setPointVariable = linearProblem.getRangeActionSetpointVariable(pstRangeAction, cnec1.getState()); + + // check flow constraint for cnec1 + OpenRaoMPConstraint flowConstraint1 = linearProblem.getFlowConstraint(cnec1, TwoSides.ONE); + assertNotNull(flowConstraint1); + assertEquals(REF_FLOW_CNEC1_IT2 - currentAlpha * SENSI_CNEC1_IT2, flowConstraint1.lb(), DOUBLE_TOLERANCE); + assertEquals(REF_FLOW_CNEC1_IT2 - currentAlpha * SENSI_CNEC1_IT2, flowConstraint1.ub(), DOUBLE_TOLERANCE); + assertEquals(1, flowConstraint1.getCoefficient(flowVariable1), DOUBLE_TOLERANCE); + assertEquals(-SENSI_CNEC1_IT2, flowConstraint1.getCoefficient(setPointVariable), DOUBLE_TOLERANCE); + } +} diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstGroupFillerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstGroupFillerTest.java index cfa799f4d6..1d98db43fe 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstGroupFillerTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstGroupFillerTest.java @@ -60,7 +60,7 @@ void testFillAndUpdateMethods() throws IOException { RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(new RaoParameters()); - CoreProblemFiller coreProblemFiller = new CoreProblemFiller( + MarginCoreProblemFiller coreProblemFiller = new MarginCoreProblemFiller( optimizationPerimeter, initialRangeActionSetpointResult, rangeActionParameters, @@ -72,7 +72,9 @@ void testFillAndUpdateMethods() throws IOException { DiscretePstTapFiller discretePstTapFiller = new DiscretePstTapFiller( optimizationPerimeter, pstRangeActions, - initialRangeActionSetpointResult); + initialRangeActionSetpointResult, + rangeActionParameters, + false); DiscretePstGroupFiller discretePstGroupFiller = new DiscretePstGroupFiller( state, diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstTapFillerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstTapFillerTest.java index d67fc18686..f076ae88d4 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstTapFillerTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/DiscretePstTapFillerTest.java @@ -21,8 +21,9 @@ import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mockito; import java.io.IOException; @@ -48,8 +49,7 @@ class DiscretePstTapFillerTest extends AbstractFillerTest { private PstRangeAction pra; private PstRangeAction cra; - @BeforeEach - void setUpAndFill() throws IOException { + void setUpAndFill(boolean costOptimization) throws IOException { // prepare data init(); preventiveState = crac.getPreventiveState(); @@ -61,6 +61,7 @@ void setUpAndFill() throws IOException { .withNetworkElement("BBE2AA1 BBE3AA1 1") .newOnContingencyStateUsageRule().withUsageMethod(AVAILABLE).withContingency("N-1 NL1-NL3").withInstant("curative").add() .withInitialTap(0) + .withActivationCost(10.0) .withTapToAngleConversionMap(tapToAngle) .newTapRange() .withMinTap(-10) @@ -81,7 +82,7 @@ void setUpAndFill() throws IOException { RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(new RaoParameters()); - CoreProblemFiller coreProblemFiller = new CoreProblemFiller( + MarginCoreProblemFiller coreProblemFiller = new MarginCoreProblemFiller( optimizationPerimeter, initialRangeActionSetpointResult, rangeActionParameters, @@ -94,7 +95,9 @@ void setUpAndFill() throws IOException { discretePstTapFiller = new DiscretePstTapFiller( optimizationPerimeter, pstRangeActions, - initialRangeActionSetpointResult); + initialRangeActionSetpointResult, + new RangeActionsOptimizationParameters(), + true); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) @@ -188,8 +191,10 @@ private void checkPstRelativeTapConstraint(double expectedLb, double expectedUb) assertEquals(1, craRelativeTapC.getCoefficient(variationDownV)); } - @Test - void testFillAndUpdateMethods() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testFillAndUpdateMethods(boolean costOptimization) throws IOException { + setUpAndFill(costOptimization); checkContent(pstRangeAction, preventiveState, 0, -15, 15, true); checkContent(cra, curativeState, 0, -16, 16, true); checkPstRelativeTapConstraint(-10, 7); @@ -206,10 +211,18 @@ void testFillAndUpdateMethods() { checkContent(pra, preventiveState, -4, -15, 15, false); checkContent(cra, curativeState, -6, -16, 16, false); checkPstRelativeTapConstraint(-8, 9); + + if (costOptimization) { + assertEquals(10.0, linearProblem.getObjective().getCoefficient(linearProblem.getTotalPstRangeActionTapVariationVariable(pra, preventiveState, LinearProblem.VariationDirectionExtension.UPWARD))); + assertEquals(10.0, linearProblem.getObjective().getCoefficient(linearProblem.getTotalPstRangeActionTapVariationVariable(pra, preventiveState, LinearProblem.VariationDirectionExtension.UPWARD))); + assertEquals(0.01, linearProblem.getObjective().getCoefficient(linearProblem.getTotalPstRangeActionTapVariationVariable(cra, curativeState, LinearProblem.VariationDirectionExtension.UPWARD)), 1e-2); + assertEquals(0.01, linearProblem.getObjective().getCoefficient(linearProblem.getTotalPstRangeActionTapVariationVariable(cra, curativeState, LinearProblem.VariationDirectionExtension.DOWNWARD)), 1e-2); + } } @Test - void testUpdateBetweenMipIteration() { + void testUpdateBetweenMipIteration() throws IOException { + setUpAndFill(false); RangeActionActivationResultImpl rangeActionActivationResult = new RangeActionActivationResultImpl(new RangeActionSetpointResultImpl(Map.of(pra, 0., cra, 0.))); diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CoreProblemFillerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MarginCoreProblemFillerTest.java similarity index 99% rename from ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CoreProblemFillerTest.java rename to ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MarginCoreProblemFillerTest.java index 9c1dab5b58..5d98b53ea0 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/CoreProblemFillerTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MarginCoreProblemFillerTest.java @@ -41,9 +41,9 @@ * @author Joris Mancini {@literal } * @author Baptiste Seguinot {@literal } */ -class CoreProblemFillerTest extends AbstractFillerTest { +class MarginCoreProblemFillerTest extends AbstractFillerTest { private LinearProblem linearProblem; - private CoreProblemFiller coreProblemFiller; + private MarginCoreProblemFiller coreProblemFiller; private RangeActionSetpointResult initialRangeActionSetpointResult; // some additional data private double minAlpha; @@ -94,7 +94,7 @@ private void initialize(Set cnecs, double pstSensitivityThreshold, dou raoParameters.getRangeActionsOptimizationParameters().setInjectionRaSensitivityThreshold(injectionSensitivityThreshold); RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(raoParameters); - coreProblemFiller = new CoreProblemFiller( + coreProblemFiller = new MarginCoreProblemFiller( optimizationPerimeter, initialRangeActionSetpointResult, rangeActionParameters, @@ -529,7 +529,7 @@ void updateTestOnPreventive() { assertEquals("Constraint Tieline BE FR - Defaut - N-1 NL1-NL3_two_flow_constraint has not been created yet", e.getMessage()); // check the number of variables and constraints - // No iterative relative variation constraint should be created since CoreProblemFiller.raRangeShrinking = false + // No iterative relative variation constraint should be created since MarginCoreProblemFiller.raRangeShrinking = false // total number of variables 5 : // - 1 per CNEC (flow) // - 4 per range action (set-point 3 variations [up, down, absolute]) diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxLoopFlowFillerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxLoopFlowFillerTest.java index 694c068751..145b01a514 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxLoopFlowFillerTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxLoopFlowFillerTest.java @@ -45,7 +45,7 @@ */ class MaxLoopFlowFillerTest extends AbstractFillerTest { private LinearProblem linearProblem; - private CoreProblemFiller coreProblemFiller; + private MarginCoreProblemFiller coreProblemFiller; private MaxLoopFlowFiller maxLoopFlowFiller; private LoopFlowParametersExtension loopFlowParameters; private FlowCnec cnecOn2sides; @@ -74,7 +74,7 @@ public void setUp() throws IOException { Mockito.when(optimizationPerimeter.getRangeActionsPerState()).thenReturn(rangeActions); RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(new RaoParameters()); - coreProblemFiller = new CoreProblemFiller( + coreProblemFiller = new MarginCoreProblemFiller( optimizationPerimeter, initialRangeActionSetpointResult, rangeActionParameters, diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinMarginFillerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinMarginFillerTest.java index dc38aec76f..d4fe0fbe1b 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinMarginFillerTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinMarginFillerTest.java @@ -38,7 +38,7 @@ */ class MaxMinMarginFillerTest extends AbstractFillerTest { private LinearProblem linearProblem; - private CoreProblemFiller coreProblemFiller; + private MarginCoreProblemFiller coreProblemFiller; private MaxMinMarginFiller maxMinMarginFiller; @BeforeEach @@ -61,7 +61,7 @@ public void setUp() throws IOException { raoParameters.getRangeActionsOptimizationParameters().setInjectionRaPenaltyCost(0.01); RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(raoParameters); - coreProblemFiller = new CoreProblemFiller( + coreProblemFiller = new MarginCoreProblemFiller( optimizationPerimeter, initialRangeActionSetpointResult, rangeActionParameters, @@ -70,7 +70,7 @@ public void setUp() throws IOException { } private void createMaxMinMarginFiller(Unit unit) { - maxMinMarginFiller = new MaxMinMarginFiller(Set.of(cnec1), unit); + maxMinMarginFiller = new MaxMinMarginFiller(Set.of(cnec1), unit, false); } private void buildLinearProblem() { @@ -186,7 +186,7 @@ void fillWithMissingRangeActionVariables() { .build(); // FlowVariables present , but not the absoluteRangeActionVariables present, - // This should work since range actions can be filtered out by the CoreProblemFiller if their number + // This should work since range actions can be filtered out by the MarginCoreProblemFiller if their number // exceeds the max-pst-per-tso parameter linearProblem.addFlowVariable(0.0, 0.0, cnec1, TwoSides.ONE); linearProblem.addFlowVariable(0.0, 0.0, cnec2, TwoSides.TWO); diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinRelativeMarginFillerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinRelativeMarginFillerTest.java index 3e741bdd1d..d8a39774df 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinRelativeMarginFillerTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MaxMinRelativeMarginFillerTest.java @@ -48,7 +48,7 @@ class MaxMinRelativeMarginFillerTest extends AbstractFillerTest { private static final double PRECISE_DOUBLE_TOLERANCE = 1e-9; private LinearProblem linearProblem; - private CoreProblemFiller coreProblemFiller; + private MarginCoreProblemFiller coreProblemFiller; private MaxMinRelativeMarginFiller maxMinRelativeMarginFiller; private RelativeMarginsParametersExtension parameters; private RangeActionSetpointResult initialRangeActionSetpointResult; @@ -77,7 +77,7 @@ public void setUp() throws IOException { RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(raoParameters); parameters = raoParameters.getExtension(RelativeMarginsParametersExtension.class); - coreProblemFiller = new CoreProblemFiller( + coreProblemFiller = new MarginCoreProblemFiller( optimizationPerimeter, initialRangeActionSetpointResult, rangeActionParameters, diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MnecFillerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MnecFillerTest.java index 250072c307..a2440d81bd 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MnecFillerTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MnecFillerTest.java @@ -39,7 +39,7 @@ */ class MnecFillerTest extends AbstractFillerTest { private LinearProblem linearProblem; - private CoreProblemFiller coreProblemFiller; + private MarginCoreProblemFiller coreProblemFiller; private FlowCnec mnec1; private FlowCnec mnec2; private FlowCnec mnec3; @@ -104,7 +104,7 @@ public void setUp() throws IOException { raoParameters.getRangeActionsOptimizationParameters().setInjectionRaPenaltyCost(0.01); RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(raoParameters); - coreProblemFiller = new CoreProblemFiller( + coreProblemFiller = new MarginCoreProblemFiller( optimizationPerimeter, initialRangeActionSetpointResult, rangeActionParameters, diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/RaUsageLimitsFillerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/RaUsageLimitsFillerTest.java index 61258064ea..88aa302dd8 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/RaUsageLimitsFillerTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/RaUsageLimitsFillerTest.java @@ -50,7 +50,7 @@ class RaUsageLimitsFillerTest extends AbstractFillerTest { private State state; private LinearProblem linearProblem; - private CoreProblemFiller coreProblemFiller; + private MarginCoreProblemFiller coreProblemFiller; @BeforeEach public void setup() throws IOException { @@ -107,7 +107,7 @@ public void setup() throws IOException { RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(new RaoParameters()); - coreProblemFiller = new CoreProblemFiller( + coreProblemFiller = new MarginCoreProblemFiller( optimizationPerimeter, prePerimeterRangeActionSetpointResult, rangeActionParameters, @@ -123,7 +123,7 @@ void testSkipFiller() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) .withProblemFiller(raUsageLimitsFiller) @@ -146,7 +146,7 @@ void testVariationVariableAndConstraints() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) .withProblemFiller(raUsageLimitsFiller) @@ -179,7 +179,7 @@ void testVariationVariableAndConstraintsApproxPsts() { prePerimeterRangeActionSetpointResult, raLimitationParameters, true, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) .withProblemFiller(raUsageLimitsFiller) @@ -212,7 +212,7 @@ void testSkipConstraints1() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) .withProblemFiller(raUsageLimitsFiller) @@ -245,7 +245,7 @@ void testSkipConstraints2() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) .withProblemFiller(raUsageLimitsFiller) @@ -266,7 +266,7 @@ void testMaxRa() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) @@ -293,7 +293,7 @@ void testSkipLargeMaxRa1() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) @@ -316,7 +316,7 @@ void testSkipLargeMaxRa2() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) @@ -347,7 +347,7 @@ void testMaxTso() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) .withProblemFiller(raUsageLimitsFiller) @@ -380,7 +380,7 @@ void testSkipLargeMaxTso1() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) .withProblemFiller(raUsageLimitsFiller) @@ -402,7 +402,7 @@ void testSkipLargeMaxTso2() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) .withProblemFiller(raUsageLimitsFiller) @@ -424,7 +424,7 @@ void testMaxTsoWithExclusion() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) .withProblemFiller(raUsageLimitsFiller) @@ -451,7 +451,7 @@ void testMaxRaPerTso() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) @@ -492,7 +492,7 @@ void testMaxPstPerTso() { prePerimeterRangeActionSetpointResult, raLimitationParameters, false, - network); + network, false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) @@ -539,7 +539,7 @@ void testMaxElementaryActionsPerTsoConstraint() { prePerimeterRangeActionSetpointResult, raLimitationParameters, true, - network); + network, false); Map> pstRangeActionsPerState = new HashMap<>(); rangeActionsPerState.forEach((s, rangeActionSet) -> rangeActionSet.stream().filter(PstRangeAction.class::isInstance).map(PstRangeAction.class::cast).forEach(pstRangeAction -> pstRangeActionsPerState.computeIfAbsent(s, e -> new HashSet<>()).add(pstRangeAction))); @@ -548,7 +548,7 @@ void testMaxElementaryActionsPerTsoConstraint() { when(optimizationPerimeter.getMainOptimizationState()).thenReturn(state); when(optimizationPerimeter.getRangeActionsPerState()).thenReturn(rangeActionsPerState); - DiscretePstTapFiller discretePstTapFiller = new DiscretePstTapFiller(optimizationPerimeter, pstRangeActionsPerState, prePerimeterRangeActionSetpointResult); + DiscretePstTapFiller discretePstTapFiller = new DiscretePstTapFiller(optimizationPerimeter, pstRangeActionsPerState, prePerimeterRangeActionSetpointResult, new RangeActionsOptimizationParameters(), false); linearProblem = new LinearProblemBuilder() .withProblemFiller(coreProblemFiller) diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/UnoptimizedCnecFillerMarginDecreaseRuleTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/UnoptimizedCnecFillerMarginDecreaseRuleTest.java index f0624a714c..8dbcac76b1 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/UnoptimizedCnecFillerMarginDecreaseRuleTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/UnoptimizedCnecFillerMarginDecreaseRuleTest.java @@ -44,7 +44,7 @@ class UnoptimizedCnecFillerMarginDecreaseRuleTest extends AbstractFillerTest { private static final double MAX_ABS_THRESHOLD = 1000; private LinearProblem linearProblem; - private CoreProblemFiller coreProblemFiller; + private MarginCoreProblemFiller coreProblemFiller; private UnoptimizedCnecFiller unoptimizedCnecFiller; private FlowCnec cnecNl; private FlowCnec cnecFr; @@ -82,7 +82,7 @@ public void setUp() throws IOException { raoParameters.getRangeActionsOptimizationParameters().setInjectionRaPenaltyCost(0.01); RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(raoParameters); - coreProblemFiller = new CoreProblemFiller( + coreProblemFiller = new MarginCoreProblemFiller( optimizationPerimeter, initialRangeActionSetpointResult, rangeActionParameters, @@ -96,7 +96,7 @@ private void buildLinearProblemWithMaxMinMargin() { private void buildLinearProblemWithMaxMinMargin(boolean initialFlowsAreNan) { UnoptimizedCnecParameters unoptimizedCnecParameters = new UnoptimizedCnecParameters(Set.of("NL")); - MaxMinMarginFiller maxMinMarginFiller = new MaxMinMarginFiller(Set.of(cnecNl, cnecFr), Unit.MEGAWATT); + MaxMinMarginFiller maxMinMarginFiller = new MaxMinMarginFiller(Set.of(cnecNl, cnecFr), Unit.MEGAWATT, false); FlowResult initialFlowResult = Mockito.mock(FlowResult.class); when(initialFlowResult.getMargin(cnecNl, TwoSides.TWO, Unit.MEGAWATT)).thenReturn(400.); when(initialFlowResult.getMargin(cnecFr, TwoSides.ONE, Unit.MEGAWATT)).thenReturn(600.); diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/FunctionalCostComputerTestUtils.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/FunctionalCostComputerTestUtils.java new file mode 100644 index 0000000000..5084f191d2 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/FunctionalCostComputerTestUtils.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024, 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.result.functionalcostcomputer; + +import com.powsybl.openrao.data.crac.api.Crac; +import com.powsybl.openrao.data.crac.api.CracFactory; +import com.powsybl.openrao.data.crac.api.InstantKind; +import com.powsybl.openrao.data.crac.api.State; +import com.powsybl.openrao.data.crac.api.cnec.FlowCnec; +import com.powsybl.openrao.data.crac.impl.FlowCnecImpl; +import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult; +import org.mockito.Mockito; + +import java.util.List; +import java.util.Map; + +/** + * @author Thomas Bouquet {@literal } + */ +public class FunctionalCostComputerTestUtils { + protected Crac crac; + protected State autoStateCo1; + protected State autoStateCo2; + protected State curativeStateCo1; + protected State curativeStateCo2; + protected OptimizationResult secondPreventivePerimeterResult; + protected Map postContingencyResults; + + protected void init() { + crac = CracFactory.findDefault().create("crac"); + crac.newInstant("preventive", InstantKind.PREVENTIVE); + crac.newInstant("outage", InstantKind.OUTAGE); + crac.newInstant("auto", InstantKind.AUTO); + crac.newInstant("curative", InstantKind.CURATIVE); + + // mock states + + autoStateCo1 = Mockito.mock(State.class); + Mockito.when(autoStateCo1.getInstant()).thenReturn(crac.getInstant("auto")); + + autoStateCo2 = Mockito.mock(State.class); + Mockito.when(autoStateCo2.getInstant()).thenReturn(crac.getInstant("auto")); + + curativeStateCo1 = Mockito.mock(State.class); + Mockito.when(curativeStateCo1.getInstant()).thenReturn(crac.getInstant("curative")); + + curativeStateCo2 = Mockito.mock(State.class); + Mockito.when(curativeStateCo2.getInstant()).thenReturn(crac.getInstant("curative")); + + // mock flow cnecs + + FlowCnec autoFlowCnec = Mockito.mock(FlowCnecImpl.class); + FlowCnec curativeFlowCnec = Mockito.mock(FlowCnecImpl.class); + + // mock optimization results + + secondPreventivePerimeterResult = Mockito.mock(OptimizationResult.class); + Mockito.when(secondPreventivePerimeterResult.getFunctionalCost()).thenReturn(100.0); + + OptimizationResult autoPerimeterResultCo1 = Mockito.mock(OptimizationResult.class); + Mockito.when(autoPerimeterResultCo1.getFunctionalCost()).thenReturn(30.0); + Mockito.when(autoPerimeterResultCo1.getMostLimitingElements(1)).thenReturn(List.of(autoFlowCnec)); + + OptimizationResult autoPerimeterResultCo2 = Mockito.mock(OptimizationResult.class); + Mockito.when(autoPerimeterResultCo2.getFunctionalCost()).thenReturn(17.0); + Mockito.when(autoPerimeterResultCo2.getMostLimitingElements(1)).thenReturn(List.of(autoFlowCnec)); + + OptimizationResult curativePerimeterResultCo1 = Mockito.mock(OptimizationResult.class); + Mockito.when(curativePerimeterResultCo1.getFunctionalCost()).thenReturn(250.0); + Mockito.when(curativePerimeterResultCo1.getMostLimitingElements(1)).thenReturn(List.of(curativeFlowCnec)); + + OptimizationResult curativePerimeterResultCo2 = Mockito.mock(OptimizationResult.class); + Mockito.when(curativePerimeterResultCo2.getFunctionalCost()).thenReturn(110.0); + Mockito.when(curativePerimeterResultCo2.getMostLimitingElements(1)).thenReturn(List.of(curativeFlowCnec)); + + // mock post-contingency results + + postContingencyResults = Map.of(autoStateCo1, autoPerimeterResultCo1, autoStateCo2, autoPerimeterResultCo2, curativeStateCo1, curativePerimeterResultCo1, curativeStateCo2, curativePerimeterResultCo2); + } +} diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/MaximumFunctionalCostComputerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/MaximumFunctionalCostComputerTest.java new file mode 100644 index 0000000000..48773d14b5 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/MaximumFunctionalCostComputerTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024, 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.result.functionalcostcomputer; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Thomas Bouquet {@literal } + */ +class MaximumFunctionalCostComputerTest extends FunctionalCostComputerTestUtils { + private MaximumFunctionalCostComputer functionalCostComputer; + + @BeforeEach + void setUp() { + init(); + functionalCostComputer = new MaximumFunctionalCostComputer(secondPreventivePerimeterResult, postContingencyResults); + } + + @Test + void testPreventiveTotalFunctionalCost() { + assertEquals(100.0, functionalCostComputer.computeFunctionalCost(crac.getInstant("preventive"))); + } + + @Test + void testOutageTotalFunctionalCost() { + assertEquals(100.0, functionalCostComputer.computeFunctionalCost(crac.getInstant("outage"))); + } + + @Test + void testAutoTotalFunctionalCost() { + assertEquals(100.0, functionalCostComputer.computeFunctionalCost(crac.getInstant("auto"))); + } + + @Test + void testCurativeTotalFunctionalCost() { + assertEquals(250.0, functionalCostComputer.computeFunctionalCost(crac.getInstant("curative"))); + } +} diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/TotalFunctionalCostComputerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/TotalFunctionalCostComputerTest.java new file mode 100644 index 0000000000..d3e1a49954 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/functionalcostcomputer/TotalFunctionalCostComputerTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, 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.result.functionalcostcomputer; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Thomas Bouquet {@literal } + */ +class TotalFunctionalCostComputerTest extends FunctionalCostComputerTestUtils { + private TotalFunctionalCostComputer functionalCostComputer; + + @BeforeEach + void setUp() { + init(); + functionalCostComputer = new TotalFunctionalCostComputer(secondPreventivePerimeterResult, postContingencyResults); + } + + @Test + void testPreventiveTotalFunctionalCost() { + assertEquals(100.0, functionalCostComputer.computeFunctionalCost(crac.getInstant("preventive"))); + } + + @Test + void testOutageTotalFunctionalCost() { + assertEquals(100.0, functionalCostComputer.computeFunctionalCost(crac.getInstant("outage"))); + } + + @Test + void testAutoTotalFunctionalCost() { + assertEquals(147.0, functionalCostComputer.computeFunctionalCost(crac.getInstant("auto"))); + } + + @Test + void testCurativeTotalFunctionalCost() { + assertEquals(507.0, functionalCostComputer.computeFunctionalCost(crac.getInstant("curative"))); + } + + @Test + void testTotalFunctionalCostForNullInstant() { + assertEquals(0.0, functionalCostComputer.computeFunctionalCost(null)); + } +} diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResultTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResultTest.java index 87ddf9718c..36759eb3ff 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResultTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResultTest.java @@ -54,7 +54,7 @@ void testGetFlow() { when(postCraPrePerimeterResult.getFlow(eq(cnec1), any(), any())).thenReturn(135.4); when(postCraPrePerimeterResult.getFlow(eq(cnec1), any(), any(), any())).thenReturn(135.4); - CurativeWithSecondPraoResult result = new CurativeWithSecondPraoResult(state1, null, null, null, postCraPrePerimeterResult); + CurativeWithSecondPraoResult result = new CurativeWithSecondPraoResult(state1, null, null, null, postCraPrePerimeterResult, false); assertEquals(135.4, result.getFlow(cnec1, TwoSides.TWO, Unit.MEGAWATT), DOUBLE_TOLERANCE); assertEquals(135.4, result.getFlow(cnec1, TwoSides.ONE, Unit.AMPERE, mock(Instant.class)), DOUBLE_TOLERANCE); diff --git a/ra-optimisation/search-tree-rao/src/test/resources/crac/small-crac.json b/ra-optimisation/search-tree-rao/src/test/resources/crac/small-crac.json index 3421c1d85b..bbe459afe0 100644 --- a/ra-optimisation/search-tree-rao/src/test/resources/crac/small-crac.json +++ b/ra-optimisation/search-tree-rao/src/test/resources/crac/small-crac.json @@ -1,8 +1,26 @@ { "type" : "CRAC", - "version" : "1.0", + "version" : "2.6", "id": "LS_unsecure", "name": "LS_unsecure", + "instants": [ + { + "id": "preventive", + "kind": "PREVENTIVE" + }, + { + "id": "outage", + "kind": "OUTAGE" + }, + { + "id": "auto", + "kind": "AUTO" + }, + { + "id": "curative", + "kind": "CURATIVE" + } + ], "networkElementsNamePerId": { }, "contingencies": [ { @@ -22,7 +40,7 @@ "unit": "megawatt", "max": 750, "min" : -750, - "rule" : "onRightSide" + "side" : 2 } ], "contingencyId": "N-1 NL1-NL3", "instant" : "curative", @@ -38,7 +56,7 @@ "unit": "megawatt", "max": 750, "min" : -750, - "rule" : "onLeftSide" + "side" : 1 } ], "instant": "preventive", "optimized": true, @@ -52,6 +70,11 @@ "operator": "BE", "initialTap": 0, "speed": 1, + "activationCost": 15.0, + "variationCosts": { + "up": 10.0, + "down": 10.0 + }, "tapToAngleConversionMap" : { "-1" : -0.3896097993971608, "0" : 0.0, @@ -87,13 +110,13 @@ "15" : 5.839110508104064, "16" : 6.2276423729910535 }, - "freeToUseUsageRules": [ + "onInstantUsageRules": [ { "usageMethod": "available", "instant": "preventive" } ], - "onStateUsageRules" : [ { + "onContingencyStateUsageRules" : [ { "instant" : "curative", "contingencyId" : "N-1 NL1-NL3", "usageMethod" : "available" @@ -148,13 +171,13 @@ "15" : 5.839110508104064, "16" : 6.2276423729910535 }, - "freeToUseUsageRules": [ + "onInstantUsageRules": [ { "usageMethod": "available", "instant": "preventive" } ], - "onStateUsageRules" : [ { + "onContingencyStateUsageRules" : [ { "instant" : "auto", "contingencyId" : "N-1 NL1-NL3", "usageMethod" : "available" diff --git a/tests/src/test/resources/com/powsybl/openrao/tests/features/epic92_costly_rao/US92_2.feature b/tests/src/test/resources/com/powsybl/openrao/tests/features/epic92_costly_rao/US92_2.feature new file mode 100644 index 0000000000..29de68b40f --- /dev/null +++ b/tests/src/test/resources/com/powsybl/openrao/tests/features/epic92_costly_rao/US92_2.feature @@ -0,0 +1,90 @@ +# Copyright (c) 2024, 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/. + +Feature: US 92.2: Costly range actions optimization - APPROXIMATED_INTEGERS PSTs + + @fast @preventive-only @costly @rao + Scenario: US 92.2.1: Change only necessary taps on preventive PST + The RAO can increase the minimum margin by setting the tap of the PST on position -10 + but stops at position -5 because the network is secure and this saves expenses. + Given network file is "epic92/2Nodes2ParallelLinesPST.uct" + Given crac file is "epic92/crac-92-2-1.json" + Given configuration file is "epic92/RaoParameters_dc_minObjective_discretePst.json" + When I launch search_tree_rao + Then the worst margin is 45.46 MW + And the value of the objective function initially should be 2000000.0 + And 1 remedial actions are used in preventive + And the remedial action "pstBeFr2" is used in preventive + And the tap of PstRangeAction "pstBeFr2" should be -5 in preventive + And the value of the objective function after PRA should be 55.0 + + @fast @preventive-only @costly @rao + Scenario: US 92.2.2: Two PSTs + PST 1 has cheaper variation costs (5 per tap) but a higher activation price (100) so moving the 9 required taps would + require a cost of 145. PST 2 is cheaper to activate (5) and more expensive to use (15 per tap) but leads to a total + cost of 140 so it is chosen. + Given network file is "epic92/2Nodes3ParallelLines2PSTs.uct" + Given crac file is "epic92/crac-92-2-2.json" + Given configuration file is "epic92/RaoParameters_dc_minObjective_discretePst.json" + When I launch search_tree_rao + Then the worst margin is 31.15 MW + And the value of the objective function initially should be 2633333.33 + And 1 remedial actions are used in preventive + And the remedial action "pstBeFr3" is used in preventive + And the tap of PstRangeAction "pstBeFr2" should be 0 in preventive + And the tap of PstRangeAction "pstBeFr3" should be -9 in preventive + And the value of the objective function after PRA should be 140.0 + + @fast @costly @rao + Scenario: US 92.2.3: Costly PST in preventive and curative + Given network file is "epic92/2Nodes3ParallelLinesPST.uct" + Given crac file is "epic92/crac-92-2-3.json" + Given configuration file is "epic92/RaoParameters_dc_minObjective_discretePst.json" + When I launch search_tree_rao + Then the worst margin is 11.73 MW + And the value of the objective function initially should be 4300000.0 + And 1 remedial actions are used in preventive + And the remedial action "pstBeFr3" is used in preventive + And the tap of PstRangeAction "pstBeFr3" should be -3 in preventive + # Activation of pstBeFr3 (20) + 3 taps moved (3 * 7.5) + overload penalty (282.71 * 10000) + And the value of the objective function after PRA should be 2827226.08 + And 1 remedial actions are used after "coBeFr2" at "curative" + And the tap of PstRangeAction "pstBeFr3" should be -9 after "coBeFr2" at "curative" + # Activation of pstBeFr3 twice (2 * 20) + 9 taps moved in total (3 * 7.5 + 6 * 7.5) + And the value of the objective function after CRA should be 107.5 + + @fast @costly @rao + Scenario: US 92.2.4: Free PST in preventive and curative + Given network file is "epic92/2Nodes3ParallelLinesPST.uct" + Given crac file is "epic92/crac-92-2-4.json" + Given configuration file is "epic92/RaoParameters_dc_minObjective_discretePst.json" + When I launch search_tree_rao + Then the worst margin is 11.73 MW + And the value of the objective function initially should be 4300000.0 + And 1 remedial actions are used in preventive + And the remedial action "pstBeFr3" is used in preventive + And the tap of PstRangeAction "pstBeFr3" should be -3 in preventive + # Overload penalty (282.71 * 10000) + And the value of the objective function after PRA should be 2827171.08 + And 1 remedial actions are used after "coBeFr2" at "curative" + And the tap of PstRangeAction "pstBeFr3" should be -9 after "coBeFr2" at "curative" + And the value of the objective function after CRA should be 0 + + @fast @costly @rao @second-preventive + Scenario: US 92.2.5: PST in 2nd preventive optimization + PST is moved to tap -9 straight from preventive optimization to cut curative activation costs. + Given network file is "epic92/2Nodes3ParallelLinesPST.uct" + Given crac file is "epic92/crac-92-2-3.json" + Given configuration file is "epic92/RaoParameters_dc_minObjective_discretePst_2P.json" + When I launch search_tree_rao + Then the worst margin is 11.73 MW + And the value of the objective function initially should be 4300000.0 + And 1 remedial actions are used in preventive + And the remedial action "pstBeFr3" is used in preventive + And the tap of PstRangeAction "pstBeFr3" should be -9 in preventive + # Activation of pstBeFr3 (20) + 9 taps moved (9 * 7.5) + And the value of the objective function after PRA should be 87.5 + And 0 remedial actions are used after "coBeFr2" at "curative" + And the value of the objective function after CRA should be 87.5 \ No newline at end of file diff --git a/tests/src/test/resources/com/powsybl/openrao/tests/features/epic92_costly_rao/US92_3.feature b/tests/src/test/resources/com/powsybl/openrao/tests/features/epic92_costly_rao/US92_3.feature new file mode 100644 index 0000000000..b134d78d36 --- /dev/null +++ b/tests/src/test/resources/com/powsybl/openrao/tests/features/epic92_costly_rao/US92_3.feature @@ -0,0 +1,116 @@ +# Copyright (c) 2024, 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/. + + +Feature: US 92.3: Exhaustive costly optimization - APPROXIMATED_INTEGERS PSTs + + @fast @preventive-only @costly @rao + Scenario: US 92.3.1: Activate one topological action and one PST in preventive + Two ways to secure the network: + 1. move PST to tap -5 => cost of 25 + 2. (optimal) close line BE-FR 2 and move PST to tap -2 => cost of 20 + Given network file is "epic92/2Nodes3ParallelLinesPST2LinesClosed.uct" + Given crac file is "epic92/crac-92-3-1.json" + Given configuration file is "epic92/RaoParameters_dc_minObjective_discretePst.json" + When I launch search_tree_rao + Then the worst margin is 32.13 MW + And the value of the objective function initially should be 2000000.0 + And 2 remedial actions are used in preventive + And the remedial action "pstBeFr3" is used in preventive + And the tap of PstRangeAction "pstBeFr3" should be -2 in preventive + And the remedial action "closeBeFr2" is used in preventive + And the value of the objective function after PRA should be 20.0 + + @fast @costly @rao + Scenario: US 92.3.2: Preventive and curative PST + curative topological action + The PST is moved to tap -5 to secure the preventive perimeter for a total cost of 95 + (20 for activation + 5 * 15 for variation). Then, there are two ways to secure the curative perimeter: + 1. move PST to tap -7 => cost of 20 + 2 * 15 = 50 + 2. (optimal) close line BE-FR 3 and move PST to tap -6 => cost of 10 + 20 + 1 * 15 = 45 + Given network file is "epic92/2Nodes4ParallelLinesPST3LinesClosed.uct" + Given crac file is "epic92/crac-92-3-2.json" + Given configuration file is "epic92/RaoParameters_dc_minObjective_discretePst.json" + When I launch search_tree_rao + # Worst margin on preventive CNEC + Then the worst margin is 5.3 MW + And the value of the objective function initially should be 3500000.0 + And 1 remedial actions are used in preventive + And the remedial action "pstBeFr4" is used in preventive + And the tap of PstRangeAction "pstBeFr4" should be -5 in preventive + # Activation of pstBeFr4 (20) + 5 taps moved (5 * 15) + overload penalty (282.71 * 10000) + And the value of the objective function after PRA should be 1045531.44 + And 2 remedial actions are used after "coBeFr2" at "curative" + And the remedial action "pstBeFr4" is used after "coBeFr2" at "curative" + And the tap of PstRangeAction "pstBeFr4" should be -6 after "coBeFr2" at "curative" + And the remedial action "closeBeFr3" is used after "coBeFr2" at "curative" + # Activation of pstBeFr4 twice (2 * 20) + 6 taps moved in total (6 * 15) + activation of closeBeFr3 (10) + And the value of the objective function after CRA should be 140.0 + + @fast @costly @rao @second-preventive + Scenario: US 92.3.3: Preventive and curative PST + curative topological action with 2nd preventive optimization + The PST is moved to tap -6 straight from preventive to only activate the remedial action once. + Given network file is "epic92/2Nodes4ParallelLinesPST3LinesClosed.uct" + Given crac file is "epic92/crac-92-3-2.json" + Given configuration file is "epic92/RaoParameters_dc_minObjective_discretePst_2P.json" + When I launch search_tree_rao + # Worst margin on curative CNEC + Then the worst margin is 13.02 MW + And the value of the objective function initially should be 3500000.0 + And 1 remedial actions are used in preventive + And the remedial action "pstBeFr4" is used in preventive + And the tap of PstRangeAction "pstBeFr4" should be -6 in preventive + # Activation of pstBeFr4 (20) + 6 taps moved (6 * 15) + overload penalty (55.46 * 10000) + And the value of the objective function after PRA should be 554758.53 + And 1 remedial actions are used after "coBeFr2" at "curative" + And the remedial action "closeBeFr3" is used after "coBeFr2" at "curative" + # Activation of pstBeFr4 (20) + 6 taps moved in total (6 * 15) + activation of closeBeFr3 (10) + And the value of the objective function after CRA should be 120.0 + + @fast @costly @rao + Scenario: US 92.3.4: Preventive and curative PST + curative topological action - 2 scenarios + Given network file is "epic92/2Nodes5ParallelLinesPST4LinesClosed.uct" + Given crac file is "epic92/crac-92-3-4.json" + Given configuration file is "epic92/RaoParameters_dc_minObjective_discretePst.json" + When I launch search_tree_rao + # Worst margin on preventive CNEC + Then the worst margin is 2.73 MW + And the value of the objective function initially should be 2333333.33 + And 1 remedial actions are used in preventive + And the remedial action "pstBeFr5" is used in preventive + And the tap of PstRangeAction "pstBeFr5" should be -5 in preventive + # Activation of pstBeFr4 (20) + 5 taps moved (5 * 15) + overload penalty (69.7 * 10000) + And the value of the objective function after PRA should be 696982.63 + And 2 remedial actions are used after "coBeFr2" at "curative" + And the remedial action "pstBeFr5" is used after "coBeFr2" at "curative" + And the tap of PstRangeAction "pstBeFr5" should be -6 after "coBeFr2" at "curative" + And the remedial action "closeBeFr4" is used after "coBeFr2" at "curative" + And 2 remedial actions are used after "coBeFr3" at "curative" + And the remedial action "pstBeFr5" is used after "coBeFr3" at "curative" + And the tap of PstRangeAction "pstBeFr5" should be -7 after "coBeFr3" at "curative" + And the remedial action "closeBeFr4" is used after "coBeFr3" at "curative" + # Activation of pstBeFr4 three times (3 * 20) + 8 taps moved in total (8 * 15) + activation of closeBeFr3 twice (2 * 10) + And the value of the objective function after CRA should be 200.0 + + @fast @costly @rao @second-preventive + Scenario: US 92.3.5: Preventive and curative PST + curative topological action - 2 scenarios with 2nd preventive optimization + To cut activation cost expenses, the PST is moved to tap -7 straight from preventive optimization. + Given network file is "epic92/2Nodes5ParallelLinesPST4LinesClosed.uct" + Given crac file is "epic92/crac-92-3-4.json" + Given configuration file is "epic92/RaoParameters_dc_minObjective_discretePst_2P.json" + When I launch search_tree_rao + # Worst margin on curative CNEC + Then the worst margin is 21.8 MW + And the value of the objective function initially should be 2333333.33 + And 1 remedial actions are used in preventive + And the remedial action "pstBeFr5" is used in preventive + And the tap of PstRangeAction "pstBeFr5" should be -7 in preventive + # Activation of pstBeFr4 (20) + 5 taps moved (7 * 15) + overload penalty (4.26 * 10000) + And the value of the objective function after PRA should be 42744.12 + And 1 remedial actions are used after "coBeFr2" at "curative" + And the remedial action "closeBeFr4" is used after "coBeFr2" at "curative" + And 1 remedial actions are used after "coBeFr3" at "curative" + And the remedial action "closeBeFr4" is used after "coBeFr3" at "curative" + # Activation of pstBeFr4 (20) + 7 taps moved in total (7 * 15) + activation of closeBeFr3 twice (2 * 10) + And the value of the objective function after CRA should be 145.0 \ No newline at end of file diff --git a/tests/src/test/resources/files/cases/epic92/2Nodes2ParallelLinesPST.uct b/tests/src/test/resources/files/cases/epic92/2Nodes2ParallelLinesPST.uct new file mode 100644 index 0000000000..c4b652e668 --- /dev/null +++ b/tests/src/test/resources/files/cases/epic92/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 5000 PST +##R +BBE1AA1 FFR1AA1 2 -0.68 90.00 16 0 SYMM diff --git a/tests/src/test/resources/files/cases/epic92/2Nodes3ParallelLines2PSTs.uct b/tests/src/test/resources/files/cases/epic92/2Nodes3ParallelLines2PSTs.uct new file mode 100644 index 0000000000..1942010820 --- /dev/null +++ b/tests/src/test/resources/files/cases/epic92/2Nodes3ParallelLines2PSTs.uct @@ -0,0 +1,14 @@ +##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 5000 PST +BBE1AA1 FFR1AA1 3 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 5000 PST +##R +BBE1AA1 FFR1AA1 2 -0.68 90.00 16 0 SYMM +BBE1AA1 FFR1AA1 3 -0.68 90.00 16 0 SYMM diff --git a/tests/src/test/resources/files/cases/epic92/2Nodes3ParallelLinesPST.uct b/tests/src/test/resources/files/cases/epic92/2Nodes3ParallelLinesPST.uct new file mode 100644 index 0000000000..82298057cb --- /dev/null +++ b/tests/src/test/resources/files/cases/epic92/2Nodes3ParallelLinesPST.uct @@ -0,0 +1,13 @@ +##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 +BBE1AA1 FFR1AA1 2 0 0.0000 10.000 0.000000 5000 +##T +BBE1AA1 FFR1AA1 3 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 5000 PST +##R +BBE1AA1 FFR1AA1 3 -0.68 90.00 16 0 SYMM diff --git a/tests/src/test/resources/files/cases/epic92/2Nodes3ParallelLinesPST2LinesClosed.uct b/tests/src/test/resources/files/cases/epic92/2Nodes3ParallelLinesPST2LinesClosed.uct new file mode 100644 index 0000000000..8607f65a3a --- /dev/null +++ b/tests/src/test/resources/files/cases/epic92/2Nodes3ParallelLinesPST2LinesClosed.uct @@ -0,0 +1,13 @@ +##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 +BBE1AA1 FFR1AA1 2 8 0.0000 10.000 0.000000 5000 +##T +BBE1AA1 FFR1AA1 3 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 5000 PST +##R +BBE1AA1 FFR1AA1 3 -0.68 90.00 16 0 SYMM diff --git a/tests/src/test/resources/files/cases/epic92/2Nodes4ParallelLinesPST3LinesClosed.uct b/tests/src/test/resources/files/cases/epic92/2Nodes4ParallelLinesPST3LinesClosed.uct new file mode 100644 index 0000000000..86891741bd --- /dev/null +++ b/tests/src/test/resources/files/cases/epic92/2Nodes4ParallelLinesPST3LinesClosed.uct @@ -0,0 +1,14 @@ +##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 +BBE1AA1 FFR1AA1 2 0 0.0000 10.000 0.000000 5000 +BBE1AA1 FFR1AA1 3 8 0.0000 10.000 0.000000 5000 +##T +BBE1AA1 FFR1AA1 4 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 5000 PST +##R +BBE1AA1 FFR1AA1 4 -0.68 90.00 16 0 SYMM diff --git a/tests/src/test/resources/files/cases/epic92/2Nodes5ParallelLinesPST4LinesClosed.uct b/tests/src/test/resources/files/cases/epic92/2Nodes5ParallelLinesPST4LinesClosed.uct new file mode 100644 index 0000000000..e83c5a9072 --- /dev/null +++ b/tests/src/test/resources/files/cases/epic92/2Nodes5ParallelLinesPST4LinesClosed.uct @@ -0,0 +1,15 @@ +##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 +BBE1AA1 FFR1AA1 2 0 0.0000 10.000 0.000000 5000 +BBE1AA1 FFR1AA1 3 0 0.0000 10.000 0.000000 5000 +BBE1AA1 FFR1AA1 4 8 0.0000 10.000 0.000000 5000 +##T +BBE1AA1 FFR1AA1 5 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 5000 PST +##R +BBE1AA1 FFR1AA1 5 -0.68 90.00 16 0 SYMM diff --git a/tests/src/test/resources/files/configurations/epic92/RaoParameters_dc_minObjective_2P.json b/tests/src/test/resources/files/configurations/epic92/RaoParameters_dc_minObjective_2P.json new file mode 100644 index 0000000000..7798599dcf --- /dev/null +++ b/tests/src/test/resources/files/configurations/epic92/RaoParameters_dc_minObjective_2P.json @@ -0,0 +1,134 @@ +{ + "version" : "2.4", + "objective-function" : { + "type" : "MIN_COST_IN_MEGAWATT", + "forbid-cost-increase" : false, + "curative-min-obj-improvement" : 0.0, + "preventive-stop-criterion" : "MIN_OBJECTIVE", + "curative-stop-criterion" : "MIN_OBJECTIVE" + }, + "range-actions-optimization" : { + "max-mip-iterations" : 5, + "pst-penalty-cost" : 0.01, + "pst-sensitivity-threshold" : 1.0E-6, + "pst-model" : "CONTINUOUS", + "hvdc-penalty-cost" : 0.001, + "hvdc-sensitivity-threshold" : 1.0E-6, + "injection-ra-penalty-cost" : 0.001, + "injection-ra-sensitivity-threshold" : 1.0E-6, + "ra-range-shrinking" : "DISABLED", + "linear-optimization-solver" : { + "solver" : "CBC", + "relative-mip-gap" : 0.001, + "solver-specific-parameters" : null + } + }, + "topological-actions-optimization" : { + "max-preventive-search-tree-depth" : 5, + "max-auto-search-tree-depth" : 5, + "max-curative-search-tree-depth" : 5, + "predefined-combinations" : [ ], + "relative-minimum-impact-threshold" : 0.0, + "absolute-minimum-impact-threshold" : 0.0, + "skip-actions-far-from-most-limiting-element" : false, + "max-number-of-boundaries-for-skipping-actions" : 0 + }, + "multi-threading" : { + "contingency-scenarios-in-parallel" : 2, + "preventive-leaves-in-parallel" : 4, + "curative-leaves-in-parallel" : 2 + }, + "second-preventive-rao" : { + "execution-condition" : "POSSIBLE_CURATIVE_IMPROVEMENT", + "re-optimize-curative-range-actions" : true, + "hint-from-first-preventive-rao" : false + }, + "not-optimized-cnecs" : { + "do-not-optimize-curative-cnecs-for-tsos-without-cras" : false + }, + "load-flow-and-sensitivity-computation" : { + "load-flow-provider" : "OpenLoadFlow", + "sensitivity-provider" : "OpenLoadFlow", + "sensitivity-failure-overcost" : 10000.0, + "sensitivity-parameters" : { + "version" : "1.0", + "load-flow-parameters" : { + "version" : "1.9", + "voltageInitMode" : "UNIFORM_VALUES", + "transformerVoltageControlOn" : false, + "phaseShifterRegulationOn" : false, + "useReactiveLimits" : true, + "twtSplitShuntAdmittance" : true, + "shuntCompensatorVoltageControlOn" : false, + "readSlackBus" : false, + "writeSlackBus" : true, + "dc" : true, + "distributedSlack" : true, + "balanceType" : "PROPORTIONAL_TO_GENERATION_P", + "dcUseTransformerRatio" : false, + "countriesToBalance" : [ "GR", "BE", "SK", "TR", "CH", "RS", "PL", "UA", "BG", "ES", "ME", "CZ", "HR", "AL", "RO", "HU", "AT", "FR", "PT", "DE", "MK", "BA", "SI", "IT", "NL" ], + "connectedComponentMode" : "MAIN", + "hvdcAcEmulation" : true, + "dcPowerFactor" : 1.0, + "extensions" : { + "open-load-flow-parameters" : { + "slackBusSelectionMode" : "MOST_MESHED", + "slackBusesIds" : [ ], + "slackDistributionFailureBehavior" : "LEAVE_ON_SLACK_BUS", + "lowImpedanceBranchMode" : "REPLACE_BY_ZERO_IMPEDANCE_LINE", + "loadPowerFactorConstant" : false, + "plausibleActivePowerLimit" : 10000.0, + "newtonRaphsonStoppingCriteriaType" : "UNIFORM_CRITERIA", + "maxActivePowerMismatch" : 0.01, + "maxReactivePowerMismatch" : 0.01, + "maxVoltageMismatch" : 1.0E-4, + "maxAngleMismatch" : 1.0E-5, + "maxRatioMismatch" : 1.0E-5, + "maxSusceptanceMismatch" : 1.0E-4, + "slackBusPMaxMismatch" : 1.0, + "voltagePerReactivePowerControl" : false, + "maxNewtonRaphsonIterations" : 30, + "maxOuterLoopIterations" : 20, + "newtonRaphsonConvEpsPerEq" : 1.0E-4, + "voltageInitModeOverride" : "NONE", + "transformerVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL", + "shuntVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL", + "minPlausibleTargetVoltage" : 0.8, + "maxPlausibleTargetVoltage" : 1.2, + "minNominalVoltageTargetVoltageCheck" : 20.0, + "minRealisticVoltage" : 0.5, + "maxRealisticVoltage" : 1.5, + "lowImpedanceThreshold" : 1.0E-8, + "reactiveRangeCheckMode" : "MAX", + "networkCacheEnabled" : false, + "svcVoltageMonitoring" : true, + "stateVectorScalingMode" : "NONE", + "maxSlackBusCount" : 1, + "debugDir" : null, + "incrementalTransformerRatioTapControlOuterLoopMaxTapShift" : 3, + "secondaryVoltageControl" : false, + "reactiveLimitsMaxPqPvSwitch" : 3, + "phaseShifterControlMode" : "CONTINUOUS_WITH_DISCRETISATION", + "alwaysUpdateNetwork" : false, + "mostMeshedSlackBusSelectorMaxNominalVoltagePercentile" : 95.0, + "reportedFeatures" : [ ], + "slackBusCountryFilter" : [ ], + "actionableSwitchesIds" : [ ], + "asymmetrical" : false, + "reactivePowerDispatchMode" : "Q_EQUAL_PROPORTION", + "outerLoopNames" : null, + "useActiveLimits" : true, + "lineSearchStateVectorScalingMaxIteration" : 10, + "lineSearchStateVectorScalingStepFold" : 1.3333333333333333, + "maxVoltageChangeStateVectorScalingMaxDv" : 0.1, + "maxVoltageChangeStateVectorScalingMaxDphi" : 0.17453292519943295, + "linePerUnitMode" : "IMPEDANCE", + "useLoadModel" : false, + "dcApproximationType" : "IGNORE_R", + "simulateAutomationSystems" : false + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/src/test/resources/files/configurations/epic92/RaoParameters_dc_minObjective_discretePst.json b/tests/src/test/resources/files/configurations/epic92/RaoParameters_dc_minObjective_discretePst.json new file mode 100644 index 0000000000..96c7381fb3 --- /dev/null +++ b/tests/src/test/resources/files/configurations/epic92/RaoParameters_dc_minObjective_discretePst.json @@ -0,0 +1,134 @@ +{ + "version" : "2.4", + "objective-function" : { + "type" : "MIN_COST_IN_MEGAWATT", + "forbid-cost-increase" : false, + "curative-min-obj-improvement" : 0.0, + "preventive-stop-criterion" : "MIN_OBJECTIVE", + "curative-stop-criterion" : "MIN_OBJECTIVE" + }, + "range-actions-optimization" : { + "max-mip-iterations" : 5, + "pst-penalty-cost" : 0.01, + "pst-sensitivity-threshold" : 1.0E-6, + "pst-model" : "APPROXIMATED_INTEGERS", + "hvdc-penalty-cost" : 0.001, + "hvdc-sensitivity-threshold" : 1.0E-6, + "injection-ra-penalty-cost" : 0.001, + "injection-ra-sensitivity-threshold" : 1.0E-6, + "ra-range-shrinking" : "DISABLED", + "linear-optimization-solver" : { + "solver" : "CBC", + "relative-mip-gap" : 0.001, + "solver-specific-parameters" : null + } + }, + "topological-actions-optimization" : { + "max-preventive-search-tree-depth" : 5, + "max-auto-search-tree-depth" : 5, + "max-curative-search-tree-depth" : 5, + "predefined-combinations" : [ ], + "relative-minimum-impact-threshold" : 0.0, + "absolute-minimum-impact-threshold" : 0.0, + "skip-actions-far-from-most-limiting-element" : false, + "max-number-of-boundaries-for-skipping-actions" : 0 + }, + "multi-threading" : { + "contingency-scenarios-in-parallel" : 2, + "preventive-leaves-in-parallel" : 4, + "curative-leaves-in-parallel" : 2 + }, + "second-preventive-rao" : { + "execution-condition" : "DISABLED", + "re-optimize-curative-range-actions" : false, + "hint-from-first-preventive-rao" : false + }, + "not-optimized-cnecs" : { + "do-not-optimize-curative-cnecs-for-tsos-without-cras" : false + }, + "load-flow-and-sensitivity-computation" : { + "load-flow-provider" : "OpenLoadFlow", + "sensitivity-provider" : "OpenLoadFlow", + "sensitivity-failure-overcost" : 10000.0, + "sensitivity-parameters" : { + "version" : "1.0", + "load-flow-parameters" : { + "version" : "1.9", + "voltageInitMode" : "UNIFORM_VALUES", + "transformerVoltageControlOn" : false, + "phaseShifterRegulationOn" : false, + "useReactiveLimits" : true, + "twtSplitShuntAdmittance" : true, + "shuntCompensatorVoltageControlOn" : false, + "readSlackBus" : false, + "writeSlackBus" : true, + "dc" : true, + "distributedSlack" : true, + "balanceType" : "PROPORTIONAL_TO_GENERATION_P", + "dcUseTransformerRatio" : false, + "countriesToBalance" : [ "GR", "BE", "SK", "TR", "CH", "RS", "PL", "UA", "BG", "ES", "ME", "CZ", "HR", "AL", "RO", "HU", "AT", "FR", "PT", "DE", "MK", "BA", "SI", "IT", "NL" ], + "connectedComponentMode" : "MAIN", + "hvdcAcEmulation" : true, + "dcPowerFactor" : 1.0, + "extensions" : { + "open-load-flow-parameters" : { + "slackBusSelectionMode" : "MOST_MESHED", + "slackBusesIds" : [ ], + "slackDistributionFailureBehavior" : "LEAVE_ON_SLACK_BUS", + "lowImpedanceBranchMode" : "REPLACE_BY_ZERO_IMPEDANCE_LINE", + "loadPowerFactorConstant" : false, + "plausibleActivePowerLimit" : 10000.0, + "newtonRaphsonStoppingCriteriaType" : "UNIFORM_CRITERIA", + "maxActivePowerMismatch" : 0.01, + "maxReactivePowerMismatch" : 0.01, + "maxVoltageMismatch" : 1.0E-4, + "maxAngleMismatch" : 1.0E-5, + "maxRatioMismatch" : 1.0E-5, + "maxSusceptanceMismatch" : 1.0E-4, + "slackBusPMaxMismatch" : 1.0, + "voltagePerReactivePowerControl" : false, + "maxNewtonRaphsonIterations" : 30, + "maxOuterLoopIterations" : 20, + "newtonRaphsonConvEpsPerEq" : 1.0E-4, + "voltageInitModeOverride" : "NONE", + "transformerVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL", + "shuntVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL", + "minPlausibleTargetVoltage" : 0.8, + "maxPlausibleTargetVoltage" : 1.2, + "minNominalVoltageTargetVoltageCheck" : 20.0, + "minRealisticVoltage" : 0.5, + "maxRealisticVoltage" : 1.5, + "lowImpedanceThreshold" : 1.0E-8, + "reactiveRangeCheckMode" : "MAX", + "networkCacheEnabled" : false, + "svcVoltageMonitoring" : true, + "stateVectorScalingMode" : "NONE", + "maxSlackBusCount" : 1, + "debugDir" : null, + "incrementalTransformerRatioTapControlOuterLoopMaxTapShift" : 3, + "secondaryVoltageControl" : false, + "reactiveLimitsMaxPqPvSwitch" : 3, + "phaseShifterControlMode" : "CONTINUOUS_WITH_DISCRETISATION", + "alwaysUpdateNetwork" : false, + "mostMeshedSlackBusSelectorMaxNominalVoltagePercentile" : 95.0, + "reportedFeatures" : [ ], + "slackBusCountryFilter" : [ ], + "actionableSwitchesIds" : [ ], + "asymmetrical" : false, + "reactivePowerDispatchMode" : "Q_EQUAL_PROPORTION", + "outerLoopNames" : null, + "useActiveLimits" : true, + "lineSearchStateVectorScalingMaxIteration" : 10, + "lineSearchStateVectorScalingStepFold" : 1.3333333333333333, + "maxVoltageChangeStateVectorScalingMaxDv" : 0.1, + "maxVoltageChangeStateVectorScalingMaxDphi" : 0.17453292519943295, + "linePerUnitMode" : "IMPEDANCE", + "useLoadModel" : false, + "dcApproximationType" : "IGNORE_R", + "simulateAutomationSystems" : false + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/src/test/resources/files/configurations/epic92/RaoParameters_dc_minObjective_discretePst_2P.json b/tests/src/test/resources/files/configurations/epic92/RaoParameters_dc_minObjective_discretePst_2P.json new file mode 100644 index 0000000000..8d3b175f5f --- /dev/null +++ b/tests/src/test/resources/files/configurations/epic92/RaoParameters_dc_minObjective_discretePst_2P.json @@ -0,0 +1,134 @@ +{ + "version" : "2.4", + "objective-function" : { + "type" : "MIN_COST_IN_MEGAWATT", + "forbid-cost-increase" : false, + "curative-min-obj-improvement" : 0.0, + "preventive-stop-criterion" : "MIN_OBJECTIVE", + "curative-stop-criterion" : "MIN_OBJECTIVE" + }, + "range-actions-optimization" : { + "max-mip-iterations" : 5, + "pst-penalty-cost" : 0.01, + "pst-sensitivity-threshold" : 1.0E-6, + "pst-model" : "APPROXIMATED_INTEGERS", + "hvdc-penalty-cost" : 0.001, + "hvdc-sensitivity-threshold" : 1.0E-6, + "injection-ra-penalty-cost" : 0.001, + "injection-ra-sensitivity-threshold" : 1.0E-6, + "ra-range-shrinking" : "DISABLED", + "linear-optimization-solver" : { + "solver" : "CBC", + "relative-mip-gap" : 0.001, + "solver-specific-parameters" : null + } + }, + "topological-actions-optimization" : { + "max-preventive-search-tree-depth" : 5, + "max-auto-search-tree-depth" : 5, + "max-curative-search-tree-depth" : 5, + "predefined-combinations" : [ ], + "relative-minimum-impact-threshold" : 0.0, + "absolute-minimum-impact-threshold" : 0.0, + "skip-actions-far-from-most-limiting-element" : false, + "max-number-of-boundaries-for-skipping-actions" : 0 + }, + "multi-threading" : { + "contingency-scenarios-in-parallel" : 2, + "preventive-leaves-in-parallel" : 4, + "curative-leaves-in-parallel" : 2 + }, + "second-preventive-rao" : { + "execution-condition" : "POSSIBLE_CURATIVE_IMPROVEMENT", + "re-optimize-curative-range-actions" : true, + "hint-from-first-preventive-rao" : false + }, + "not-optimized-cnecs" : { + "do-not-optimize-curative-cnecs-for-tsos-without-cras" : false + }, + "load-flow-and-sensitivity-computation" : { + "load-flow-provider" : "OpenLoadFlow", + "sensitivity-provider" : "OpenLoadFlow", + "sensitivity-failure-overcost" : 10000.0, + "sensitivity-parameters" : { + "version" : "1.0", + "load-flow-parameters" : { + "version" : "1.9", + "voltageInitMode" : "UNIFORM_VALUES", + "transformerVoltageControlOn" : false, + "phaseShifterRegulationOn" : false, + "useReactiveLimits" : true, + "twtSplitShuntAdmittance" : true, + "shuntCompensatorVoltageControlOn" : false, + "readSlackBus" : false, + "writeSlackBus" : true, + "dc" : true, + "distributedSlack" : true, + "balanceType" : "PROPORTIONAL_TO_GENERATION_P", + "dcUseTransformerRatio" : false, + "countriesToBalance" : [ "GR", "BE", "SK", "TR", "CH", "RS", "PL", "UA", "BG", "ES", "ME", "CZ", "HR", "AL", "RO", "HU", "AT", "FR", "PT", "DE", "MK", "BA", "SI", "IT", "NL" ], + "connectedComponentMode" : "MAIN", + "hvdcAcEmulation" : true, + "dcPowerFactor" : 1.0, + "extensions" : { + "open-load-flow-parameters" : { + "slackBusSelectionMode" : "MOST_MESHED", + "slackBusesIds" : [ ], + "slackDistributionFailureBehavior" : "LEAVE_ON_SLACK_BUS", + "lowImpedanceBranchMode" : "REPLACE_BY_ZERO_IMPEDANCE_LINE", + "loadPowerFactorConstant" : false, + "plausibleActivePowerLimit" : 10000.0, + "newtonRaphsonStoppingCriteriaType" : "UNIFORM_CRITERIA", + "maxActivePowerMismatch" : 0.01, + "maxReactivePowerMismatch" : 0.01, + "maxVoltageMismatch" : 1.0E-4, + "maxAngleMismatch" : 1.0E-5, + "maxRatioMismatch" : 1.0E-5, + "maxSusceptanceMismatch" : 1.0E-4, + "slackBusPMaxMismatch" : 1.0, + "voltagePerReactivePowerControl" : false, + "maxNewtonRaphsonIterations" : 30, + "maxOuterLoopIterations" : 20, + "newtonRaphsonConvEpsPerEq" : 1.0E-4, + "voltageInitModeOverride" : "NONE", + "transformerVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL", + "shuntVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL", + "minPlausibleTargetVoltage" : 0.8, + "maxPlausibleTargetVoltage" : 1.2, + "minNominalVoltageTargetVoltageCheck" : 20.0, + "minRealisticVoltage" : 0.5, + "maxRealisticVoltage" : 1.5, + "lowImpedanceThreshold" : 1.0E-8, + "reactiveRangeCheckMode" : "MAX", + "networkCacheEnabled" : false, + "svcVoltageMonitoring" : true, + "stateVectorScalingMode" : "NONE", + "maxSlackBusCount" : 1, + "debugDir" : null, + "incrementalTransformerRatioTapControlOuterLoopMaxTapShift" : 3, + "secondaryVoltageControl" : false, + "reactiveLimitsMaxPqPvSwitch" : 3, + "phaseShifterControlMode" : "CONTINUOUS_WITH_DISCRETISATION", + "alwaysUpdateNetwork" : false, + "mostMeshedSlackBusSelectorMaxNominalVoltagePercentile" : 95.0, + "reportedFeatures" : [ ], + "slackBusCountryFilter" : [ ], + "actionableSwitchesIds" : [ ], + "asymmetrical" : false, + "reactivePowerDispatchMode" : "Q_EQUAL_PROPORTION", + "outerLoopNames" : null, + "useActiveLimits" : true, + "lineSearchStateVectorScalingMaxIteration" : 10, + "lineSearchStateVectorScalingStepFold" : 1.3333333333333333, + "maxVoltageChangeStateVectorScalingMaxDv" : 0.1, + "maxVoltageChangeStateVectorScalingMaxDphi" : 0.17453292519943295, + "linePerUnitMode" : "IMPEDANCE", + "useLoadModel" : false, + "dcApproximationType" : "IGNORE_R", + "simulateAutomationSystems" : false + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/src/test/resources/files/crac/epic92/crac-92-2-1.json b/tests/src/test/resources/files/crac/epic92/crac-92-2-1.json new file mode 100644 index 0000000000..0cbfacc315 --- /dev/null +++ b/tests/src/test/resources/files/crac/epic92/crac-92-2-1.json @@ -0,0 +1,116 @@ +{ + "type": "CRAC", + "version": "2.6", + "info": "Generated by PowSyBl OpenRAO https://powsybl.readthedocs.io/projects/openrao/", + "id": "crac-92.2.1", + "name": "crac-92.2.1", + "instants": [ + { + "id": "preventive", + "kind": "PREVENTIVE" + }, + { + "id": "outage", + "kind": "OUTAGE" + }, + { + "id": "curative", + "kind": "CURATIVE" + } + ], + "networkElementsNamePerId": {}, + "flowCnecs": [ + { + "id": "cnecBeFrPreventive", + "name": "cnecBeFrPreventive", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "preventive", + "contingencyId": null, + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -300.0, + "max": 300.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -300.0, + "max": 300.0, + "side": 2 + } + ] + } + ], + "pstRangeActions": [ + { + "id": "pstBeFr2", + "name": "pstBeFr2", + "operator": "BE", + "activationCost": 5.0, + "variationCosts": { + "up": 10.0, + "down": 10.0 + }, + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "networkElementId": "BBE1AA1 FFR1AA1 2", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/src/test/resources/files/crac/epic92/crac-92-2-2.json b/tests/src/test/resources/files/crac/epic92/crac-92-2-2.json new file mode 100644 index 0000000000..511f46ee1e --- /dev/null +++ b/tests/src/test/resources/files/crac/epic92/crac-92-2-2.json @@ -0,0 +1,176 @@ +{ + "type": "CRAC", + "version": "2.6", + "info": "Generated by PowSyBl OpenRAO https://powsybl.readthedocs.io/projects/openrao/", + "id": "crac-92.2.2", + "name": "crac-92.2.2", + "instants": [ + { + "id": "preventive", + "kind": "PREVENTIVE" + }, + { + "id": "outage", + "kind": "OUTAGE" + }, + { + "id": "curative", + "kind": "CURATIVE" + } + ], + "networkElementsNamePerId": {}, + "flowCnecs": [ + { + "id": "cnecBeFrPreventive", + "name": "cnecBeFrPreventive", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "preventive", + "contingencyId": null, + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -70.0, + "max": 70.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -70.0, + "max": 70.0, + "side": 2 + } + ] + } + ], + "pstRangeActions": [ + { + "id": "pstBeFr2", + "name": "pstBeFr2", + "operator": "BE", + "activationCost": 100.0, + "variationCosts": { + "up": 5.0, + "down": 5.0 + }, + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "networkElementId": "BBE1AA1 FFR1AA1 2", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ] + }, + { + "id": "pstBeFr3", + "name": "pstBeFr3", + "operator": "BE", + "activationCost": 5.0, + "variationCosts": { + "up": 15.0, + "down": 15.0 + }, + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "networkElementId": "BBE1AA1 FFR1AA1 3", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/src/test/resources/files/crac/epic92/crac-92-2-3.json b/tests/src/test/resources/files/crac/epic92/crac-92-2-3.json new file mode 100644 index 0000000000..a47d8371db --- /dev/null +++ b/tests/src/test/resources/files/crac/epic92/crac-92-2-3.json @@ -0,0 +1,161 @@ +{ + "type": "CRAC", + "version": "2.6", + "info": "Generated by PowSyBl OpenRAO https://powsybl.readthedocs.io/projects/openrao/", + "id": "crac-92.2.3", + "name": "crac-92.2.3", + "instants": [ + { + "id": "preventive", + "kind": "PREVENTIVE" + }, + { + "id": "outage", + "kind": "OUTAGE" + }, + { + "id": "curative", + "kind": "CURATIVE" + } + ], + "networkElementsNamePerId": {}, + "contingencies": [ + { + "id": "coBeFr2", + "networkElementsIds": [ + "BBE1AA1 FFR1AA1 2" + ] + } + ], + "flowCnecs": [ + { + "id": "cnecBeFrPreventive", + "name": "cnecBeFrPreventive", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "preventive", + "contingencyId": null, + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -250.0, + "max": 250.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -250.0, + "max": 250.0, + "side": 2 + } + ] + }, + { + "id": "cnecBeFrCurative", + "name": "cnecBeFrCurative", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "curative", + "contingencyId": "coBeFr2", + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -70.0, + "max": 70.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -70.0, + "max": 70.0, + "side": 2 + } + ] + } + ], + "pstRangeActions": [ + { + "id": "pstBeFr3", + "name": "pstBeFr3", + "operator": "BE", + "activationCost": 20.0, + "variationCosts": { + "up": 7.5, + "down": 7.5 + }, + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "onContingencyStateUsageRules": [ + { + "instant": "curative", + "contingencyId": "coBeFr2", + "usageMethod": "available" + } + ], + "networkElementId": "BBE1AA1 FFR1AA1 3", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/src/test/resources/files/crac/epic92/crac-92-2-4.json b/tests/src/test/resources/files/crac/epic92/crac-92-2-4.json new file mode 100644 index 0000000000..ec6c3fcfb6 --- /dev/null +++ b/tests/src/test/resources/files/crac/epic92/crac-92-2-4.json @@ -0,0 +1,156 @@ +{ + "type": "CRAC", + "version": "2.6", + "info": "Generated by PowSyBl OpenRAO https://powsybl.readthedocs.io/projects/openrao/", + "id": "crac-92.2.4", + "name": "crac-92.2.4", + "instants": [ + { + "id": "preventive", + "kind": "PREVENTIVE" + }, + { + "id": "outage", + "kind": "OUTAGE" + }, + { + "id": "curative", + "kind": "CURATIVE" + } + ], + "networkElementsNamePerId": {}, + "contingencies": [ + { + "id": "coBeFr2", + "networkElementsIds": [ + "BBE1AA1 FFR1AA1 2" + ] + } + ], + "flowCnecs": [ + { + "id": "cnecBeFrPreventive", + "name": "cnecBeFrPreventive", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "preventive", + "contingencyId": null, + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -250.0, + "max": 250.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -250.0, + "max": 250.0, + "side": 2 + } + ] + }, + { + "id": "cnecBeFrCurative", + "name": "cnecBeFrCurative", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "curative", + "contingencyId": "coBeFr2", + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -70.0, + "max": 70.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -70.0, + "max": 70.0, + "side": 2 + } + ] + } + ], + "pstRangeActions": [ + { + "id": "pstBeFr3", + "name": "pstBeFr3", + "operator": "BE", + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "onContingencyStateUsageRules": [ + { + "instant": "curative", + "contingencyId": "coBeFr2", + "usageMethod": "available" + } + ], + "networkElementId": "BBE1AA1 FFR1AA1 3", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/src/test/resources/files/crac/epic92/crac-92-3-1.json b/tests/src/test/resources/files/crac/epic92/crac-92-3-1.json new file mode 100644 index 0000000000..bf2c007f32 --- /dev/null +++ b/tests/src/test/resources/files/crac/epic92/crac-92-3-1.json @@ -0,0 +1,135 @@ +{ + "type": "CRAC", + "version": "2.6", + "info": "Generated by PowSyBl OpenRAO https://powsybl.readthedocs.io/projects/openrao/", + "id": "crac-92.3.1", + "name": "crac-92.3.1", + "instants": [ + { + "id": "preventive", + "kind": "PREVENTIVE" + }, + { + "id": "outage", + "kind": "OUTAGE" + }, + { + "id": "curative", + "kind": "CURATIVE" + } + ], + "networkElementsNamePerId": {}, + "flowCnecs": [ + { + "id": "cnecBeFrPreventive", + "name": "cnecBeFrPreventive", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "preventive", + "contingencyId": null, + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -300.0, + "max": 300.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -300.0, + "max": 300.0, + "side": 2 + } + ] + } + ], + "pstRangeActions": [ + { + "id": "pstBeFr3", + "name": "pstBeFr3", + "operator": "BE", + "variationCosts": { + "up": 5.0, + "down": 5.0 + }, + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "networkElementId": "BBE1AA1 FFR1AA1 3", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ] + } + ], + "networkActions": [ + { + "id": "closeBeFr2", + "name": "closeBeFr2", + "operator": "FR", + "activationCost": 10.0, + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "terminalsConnectionActions": [ + { + "networkElementId": "BBE1AA1 FFR1AA1 2", + "actionType": "close" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/src/test/resources/files/crac/epic92/crac-92-3-2.json b/tests/src/test/resources/files/crac/epic92/crac-92-3-2.json new file mode 100644 index 0000000000..0368e1b095 --- /dev/null +++ b/tests/src/test/resources/files/crac/epic92/crac-92-3-2.json @@ -0,0 +1,182 @@ +{ + "type": "CRAC", + "version": "2.6", + "info": "Generated by PowSyBl OpenRAO https://powsybl.readthedocs.io/projects/openrao/", + "id": "crac-92.3.1", + "name": "crac-92.3.1", + "instants": [ + { + "id": "preventive", + "kind": "PREVENTIVE" + }, + { + "id": "outage", + "kind": "OUTAGE" + }, + { + "id": "curative", + "kind": "CURATIVE" + } + ], + "networkElementsNamePerId": {}, + "contingencies": [ + { + "id": "coBeFr2", + "networkElementsIds": [ + "BBE1AA1 FFR1AA1 2" + ] + } + ], + "flowCnecs": [ + { + "id": "cnecBeFrPreventive", + "name": "cnecBeFrPreventive", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "preventive", + "contingencyId": null, + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -175.0, + "max": 175.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -175.0, + "max": 175.0, + "side": 2 + } + ] + }, + { + "id": "cnecBeFrCurative", + "name": "cnecBeFrCurative", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "curative", + "contingencyId": "coBeFr2", + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -150.0, + "max": 150.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -150.0, + "max": 150.0, + "side": 2 + } + ] + } + ], + "pstRangeActions": [ + { + "id": "pstBeFr4", + "name": "pstBeFr4", + "operator": "BE", + "activationCost": 20.0, + "variationCosts": { + "up": 15.0, + "down": 15.0 + }, + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "onContingencyStateUsageRules": [ + { + "instant": "curative", + "contingencyId": "coBeFr2", + "usageMethod": "available" + } + ], + "networkElementId": "BBE1AA1 FFR1AA1 4", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ] + } + ], + "networkActions": [ + { + "id": "closeBeFr3", + "name": "closeBeFr3", + "operator": "FR", + "activationCost": 10.0, + "onContingencyStateUsageRules": [ + { + "instant": "curative", + "contingencyId": "coBeFr2", + "usageMethod": "available" + } + ], + "terminalsConnectionActions": [ + { + "networkElementId": "BBE1AA1 FFR1AA1 3", + "actionType": "close" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/src/test/resources/files/crac/epic92/crac-92-3-4.json b/tests/src/test/resources/files/crac/epic92/crac-92-3-4.json new file mode 100644 index 0000000000..d8e29a0df5 --- /dev/null +++ b/tests/src/test/resources/files/crac/epic92/crac-92-3-4.json @@ -0,0 +1,228 @@ +{ + "type": "CRAC", + "version": "2.6", + "info": "Generated by PowSyBl OpenRAO https://powsybl.readthedocs.io/projects/openrao/", + "id": "crac-92.3.4", + "name": "crac-92.3.4", + "instants": [ + { + "id": "preventive", + "kind": "PREVENTIVE" + }, + { + "id": "outage", + "kind": "OUTAGE" + }, + { + "id": "curative", + "kind": "CURATIVE" + } + ], + "networkElementsNamePerId": {}, + "contingencies": [ + { + "id": "coBeFr2", + "networkElementsIds": [ + "BBE1AA1 FFR1AA1 2" + ] + }, + { + "id": "coBeFr3", + "networkElementsIds": [ + "BBE1AA1 FFR1AA1 3" + ] + } + ], + "flowCnecs": [ + { + "id": "cnecBeFrPreventive", + "name": "cnecBeFrPreventive", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "preventive", + "contingencyId": null, + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -130.0, + "max": 130.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -130.0, + "max": 130.0, + "side": 2 + } + ] + }, + { + "id": "cnecBeFrCurative - coBeFr2", + "name": "cnecBeFrCurative - coBeFr2", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "curative", + "contingencyId": "coBeFr2", + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -110.0, + "max": 110.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -110.0, + "max": 110.0, + "side": 2 + } + ] + }, + { + "id": "cnecBeFrCurative - coBeFr3", + "name": "cnecBeFrCurative - coBeFr3", + "networkElementId": "BBE1AA1 FFR1AA1 1", + "operator": "FR", + "instant": "curative", + "contingencyId": "coBeFr3", + "optimized": true, + "monitored": false, + "iMax": [ + NaN + ], + "nominalV": [ + 400.0 + ], + "thresholds": [ + { + "unit": "megawatt", + "min": -100.0, + "max": 100.0, + "side": 1 + }, + { + "unit": "megawatt", + "min": -100.0, + "max": 100.0, + "side": 2 + } + ] + } + ], + "pstRangeActions": [ + { + "id": "pstBeFr5", + "name": "pstBeFr5", + "operator": "BE", + "activationCost": 20.0, + "variationCosts": { + "up": 15.0, + "down": 15.0 + }, + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "onContingencyStateUsageRules": [ + { + "instant": "curative", + "contingencyId": "coBeFr2", + "usageMethod": "available" + }, + { + "instant": "curative", + "contingencyId": "coBeFr3", + "usageMethod": "available" + } + ], + "networkElementId": "BBE1AA1 FFR1AA1 5", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ] + } + ], + "networkActions": [ + { + "id": "closeBeFr4", + "name": "closeBeFr4", + "operator": "FR", + "activationCost": 10.0, + "onContingencyStateUsageRules": [ + { + "instant": "curative", + "contingencyId": "coBeFr2", + "usageMethod": "available" + }, + { + "instant": "curative", + "contingencyId": "coBeFr3", + "usageMethod": "available" + } + ], + "terminalsConnectionActions": [ + { + "networkElementId": "BBE1AA1 FFR1AA1 4", + "actionType": "close" + } + ] + } + ] +} \ No newline at end of file