Skip to content

Commit

Permalink
make relative range more precise (#1070)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinBelthle authored Jul 4, 2024
1 parent efb4ea5 commit ee32693
Show file tree
Hide file tree
Showing 27 changed files with 243 additions and 148 deletions.
13 changes: 10 additions & 3 deletions docs/castor/linear-problem/core-problem-filler.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
| 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[^1] | Range upper bound[^1] |
| 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$ |

[^1]: Range actions' lower & upper bounds are computed using CRAC + network + previous RAO results, depending on the
[^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
information [here](/input-data/crac/json.md#range-actions))

Expand All @@ -50,7 +50,7 @@ with $s$ the state on $c$ which is evaluated

<br>

### Definition of the absolute setpoint variations of the RangeActions
### Definition of the setpoint variations of the RangeActions

$$
\begin{equation}
Expand All @@ -67,9 +67,16 @@ $$
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)$

This equation always applies, except for PSTs when modeling them as [APPROXIMATED_INTEGERS](/parameters.md#pst-model).
If so, this constraint will be modeled directly via PST taps, see [here](/castor/linear-problem/discrete-pst-tap-filler.md#rangeactions-relative-tap-variations) as it gives better results [^3].

<br>

[^3]: Relative bounds are originally in tap.
When converting them in angle, we take the smallest angle step between two tap changes.
Despite artificially tightening the bounds, this is the only way to ensure we respect the tap limits as the tap to angle map is non linear.
With PST modeled as APPROXIMATED_INTEGERS, we can directly use the taps and therefore avoid this approximation.

### Shrinking the allowed range

If parameter [ra-range-shrinking](/parameters.md#ra-range-shrinking) is enabled, the allowed range for range actions
Expand Down
29 changes: 20 additions & 9 deletions docs/castor/linear-problem/discrete-pst-tap-filler.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

## Used input data

| Name | Symbol | Details |
|----------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|
| PstRangeActions | $r \in \mathcal{RA}^{PST}$ | Set of PST RangeActions |
| reference angle | $\alpha _n(r)$ | angle of PstRangeAction $r$ at the beginning of the current iteration of the MILP |
| reference tap position | $t_{n}(r)$ | tap of PstRangeAction $r$ at the beginning of the current iteration of the MILP |
| PstRangeAction angle bounds | $\underline{\alpha(r)} \: , \: \overline{\alpha(r)}$ | min and max angle[^1] of PstRangeAction $r$ |
| PstRangeAction tap bounds | $\underline{t(r)} \: , \: \overline{t(r)}$ | min and max tap[^1] of PstRangeAction $r$ |
| tap-to-angle conversion function | $f_r(t) = \alpha$ | Discrete function $f$, which gives, for a given tap of the PstRangeAction $r$, its associated angle value |
| Name | Symbol | Details |
|----------------------------------|-----------------------------------|-----------------------------------------------------------------------------------------------------------|
| PstRangeActions | $r \in \mathcal{RA}^{PST}$ | Set of PST RangeActions |
| reference angle | $\alpha _n(r)$ | angle of PstRangeAction $r$ at the beginning of the current iteration of the MILP |
| reference tap position | $t_{n}(r)$ | tap of PstRangeAction $r$ at the beginning of the current iteration of the MILP |
| PstRangeAction tap bounds | $t^-(r) \: , \: t^+(r)$ | min and max tap[^1] of PstRangeAction $r$ |
| tap-to-angle conversion function | $f_r(t) = \alpha$ | Discrete function $f$, which gives, for a given tap of the PstRangeAction $r$, its associated angle value |

[^1]: PST 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
Expand Down Expand Up @@ -105,4 +104,16 @@ $$
\begin{equation}
\delta ^{+} (r) + \delta ^{-} (r) \leq 1 , \forall r \in \mathcal{RA}^{PST}
\end{equation}
$$
$$

<br>

### RangeActions relative tap variations

$$
\begin{equation}
t^-(r) \leq \Delta t^+(r, s) + \Delta t^-(r, s) - (\Delta t^+(r, s') + \Delta t^-(r, s')) \leq t^+(r)
\end{equation}
$$

with $\Delta t(r,s')$ the setpoint of the last range action on the same element as $r$ but a state preceding $s$.
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,15 @@ private BestTapFinder() {
* 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.
*
* @return a map containing the best tap position for every PstRangeAction that was optimized in the linear problem
*/
public static RangeActionActivationResult round(RangeActionActivationResult linearProblemResult,
public static RangeActionActivationResultImpl round(RangeActionActivationResult linearProblemResult,
Network network,
OptimizationPerimeter optimizationContext,
RangeActionSetpointResult prePerimeterSetpoint,
LinearOptimizationResult linearOptimizationResult,
Unit unit) {

RangeActionActivationResultImpl roundedResult = new RangeActionActivationResultImpl(prePerimeterSetpoint);
findBestTapOfPstRangeActions(linearProblemResult, network, optimizationContext, linearOptimizationResult, roundedResult, unit);
roundOtherRa(linearProblemResult, optimizationContext, roundedResult);
return roundedResult;
}

Expand All @@ -66,7 +63,6 @@ private static void findBestTapOfPstRangeActions(RangeActionActivationResult lin
LinearOptimizationResult linearOptimizationResult,
RangeActionActivationResultImpl roundedResult,
Unit unit) {

for (State state : optimizationContext.getRangeActionOptimizationStates()) {

Map<PstRangeAction, Map<Integer, Double>> minMarginPerTap = new HashMap<>();
Expand All @@ -82,10 +78,10 @@ private static void findBestTapOfPstRangeActions(RangeActionActivationResult lin
if (rangeAction instanceof PstRangeAction pstRangeAction && linearProblemResult.getActivatedRangeActions(state).contains(rangeAction)) {
Optional<String> optGroupId = pstRangeAction.getGroupId();
if (optGroupId.isPresent()) {
roundedResult.activate(pstRangeAction, state, pstRangeAction.convertTapToAngle(bestTapPerPstGroup.get(optGroupId.get())));
roundedResult.putResult(pstRangeAction, state, pstRangeAction.convertTapToAngle(bestTapPerPstGroup.get(optGroupId.get())));
} else {
int bestTap = minMarginPerTap.get(pstRangeAction).entrySet().stream().max(Comparator.comparing(Map.Entry<Integer, Double>::getValue)).orElseThrow().getKey();
roundedResult.activate(pstRangeAction, state, pstRangeAction.convertTapToAngle(bestTap));
roundedResult.putResult(pstRangeAction, state, pstRangeAction.convertTapToAngle(bestTap));
}
}
}
Expand Down Expand Up @@ -248,14 +244,4 @@ static Pair<Double, Double> computeMinMargins(Network network,
}
return Pair.of(minMargin1, minMargin2);
}

private static void roundOtherRa(RangeActionActivationResult linearProblemResult,
OptimizationPerimeter optimizationContext,
RangeActionActivationResultImpl roundedResult) {

optimizationContext.getRangeActionsPerState().forEach((state, rangeActions) -> rangeActions.stream()
.filter(ra -> !(ra instanceof PstRangeAction))
.filter(ra -> linearProblemResult.getActivatedRangeActions(state).contains(ra))
.forEach(ra -> roundedResult.activate(ra, state, Math.round(linearProblemResult.getOptimizedSetpoint(ra, state)))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

package com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms;

import com.powsybl.openrao.data.cracapi.Instant;
import com.powsybl.openrao.data.cracapi.rangeaction.PstRangeAction;
import com.powsybl.openrao.data.raoresultapi.ComputationStatus;
import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters;
import com.powsybl.openrao.searchtreerao.commons.SensitivityComputer;
Expand All @@ -20,6 +20,7 @@
import com.powsybl.openrao.searchtreerao.result.api.*;
import com.powsybl.openrao.searchtreerao.result.impl.IteratingLinearOptimizationResultImpl;
import com.powsybl.openrao.searchtreerao.result.impl.LinearProblemResult;
import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl;
import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions;
import com.powsybl.iidm.network.Network;
import org.apache.commons.lang3.tuple.Pair;
Expand All @@ -37,7 +38,7 @@ private IteratingLinearOptimizer() {

}

public static LinearOptimizationResult optimize(IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters, Instant outageInstant) {
public static LinearOptimizationResult optimize(IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) {

IteratingLinearOptimizationResultImpl bestResult = createResult(
input.getPreOptimizationFlowResult(),
Expand Down Expand Up @@ -218,17 +219,6 @@ private static IteratingLinearOptimizationResultImpl createResult(FlowResult flo
objectiveFunction.evaluate(flowResult, rangeActionActivation, sensitivityResult, sensitivityResult.getSensitivityStatus()), sensitivityResult);
}

private static RangeActionActivationResult roundResult(RangeActionActivationResult linearProblemResult, IteratingLinearOptimizationResultImpl previousResult, IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) {
return BestTapFinder.round(
linearProblemResult,
input.getNetwork(),
input.getOptimizationPerimeter(),
input.getPrePerimeterSetpoints(),
previousResult,
parameters.getObjectiveFunctionUnit()
);
}

private static Pair<IteratingLinearOptimizationResultImpl, Boolean> updateBestResultAndCheckStopCondition(boolean raRangeShrinking, LinearProblem linearProblem, IteratingLinearOptimizerInput input, int iteration, IteratingLinearOptimizationResultImpl currentResult, IteratingLinearOptimizationResultImpl bestResult) {
if (currentResult.getCost() < bestResult.getCost()) {
logBetterResult(iteration, currentResult);
Expand All @@ -243,6 +233,39 @@ private static Pair<IteratingLinearOptimizationResultImpl, Boolean> updateBestRe
return Pair.of(bestResult, !raRangeShrinking);
}

private static RangeActionActivationResult roundResult(RangeActionActivationResult linearProblemResult, IteratingLinearOptimizationResultImpl previousResult, IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) {
RangeActionActivationResultImpl roundedResult = roundPsts(linearProblemResult, previousResult, input, parameters);
roundOtherRas(linearProblemResult, input.getOptimizationPerimeter(), roundedResult);
return roundedResult;
}

private static RangeActionActivationResultImpl roundPsts(RangeActionActivationResult linearProblemResult, IteratingLinearOptimizationResultImpl previousResult, IteratingLinearOptimizerInput input, IteratingLinearOptimizerParameters parameters) {
if (parameters.getRangeActionParameters().getPstModel().equals(RangeActionsOptimizationParameters.PstModel.CONTINUOUS)) {
return BestTapFinder.round(
linearProblemResult,
input.getNetwork(),
input.getOptimizationPerimeter(),
input.getPrePerimeterSetpoints(),
previousResult,
parameters.getObjectiveFunctionUnit()
);
}
RangeActionActivationResultImpl roundedResult = new RangeActionActivationResultImpl(input.getPrePerimeterSetpoints());
input.getOptimizationPerimeter().getRangeActionOptimizationStates().forEach(state -> linearProblemResult.getActivatedRangeActions(state)
.stream().filter(PstRangeAction.class::isInstance).map(PstRangeAction.class::cast)
.forEach(pst -> roundedResult.putResult(pst, state, pst.convertTapToAngle(linearProblemResult.getOptimizedTap(pst, state))))
);
return roundedResult;
}

static void roundOtherRas(RangeActionActivationResult linearProblemResult,
OptimizationPerimeter optimizationContext,
RangeActionActivationResultImpl roundedResult) {
optimizationContext.getRangeActionsPerState().keySet().forEach(state -> linearProblemResult.getActivatedRangeActions(state).stream()
.filter(ra -> !(ra instanceof PstRangeAction))
.forEach(ra -> roundedResult.putResult(ra, state, Math.round(linearProblemResult.getOptimizedSetpoint(ra, state)))));
}

private static void logBetterResult(int iteration, ObjectiveFunctionResult currentObjectiveFunctionResult) {
TECHNICAL_LOGS.info(
"Iteration {}: better solution found with a cost of {} (functional: {})",
Expand Down
Loading

0 comments on commit ee32693

Please sign in to comment.