AppliedRemedialActions.java
/*
* Copyright (c) 2021, 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.sensitivityanalysis;
import com.powsybl.openrao.commons.OpenRaoException;
import com.powsybl.openrao.data.crac.api.State;
import com.powsybl.openrao.data.crac.api.networkaction.NetworkAction;
import com.powsybl.openrao.data.crac.api.rangeaction.RangeAction;
import com.powsybl.iidm.network.Network;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Baptiste Seguinot {@literal <baptiste.seguinot at rte-france.com>}
*/
public class AppliedRemedialActions {
private final Map<State, AppliedRemedialActionsPerState> appliedRa = new HashMap<>();
private static class AppliedRemedialActionsPerState {
private final Set<NetworkAction> networkActions = new HashSet<>();
private final Map<RangeAction<?>, Double> rangeActions = new HashMap<>();
}
public void addAppliedNetworkAction(State state, NetworkAction networkAction) {
if (networkAction != null) {
checkState(state);
appliedRa.get(state).networkActions.add(networkAction);
}
}
public void addAppliedNetworkActions(State state, Set<NetworkAction> networkActions) {
if (!networkActions.isEmpty()) {
checkState(state);
appliedRa.get(state).networkActions.addAll(networkActions);
}
}
public void addAppliedRangeAction(State state, RangeAction<?> rangeAction, double setpoint) {
if (rangeAction != null) {
checkState(state);
appliedRa.get(state).rangeActions.put(rangeAction, setpoint);
}
}
public void addAppliedRangeActions(State state, Map<RangeAction<?>, Double> rangeActions) {
if (!rangeActions.isEmpty()) {
checkState(state);
appliedRa.get(state).rangeActions.putAll(rangeActions);
}
}
public boolean isEmpty(Network network) {
return getStatesWithRa(network).isEmpty();
}
public Set<State> getStatesWithRa(Network network) {
// state with at least one network action applied
// or state with at least one range action whose setpoint is different from the one in the network
return appliedRa.entrySet().stream()
.filter(stateE -> !stateE.getValue().networkActions.isEmpty() || stateE.getValue().rangeActions.entrySet().stream()
.anyMatch(raE -> Math.abs(raE.getKey().getCurrentSetpoint(network) - raE.getValue()) > 1e-6))
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
}
public Set<NetworkAction> getAppliedNetworkActions(State state) {
if (appliedRa.containsKey(state)) {
return appliedRa.get(state).networkActions;
} else {
return new HashSet<>();
}
}
public Map<RangeAction<?>, Double> getAppliedRangeActions(State state) {
if (appliedRa.containsKey(state)) {
return appliedRa.get(state).rangeActions;
} else {
return new HashMap<>();
}
}
public void applyOnNetwork(State state, Network network) {
// Apply remedial actions from all states before or equal to given state
appliedRa.keySet().stream().filter(stateBefore ->
(stateBefore.getInstant().comesBefore(state.getInstant()) || stateBefore.getInstant().equals(state.getInstant()))
&& (stateBefore.getContingency().isEmpty() || stateBefore.getContingency().equals(state.getContingency())))
.sorted(Comparator.comparingInt(stateBefore -> stateBefore.getInstant().getOrder()))
.forEach(stateBefore -> {
appliedRa.get(stateBefore).rangeActions.forEach((rangeAction, setPoint) -> rangeAction.apply(network, setPoint));
appliedRa.get(stateBefore).networkActions.forEach(networkAction -> networkAction.apply(network));
});
}
public AppliedRemedialActions copy() {
AppliedRemedialActions ara = new AppliedRemedialActions();
appliedRa.forEach((state, appliedRaOnState) -> {
ara.addAppliedNetworkActions(state, appliedRaOnState.networkActions);
ara.addAppliedRangeActions(state, appliedRaOnState.rangeActions);
});
return ara;
}
public AppliedRemedialActions copyNetworkActionsAndAutomaticRangeActions() {
AppliedRemedialActions ara = new AppliedRemedialActions();
appliedRa.forEach((state, appliedRaOnState) -> ara.addAppliedNetworkActions(state, appliedRaOnState.networkActions));
appliedRa.forEach((state, appliedRaOnState) -> {
if (state.getInstant().isAuto()) {
ara.addAppliedRangeActions(state, appliedRaOnState.rangeActions);
}
});
return ara;
}
private void checkState(State state) {
if (!state.getInstant().isCurative() && !state.getInstant().isAuto()) {
throw new OpenRaoException("Sensitivity analysis with applied remedial actions only work with CURATIVE and AUTO remedial actions.");
}
appliedRa.putIfAbsent(state, new AppliedRemedialActionsPerState());
}
public AppliedRemedialActions copyCurative() {
Map<State, AppliedRemedialActionsPerState> curativeMap = appliedRa.entrySet().stream().filter(entry -> entry.getKey().getInstant().isCurative())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
AppliedRemedialActions ara = new AppliedRemedialActions();
curativeMap.forEach((state, appliedRaOnState) -> {
ara.addAppliedNetworkActions(state, appliedRaOnState.networkActions);
ara.addAppliedRangeActions(state, appliedRaOnState.rangeActions);
});
return ara;
}
}