Skip to content

Commit

Permalink
Decrease remedial action usage limits among consecutive instants of t…
Browse files Browse the repository at this point in the history
…he same kind (#904)

Decrease remedial action usage limits among consecutive instants of the same kind

---------

Signed-off-by: Thomas Bouquet <[email protected]>
Signed-off-by: belthlemar <[email protected]>
  • Loading branch information
bqth29 authored and MartinBelthle committed May 28, 2024
1 parent 4df8b96 commit 6db3e9e
Show file tree
Hide file tree
Showing 10 changed files with 868 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class RaUsageLimits {
private static final Map<String, Integer> DEFAULT_MAX_RA_PER_TSO = new HashMap<>();
private int maxRa = DEFAULT_MAX_RA;
private int maxTso = DEFAULT_MAX_TSO;
private final Set<String> maxTsoExclusion = new HashSet<>();
private Map<String, Integer> maxTopoPerTso = DEFAULT_MAX_TOPO_PER_TSO;
private Map<String, Integer> maxPstPerTso = DEFAULT_MAX_PST_PER_TSO;
private Map<String, Integer> maxRaPerTso = DEFAULT_MAX_RA_PER_TSO;
Expand Down Expand Up @@ -96,6 +97,10 @@ public Map<String, Integer> getMaxRaPerTso() {
return maxRaPerTso;
}

public Set<String> getMaxTsoExclusion() {
return maxTsoExclusion;
}

private Map<String, Integer> replaceNegativeValues(Map<String, Integer> limitsPerTso) {
limitsPerTso.forEach((tso, limit) -> {
if (limit < 0) {
Expand Down Expand Up @@ -123,6 +128,10 @@ private static void crossCheckMaxCraPerTsoParameters(Map<String, Integer> maxRaP
});
}

public void addTsoToExclude(String tso) {
maxTsoExclusion.add(tso);
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
18 changes: 18 additions & 0 deletions docs/input-data/crac/json.md
Original file line number Diff line number Diff line change
Expand Up @@ -1346,3 +1346,21 @@ crac.newRaUsageLimits("curative")
:::
::::

If several instants of the same kind are defined in the CRAC, the usage limits are **cumulative** among these instants.

For instance, let us consider a CRAC with 3 curative instants and the following usage limits:

```json
"ra-usage-limits-per-instant" : [ {
"instant": "curative 1",
"max-ra" : 1,
}, {
"instant": "curative 2",
"max-ra" : 3,
}, {
"instant": "curative 3",
"max-ra" : 7,
} ]
```

The maximum number of applicable remedial actions defined for the second curative instant (3) is a cumulated value that includes the maximum number of applicable remedial actions during the first curative instant (1). Thus, if 1 remedial action was applied during the first curative instant, only 2 remedial actions can actually be applied during the second curative instant. Likewise, the maximum number of remedial actions for the third curative instant includes the remedial actions applied at curative 1 and 2 instants. Depending on the number of previously applied remedial actions, the number of actually applicable remedial actions during the third curative instant can vary between 4 and 7.
Original file line number Diff line number Diff line change
Expand Up @@ -362,19 +362,23 @@ private Object runScenario(Crac crac, RaoParameters raoParameters, StateTree sta
} else if (!automatonsOnly) {
boolean allPreviousPerimetersSucceded = true;
PrePerimeterResult previousPerimeterResult = preCurativeResult;
// Optimize curative instant
// Optimize curative perimeters
Map<State, OptimizationResult> resultsPerPerimeter = new HashMap<>();
for (Perimeter curativePerimeter : optimizedScenario.getCurativePerimeters()) {
State curativeState = curativePerimeter.getRaOptimisationState();
if (previousPerimeterResult == null) {
previousPerimeterResult = getPreCurativePerimeterSensitivityAnalysis(crac, curativePerimeter, toolProvider).runBasedOnInitialResults(networkClone, raoInput.getCrac(), previousPerimeterResult, previousPerimeterResult, stateTree.getOperatorsNotSharingCras(), null);
}
if (allPreviousPerimetersSucceded) {
OptimizationResult curativeResult = optimizeCurativePerimeter(curativePerimeter, crac, networkClone,
raoParameters, stateTree, toolProvider, curativeTreeParameters, initialSensitivityOutput, previousPerimeterResult);
raoParameters, stateTree, toolProvider, curativeTreeParameters, initialSensitivityOutput, previousPerimeterResult, resultsPerPerimeter);
allPreviousPerimetersSucceded = curativeResult.getSensitivityStatus() == DEFAULT;
contingencyScenarioResults.put(curativeState, curativeResult);
applyRemedialActions(networkClone, curativeResult, curativeState);
previousPerimeterResult = null;
if (allPreviousPerimetersSucceded) {
resultsPerPerimeter.put(curativePerimeter.getRaOptimisationState(), curativeResult);
}
} else {
contingencyScenarioResults.put(curativeState, new SkippedOptimizationResultImpl(curativeState, new HashSet<>(), new HashSet<>(), ComputationStatus.FAILURE, sensitivityFailureOvercost));
}
Expand Down Expand Up @@ -402,7 +406,8 @@ private OptimizationResult optimizeCurativePerimeter(Perimeter curativePerimeter
ToolProvider toolProvider,
TreeParameters curativeTreeParameters,
PrePerimeterResult initialSensitivityOutput,
PrePerimeterResult prePerimeterSensitivityOutput) {
PrePerimeterResult prePerimeterSensitivityOutput,
Map<State, OptimizationResult> resultsPerPerimeter) {
State curativeState = curativePerimeter.getRaOptimisationState();
TECHNICAL_LOGS.info("Optimizing curative state {}.", curativeState.getId());

Expand All @@ -414,6 +419,8 @@ private OptimizationResult optimizeCurativePerimeter(Perimeter curativePerimeter
.withUnoptimizedCnecParameters(UnoptimizedCnecParameters.build(raoParameters.getNotOptimizedCnecsParameters(), stateTree.getOperatorsNotSharingCras(), raoInput.getCrac()))
.build();

searchTreeParameters.decreaseRemedialActionUsageLimits(resultsPerPerimeter);

SearchTreeInput searchTreeInput = SearchTreeInput.create()
.withNetwork(network)
.withOptimizationPerimeter(optPerimeter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.powsybl.openrao.data.cracapi.Crac;
import com.powsybl.openrao.data.cracapi.Instant;
import com.powsybl.openrao.data.cracapi.RaUsageLimits;
import com.powsybl.openrao.data.cracapi.State;
import com.powsybl.openrao.data.cracapi.rangeaction.RangeAction;
import com.powsybl.openrao.raoapi.parameters.ObjectiveFunctionParameters;
import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters;
Expand All @@ -17,7 +18,9 @@
import com.powsybl.openrao.raoapi.parameters.extensions.MnecParametersExtension;
import com.powsybl.openrao.raoapi.parameters.extensions.RelativeMarginsParametersExtension;
import com.powsybl.openrao.searchtreerao.commons.parameters.*;
import com.powsybl.openrao.searchtreerao.result.api.OptimizationResult;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
Expand All @@ -32,7 +35,7 @@ public class SearchTreeParameters {
// required for the search tree algorithm
private final TreeParameters treeParameters;
private final NetworkActionParameters networkActionParameters;
private Map<Instant, RaUsageLimits> raLimitationParameters;
private final Map<Instant, RaUsageLimits> raLimitationParameters;

// required for sub-module iterating linear optimizer
private final RangeActionsOptimizationParameters rangeActionParameters;
Expand Down Expand Up @@ -134,6 +137,63 @@ public void setRaLimitationsForSecondPreventive(RaUsageLimits raUsageLimits, Set
this.raLimitationParameters.put(preventiveInstant, raUsageLimits);
}

public void decreaseRemedialActionUsageLimits(Map<State, OptimizationResult> resultsPerOptimizationState) {
resultsPerOptimizationState.forEach((optimizedState, result) ->
raLimitationParameters.keySet().forEach(
otherInstant -> {
// Cumulative behaviour of constraints only applies to instants of the same kind
if (!otherInstant.comesBefore(optimizedState.getInstant()) && optimizedState.getInstant().getKind().equals(otherInstant.getKind())) {
RaUsageLimits raUsageLimits = raLimitationParameters.get(otherInstant);
int decreasedMaxRa = decreaseMaxRemedialAction(raUsageLimits, optimizedState, result);
Map<String, Integer> decreasedMaxRaPerTso = decreaseMaxRemedialActionPerTso(raUsageLimits, optimizedState, result);
Map<String, Integer> decreasedMaxTopoPerTso = decreaseMaxTopoPerTso(raUsageLimits, result, decreasedMaxRaPerTso);
Map<String, Integer> decreasedMaxPstPerTso = decreaseMaxPstPerTso(raUsageLimits, optimizedState, result, decreasedMaxRaPerTso);
int decreasedMaxTso = decreaseMaxTso(raUsageLimits, optimizedState, result);

RaUsageLimits decreasedRaUsageLimits = new RaUsageLimits();
decreasedRaUsageLimits.setMaxRa(decreasedMaxRa);
decreasedRaUsageLimits.setMaxRaPerTso(decreasedMaxRaPerTso);
decreasedRaUsageLimits.setMaxTopoPerTso(decreasedMaxTopoPerTso);
decreasedRaUsageLimits.setMaxPstPerTso(decreasedMaxPstPerTso);
raUsageLimits.getMaxTsoExclusion().forEach(decreasedRaUsageLimits::addTsoToExclude);
decreasedRaUsageLimits.setMaxTso(decreasedMaxTso);

raLimitationParameters.put(otherInstant, decreasedRaUsageLimits);
}
}
)
);
}

private static int decreaseMaxRemedialAction(RaUsageLimits raUsageLimits, State optimizedState, OptimizationResult result) {
return raUsageLimits.getMaxRa() - result.getActivatedNetworkActions().size() - result.getActivatedRangeActions(optimizedState).size();
}

private static Map<String, Integer> decreaseMaxTopoPerTso(RaUsageLimits raUsageLimits, OptimizationResult result, Map<String, Integer> decreasedMaxRaPerTso) {
Map<String, Integer> decreasedMaxTopoPerTso = new HashMap<>();
raUsageLimits.getMaxTopoPerTso().forEach((key, value) -> decreasedMaxTopoPerTso.put(key, Math.min(value - (int) result.getActivatedNetworkActions().stream().filter(networkAction -> key.equals(networkAction.getOperator())).count(), decreasedMaxRaPerTso.get(key))));
return decreasedMaxTopoPerTso;
}

private static Map<String, Integer> decreaseMaxPstPerTso(RaUsageLimits raUsageLimits, State optimizedState, OptimizationResult result, Map<String, Integer> decreasedMaxRaPerTso) {
Map<String, Integer> decreasedMaxPstPerTso = new HashMap<>();
raUsageLimits.getMaxPstPerTso().forEach((key, value) -> decreasedMaxPstPerTso.put(key, Math.min(value - (int) result.getActivatedRangeActions(optimizedState).stream().filter(networkAction -> key.equals(networkAction.getOperator())).count(), decreasedMaxRaPerTso.get(key))));
return decreasedMaxPstPerTso;
}

private static Map<String, Integer> decreaseMaxRemedialActionPerTso(RaUsageLimits raUsageLimits, State optimizedState, OptimizationResult result) {
Map<String, Integer> decreasedMaxRaPerTso = new HashMap<>();
raUsageLimits.getMaxRaPerTso().forEach((key, value) -> decreasedMaxRaPerTso.put(key, value - (int) result.getActivatedNetworkActions().stream().filter(networkAction -> key.equals(networkAction.getOperator())).count() - (int) result.getActivatedRangeActions(optimizedState).stream().filter(networkAction -> key.equals(networkAction.getOperator())).count()));
return decreasedMaxRaPerTso;
}

private static int decreaseMaxTso(RaUsageLimits raUsageLimits, State optimizedState, OptimizationResult result) {
int tsosWithPreviouslyAppliedRas = raUsageLimits.getMaxTsoExclusion().size();
result.getActivatedNetworkActions().forEach(networkAction -> raUsageLimits.addTsoToExclude(networkAction.getOperator()));
result.getActivatedRangeActions(optimizedState).forEach(rangeAction -> raUsageLimits.addTsoToExclude(rangeAction.getOperator()));
return raUsageLimits.getMaxTso() - (raUsageLimits.getMaxTsoExclusion().size() - tsosWithPreviouslyAppliedRas);
}

public static SearchTreeParametersBuilder create() {
return new SearchTreeParametersBuilder();
}
Expand Down Expand Up @@ -180,7 +240,7 @@ public SearchTreeParametersBuilder withNetworkActionParameters(NetworkActionPara
}

public SearchTreeParametersBuilder withGlobalRemedialActionLimitationParameters(Map<Instant, RaUsageLimits> raLimitationParameters) {
this.raLimitationParameters = raLimitationParameters;
this.raLimitationParameters = new HashMap<>(raLimitationParameters);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
import org.mockito.Mockito;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -918,6 +920,45 @@ void optimizationWithAutoSearchTreeAndAutoPsts() {
assertEquals(-131.0, raoResult.getFlow(crac.getInstant("curative"), crac.getFlowCnec("NNL2AA1 BBE3AA1 1 - Contingency DE2 NL3 1 - curative"), Side.LEFT, Unit.MEGAWATT), 1.);
}

@Test
void threeCurativeInstantsWithCumulativeMaximumNumberOfApplicableRemedialActions() {
Network network = Network.read("12Nodes_4ParallelLines.uct", getClass().getResourceAsStream("/network/12Nodes_4ParallelLines.uct"));
Crac crac = CracImporters.importCrac(
Paths.get(new File(Objects.requireNonNull(CastorFullOptimizationTest.class.getResource("/crac/small-crac-ra-limits-per-instant.json")).getFile()).toString()),
network
);

RaoInput raoInput = RaoInput.build(network, crac).build();
RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/parameters/RaoParameters_DC.json"));

RaoResult raoResult = new CastorFullOptimization(raoInput, raoParameters, null).run().join();

// SearchTree stop criterion is MIN_OBJECTIVE so all 3 remedial actions should be applied during the first curative instant
// Yet, the number of RAs that can be applied is restricted to 1 (resp. 2) in total for curative1 (resp. curative2)
assertEquals(1, raoResult.getActivatedNetworkActionsDuringState(crac.getState("contingency", crac.getInstant("curative1"))).size());
assertEquals(1, raoResult.getActivatedNetworkActionsDuringState(crac.getState("contingency", crac.getInstant("curative2"))).size());
}

@Test
void threeCurativeInstantsWithCumulativeMaximumNumberOfTsos() {
Network network = Network.read("12Nodes_4ParallelLines.uct", getClass().getResourceAsStream("/network/12Nodes_4ParallelLines.uct"));
Crac crac = CracImporters.importCrac(
Paths.get(new File(Objects.requireNonNull(CastorFullOptimizationTest.class.getResource("/crac/small-crac-ra-limits-per-instant-3-tsos.json")).getFile()).toString()),
network
);

RaoInput raoInput = RaoInput.build(network, crac).build();
RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/parameters/RaoParameters_DC.json"));

RaoResult raoResult = new CastorFullOptimization(raoInput, raoParameters, null).run().join();

// SearchTree stop criterion is MIN_OBJECTIVE so all 3 remedial actions should be applied during the first curative instant
// Yet, the number of RAs that can be applied is restricted to 2 (resp. 1) in total for curative1 (resp. curative2)
assertEquals(2, raoResult.getActivatedNetworkActionsDuringState(crac.getState("contingency", crac.getInstant("curative1"))).size());
assertEquals(0, raoResult.getActivatedNetworkActionsDuringState(crac.getState("contingency", crac.getInstant("curative2"))).size());
assertEquals(1, raoResult.getActivatedNetworkActionsDuringState(crac.getState("contingency", crac.getInstant("curative3"))).size());
}

@Test
void curativeOptimizationShouldNotBeDoneIfPreventiveUnsecure() {
Network network = Network.read("small-network-2P.uct", getClass().getResourceAsStream("/network/small-network-2P.uct"));
Expand Down
Loading

0 comments on commit 6db3e9e

Please sign in to comment.