NetworkActionParameters.java
/*
* Copyright (c) 2022, 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.commons.parameters;
import com.powsybl.openrao.data.crac.api.Crac;
import com.powsybl.openrao.data.crac.api.networkaction.NetworkAction;
import com.powsybl.openrao.raoapi.parameters.RaoParameters;
import com.powsybl.openrao.raoapi.parameters.TopoOptimizationParameters;
import com.powsybl.openrao.searchtreerao.commons.NetworkActionCombination;
import java.util.*;
import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.BUSINESS_WARNS;
import static com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoTopoOptimizationParameters.*;
/**
* @author Baptiste Seguinot {@literal <baptiste.seguinot at rte-france.com>}
*/
public class NetworkActionParameters {
private final List<NetworkActionCombination> predefinedCombinations;
private final double absoluteNetworkActionMinimumImpactThreshold;
private final double relativeNetworkActionMinimumImpactThreshold;
private final boolean skipNetworkActionFarFromMostLimitingElements;
private final int maxNumberOfBoundariesForSkippingNetworkActions;
public NetworkActionParameters(List<NetworkActionCombination> predefinedCombinations,
double absoluteNetworkActionMinimumImpactThreshold,
double relativeNetworkActionMinimumImpactThreshold,
boolean skipNetworkActionFarFromMostLimitingElements,
int maxNumberOfBoundariesForSkippingNetworkActions) {
this.predefinedCombinations = predefinedCombinations;
this.absoluteNetworkActionMinimumImpactThreshold = absoluteNetworkActionMinimumImpactThreshold;
this.relativeNetworkActionMinimumImpactThreshold = relativeNetworkActionMinimumImpactThreshold;
this.skipNetworkActionFarFromMostLimitingElements = skipNetworkActionFarFromMostLimitingElements;
this.maxNumberOfBoundariesForSkippingNetworkActions = maxNumberOfBoundariesForSkippingNetworkActions;
}
public List<NetworkActionCombination> getNetworkActionCombinations() {
return predefinedCombinations;
}
public double getAbsoluteNetworkActionMinimumImpactThreshold() {
return absoluteNetworkActionMinimumImpactThreshold;
}
public double getRelativeNetworkActionMinimumImpactThreshold() {
return relativeNetworkActionMinimumImpactThreshold;
}
public boolean skipNetworkActionFarFromMostLimitingElements() {
return skipNetworkActionFarFromMostLimitingElements;
}
public int getMaxNumberOfBoundariesForSkippingNetworkActions() {
return maxNumberOfBoundariesForSkippingNetworkActions;
}
public static NetworkActionParameters buildFromRaoParameters(RaoParameters raoParameters, Crac crac) {
TopoOptimizationParameters topoOptimizationParameters = raoParameters.getTopoOptimizationParameters();
return new NetworkActionParameters(computePredefinedCombinations(crac, raoParameters),
topoOptimizationParameters.getAbsoluteMinImpactThreshold(),
topoOptimizationParameters.getRelativeMinImpactThreshold(),
isSkipActionsFarFromMostLimitingElement(raoParameters),
getMaxNumberOfBoundariesForSkippingActions(raoParameters));
}
public void addNetworkActionCombination(NetworkActionCombination networkActionCombination) {
// It may happen that the 1st preventive RAO finds an optimal combination that was already defined
// In this case, remove the old combination and add the new one (marked "detected during RAO")
Optional<NetworkActionCombination> alreadyExistingNetworkActionCombination = this.predefinedCombinations
.stream().filter(naCombination -> naCombination.getNetworkActionSet().equals(networkActionCombination.getNetworkActionSet()))
.findAny();
alreadyExistingNetworkActionCombination.ifPresent(this.predefinedCombinations::remove);
this.predefinedCombinations.add(networkActionCombination);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
NetworkActionParameters that = (NetworkActionParameters) o;
return Double.compare(that.absoluteNetworkActionMinimumImpactThreshold, absoluteNetworkActionMinimumImpactThreshold) == 0 && Double.compare(that.relativeNetworkActionMinimumImpactThreshold, relativeNetworkActionMinimumImpactThreshold) == 0 && skipNetworkActionFarFromMostLimitingElements == that.skipNetworkActionFarFromMostLimitingElements && maxNumberOfBoundariesForSkippingNetworkActions == that.maxNumberOfBoundariesForSkippingNetworkActions && Objects.equals(predefinedCombinations, that.predefinedCombinations);
}
@Override
public int hashCode() {
return Objects.hash(predefinedCombinations, absoluteNetworkActionMinimumImpactThreshold, relativeNetworkActionMinimumImpactThreshold, skipNetworkActionFarFromMostLimitingElements, maxNumberOfBoundariesForSkippingNetworkActions);
}
public static List<NetworkActionCombination> computePredefinedCombinations(Crac crac, RaoParameters raoParameters) {
List<List<String>> predefinedCombinationsIds = getPredefinedCombinations(raoParameters);
List<NetworkActionCombination> computedPredefinedCombinations = new ArrayList<>();
predefinedCombinationsIds.forEach(networkActionIds -> {
Optional<NetworkActionCombination> optNaCombination = computePredefinedCombinationsFromIds(networkActionIds, crac);
optNaCombination.ifPresent(computedPredefinedCombinations::add);
});
return computedPredefinedCombinations;
}
private static Optional<NetworkActionCombination> computePredefinedCombinationsFromIds(List<String> networkActionIds, Crac crac) {
if (networkActionIds.size() < 2) {
BUSINESS_WARNS.warn("A predefined combination should contain at least 2 NetworkAction ids");
return Optional.empty();
}
Set<NetworkAction> networkActions = new HashSet<>();
for (String naId : networkActionIds) {
NetworkAction na = crac.getNetworkAction(naId);
if (na == null) {
BUSINESS_WARNS.warn("Unknown network action id in predefined-combinations parameter: {}", naId);
return Optional.empty();
}
networkActions.add(na);
}
return Optional.of(new NetworkActionCombination(networkActions));
}
}