Skip to content

Commit

Permalink
resolve comments
Browse files Browse the repository at this point in the history
Signed-off-by: belthlemar <[email protected]>
  • Loading branch information
MartinBelthle committed Mar 26, 2024
1 parent 16c3760 commit 5d44be0
Show file tree
Hide file tree
Showing 3 changed files with 538 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.powsybl.openrao.commons.RandomizedString;
import com.powsybl.openrao.data.cracapi.*;
import com.powsybl.openrao.data.cracapi.cnec.FlowCnec;
import com.powsybl.openrao.data.cracapi.networkaction.NetworkAction;
import com.powsybl.openrao.data.cracapi.rangeaction.PstRangeAction;
import com.powsybl.openrao.data.cracapi.rangeaction.RangeAction;
import com.powsybl.openrao.data.cracapi.rangeaction.StandardRangeAction;
Expand Down Expand Up @@ -742,9 +743,9 @@ static void applyPreventiveResultsForAutoOrCurativeRangeActions(Network network,
* For the same reason, we are going to check preventive RAs that share the same network elements as auto or curative RAs.
*/
static Set<RangeAction<?>> getRangeActionsExcludedFromSecondPreventive(Crac crac, PerimeterResult firstPreventiveResult, Map<State, OptimizationResult> contingencyResults) {
Set<RangeAction<?>> multipleInstantRangeActions = crac.getRangeActions().stream().filter(ra ->
isRangeActionPreventive(ra, crac)
&& isRangeActionAutoOrCurative(ra, crac)).collect(Collectors.toSet());
Set<RangeAction<?>> multipleInstantRangeActions = crac.getRangeActions().stream()
.filter(ra -> isRangeActionPreventive(ra, crac) && isRangeActionAutoOrCurative(ra, crac))
.collect(Collectors.toSet());

// If first preventive diverged, we want to remove every range action that is both preventive and auto or curative.
if (firstPreventiveResult instanceof SkippedOptimizationResultImpl) {
Expand All @@ -753,13 +754,14 @@ static Set<RangeAction<?>> getRangeActionsExcludedFromSecondPreventive(Crac crac

// Removes range actions that have a range limit relative to the previous instant.
Set<RangeAction<?>> rangeActionsToRemove = multipleInstantRangeActions.stream()
.filter(ra -> {
if (ra instanceof PstRangeAction pstRangeAction) {
return pstRangeAction.getRanges().stream().anyMatch(tapRange -> tapRange.getRangeType().equals(RELATIVE_TO_PREVIOUS_INSTANT));
}
return ((StandardRangeAction<?>) ra).getRanges().stream().anyMatch(standardRange -> standardRange.getRangeType().equals(RELATIVE_TO_PREVIOUS_INSTANT));
})
.collect(Collectors.toSet());
.filter(ra -> {
if (ra instanceof PstRangeAction pstRangeAction) {
return pstRangeAction.getRanges().stream().anyMatch(tapRange -> tapRange.getRangeType().equals(RELATIVE_TO_PREVIOUS_INSTANT));
}
return ((StandardRangeAction<?>) ra).getRanges().stream().anyMatch(standardRange -> standardRange.getRangeType().equals(RELATIVE_TO_PREVIOUS_INSTANT));
})
.collect(Collectors.toSet());
rangeActionsToRemove.forEach(multipleInstantRangeActions::remove);

// Removes RAs that put crac RaUsageLimits at risk.
// First, we filter out state that diverged because we know no set-point was chosen for this state.
Expand All @@ -769,80 +771,91 @@ static Set<RangeAction<?>> getRangeActionsExcludedFromSecondPreventive(Crac crac
// Then, we build a map that gives for each RA, its tap at each state it's available at.
Set<RangeAction<?>> rangeActionsNotPreventive = crac.getRangeActions().stream().filter(ra -> isRangeActionAutoOrCurative(ra, crac)).collect(Collectors.toSet());
State preventiveState = crac.getPreventiveState();
rangeActionsToRemove.forEach(multipleInstantRangeActions::remove);
Map<RangeAction<?>, Map<State, Set<Double>>> setPointResults = buildSetPointResultsMap(crac, firstPreventiveResult, newContingencyResults, multipleInstantRangeActions, rangeActionsNotPreventive, preventiveState);
Map<RangeAction<?>, Map<State, Double>> setPointResults = buildSetPointResultsMap(crac, firstPreventiveResult, newContingencyResults, multipleInstantRangeActions, rangeActionsNotPreventive, preventiveState);

// Finally, we filter out RAs that put crac RaUsageLimits at risk.
rangeActionsToRemove.addAll(getRangeActionsToRemove(crac, preventiveState, setPointResults));
rangeActionsToRemove.addAll(getRangeActionsToRemove(crac, preventiveState, setPointResults, newContingencyResults));
return rangeActionsToRemove;
}

/**
* Creates a map that gives for a given RA, its tap for each state it's available at.
* The only subtlety being that RAs sharing exactly the same network elements are considered to be only one RA.
*/
private static Map<RangeAction<?>, Map<State, Set<Double>>> buildSetPointResultsMap(Crac crac, PerimeterResult firstPreventiveResult, Map<State, OptimizationResult> contingencyResults, Set<RangeAction<?>> multipleInstantRangeActions, Set<RangeAction<?>> rangeActionsNotPreventive, State preventiveState) {
private static Map<RangeAction<?>, Map<State, Double>> buildSetPointResultsMap(Crac crac, PerimeterResult firstPreventiveResult, Map<State, OptimizationResult> contingencyResults, Set<RangeAction<?>> multipleInstantRangeActions, Set<RangeAction<?>> rangeActionsNotPreventive, State preventiveState) {
Map<RangeAction<?>, Set<RangeAction<?>>> correspondanceMap = new HashMap<>();
crac.getRangeActions().stream().filter(ra -> isRangeActionPreventive(ra, crac) && !isRangeActionAutoOrCurative(ra, crac)).forEach(pra -> {
Set<NetworkElement> praNetworkElements = pra.getNetworkElements();
rangeActionsNotPreventive.forEach(cra -> {
if (cra.getNetworkElements().equals(praNetworkElements)) {
correspondanceMap.putIfAbsent(pra, new HashSet<>(Set.of(cra)));
correspondanceMap.putIfAbsent(pra, new HashSet<>());
correspondanceMap.get(pra).add(cra);
}
});
});
Map<RangeAction<?>, Map<State, Set<Double>>> setPointResults = new HashMap<>();
Map<RangeAction<?>, Map<State, Double>> setPointResults = new HashMap<>();
correspondanceMap.forEach((pra, associatedCras) -> {
setPointResults.put(pra, new HashMap<>(Map.of(preventiveState, Set.of(firstPreventiveResult.getOptimizedSetpoint(pra, preventiveState)))));
setPointResults.put(pra, new HashMap<>(Map.of(preventiveState, firstPreventiveResult.getOptimizedSetpoint(pra, preventiveState))));
associatedCras.forEach(cra -> contingencyResults.forEach((state, result) -> {
if (isRangeActionAvailableInState(cra, state, crac)) {
Map<State, Set<Double>> praResults = setPointResults.get(pra);
double craSetPoint = result.getOptimizedSetpoint(cra, state);
praResults.putIfAbsent(state, new HashSet<>(Set.of(craSetPoint)));
praResults.get(state).add(craSetPoint);
setPointResults.get(pra).putIfAbsent(state, result.getOptimizedSetpoint(cra, state));
}
}));
});
multipleInstantRangeActions.forEach(ra -> {
setPointResults.put(ra, new HashMap<>(Map.of(preventiveState, Set.of(firstPreventiveResult.getOptimizedSetpoint(ra, preventiveState)))));
setPointResults.put(ra, new HashMap<>(Map.of(preventiveState, firstPreventiveResult.getOptimizedSetpoint(ra, preventiveState))));
contingencyResults.forEach((state, result) -> {
if (isRangeActionAvailableInState(ra, state, crac)) {
setPointResults.get(ra).put(state, Set.of(result.getOptimizedSetpoint(ra, state)));
setPointResults.get(ra).put(state, result.getOptimizedSetpoint(ra, state));
}
});
});
return setPointResults;
}

/**
* Checks if raUsageLimits are at risk if we choose to re-optimize a range action.
* Returns True if it's at risk, False otherwise.
*/
private static boolean shouldRemoveRaDueToUsageLimits(Crac crac, State state, RangeAction<?> rangeAction, Set<NetworkAction> activatedNetworkActions) {
String operator = rangeAction.getOperator();
RaUsageLimits raUsageLimits = crac.getRaUsageLimits(state.getInstant());
Set<RemedialAction<?>> potentiallyActivatableRas = new HashSet<>(crac.getPotentiallyAvailableRangeActions(state));
potentiallyActivatableRas.addAll(activatedNetworkActions);
long potentiallyActivatableTsos = Integer.MAX_VALUE;
long potentiallyActivatableRasForTheTso = Integer.MAX_VALUE;
if (operator != null) {
potentiallyActivatableRasForTheTso = potentiallyActivatableRas.stream()
.filter(ra -> operator.equals(ra.getOperator()))
.count();
potentiallyActivatableTsos = potentiallyActivatableRas.stream()
.map(RemedialAction::getOperator)
.filter(Objects::nonNull)
.distinct()
.count();
}
int limitingValueForTheTso = Math.min(raUsageLimits.getMaxPstPerTso().getOrDefault(operator, Integer.MAX_VALUE), raUsageLimits.getMaxRaPerTso().getOrDefault(operator, Integer.MAX_VALUE));
return raUsageLimits.getMaxRa() < potentiallyActivatableRas.size()
|| limitingValueForTheTso < potentiallyActivatableRasForTheTso
|| raUsageLimits.getMaxTso() < potentiallyActivatableTsos;
}

/**
* Gathers every range action that should not be considered in the second preventive if those 2 criterion are met :
* 1- The range action has the same tap in preventive and in a contingency scenario.
* 2- For the given state, the crac has limiting RaUsageLimits.
*/
private static Set<RangeAction<?>> getRangeActionsToRemove(Crac crac, State preventiveState, Map<RangeAction<?>, Map<State, Set<Double>>> setPointResults) {
private static Set<RangeAction<?>> getRangeActionsToRemove(Crac crac, State preventiveState, Map<RangeAction<?>, Map<State, Double>> setPointResults, Map<State, OptimizationResult> contingencyResults) {
Set<RangeAction<?>> rangeActionsToRemove = new HashSet<>();
setPointResults.forEach((ra, spMap) -> {
double referenceSetPoint = spMap.get(preventiveState).iterator().next();
for (Map.Entry<State, Set<Double>> entry : spMap.entrySet()) {
double referenceSetPoint = spMap.get(preventiveState);
for (Map.Entry<State, Double> entry : spMap.entrySet()) {
State state = entry.getKey();
if (!state.isPreventive() && entry.getValue().contains(referenceSetPoint)) {
Instant instant = state.getInstant();
if (crac.getRaUsageLimitsPerInstant().containsKey(instant)) {
String operator = ra.getOperator();
RaUsageLimits raUsageLimits = crac.getRaUsageLimits(instant);
Set<RangeAction<?>> potentiallyAvailableRas = crac.getPotentiallyAvailableRangeActions(state);
long potentiallyAvailableRasForTheOperator = operator == null ? Integer.MAX_VALUE : potentiallyAvailableRas.stream().filter(rangeAction -> {
String otherOperator = rangeAction.getOperator();
return otherOperator != null && otherOperator.equals(operator);
}).count();
int limitingValueForTheTso = Math.min(raUsageLimits.getMaxPstPerTso().getOrDefault(operator, Integer.MAX_VALUE), raUsageLimits.getMaxRaPerTso().getOrDefault(operator, Integer.MAX_VALUE));
if (raUsageLimits.getMaxRa() < potentiallyAvailableRas.size() ||
limitingValueForTheTso < potentiallyAvailableRasForTheOperator) {
rangeActionsToRemove.add(ra);
break;
}
}
if (!state.isPreventive()
&& entry.getValue().equals(referenceSetPoint)
&& crac.getRaUsageLimitsPerInstant().containsKey(state.getInstant())
&& shouldRemoveRaDueToUsageLimits(crac, state, ra, contingencyResults.get(state).getActivatedNetworkActions())) {
rangeActionsToRemove.add(ra);
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,22 @@ Feature: US 20.1: enable second optimization of the preventive perimeter
And the tap of PstRangeAction "pst_be" should be 0 in preventive
Then the worst margin is 295.6 A

@fast @rao @mock @ac @second-preventive
Scenario: US 20.1.1.8: Same case as US 20.1.1.3 with curative maxTso limits.
# We should have the same results as 20.1.1.2
Given network file is "common/TestCase16Nodes.uct"
Given crac file is "epic20/second_preventive_ls_1_8.json"
Given configuration file is "epic20/RaoParameters_maxMargin_ampere_second_preventive.json"
When I launch search_tree_rao
# We can not re-optimize pst_fr for 2 combined reasons:
# 1- It has the same taps in preventive and in curative.
# 2- There are maxTso usage limits for curative instant.
Then 2 remedial actions are used in preventive
And the remedial action "open_fr1_fr3" is used in preventive
And the tap of PstRangeAction "pst_fr" should be -5 in preventive
And the tap of PstRangeAction "pst_be" should be 0 in preventive
Then the worst margin is 295.6 A

@fast @rao @mock @ac @second-preventive
Scenario: US 20.1.2: Preventive and curative network actions 1/3
Given network file is "common/TestCase16Nodes.uct"
Expand Down
Loading

0 comments on commit 5d44be0

Please sign in to comment.