PostPerimeterSensitivityAnalysis.java
/*
* Copyright (c) 2020, 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.castor.algorithm;
import com.powsybl.iidm.network.Network;
import com.powsybl.openrao.data.crac.api.Crac;
import com.powsybl.openrao.data.crac.api.State;
import com.powsybl.openrao.data.crac.api.cnec.FlowCnec;
import com.powsybl.openrao.data.crac.api.rangeaction.RangeAction;
import com.powsybl.openrao.raoapi.parameters.RaoParameters;
import com.powsybl.openrao.searchtreerao.commons.SensitivityComputer;
import com.powsybl.openrao.searchtreerao.commons.ToolProvider;
import com.powsybl.openrao.searchtreerao.commons.objectivefunction.ObjectiveFunction;
import com.powsybl.openrao.searchtreerao.result.api.*;
import com.powsybl.openrao.searchtreerao.result.impl.*;
import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
/**
* This class aims at performing the sensitivity analysis after the optimization of a perimeter. The result can be used as a
* starting point for the next perimeter, but it is also needed for the costs, margins and flows of elements after an optimization instant.
*
* @author Philippe Edwards {@literal <philippe.edwards at rte-france.com>}
*/
public class PostPerimeterSensitivityAnalysis extends AbstractMultiPerimeterSensitivityAnalysis {
public PostPerimeterSensitivityAnalysis(Crac crac,
Set<FlowCnec> flowCnecs,
Set<RangeAction<?>> rangeActions,
RaoParameters raoParameters,
ToolProvider toolProvider) {
super(crac, flowCnecs, rangeActions, raoParameters, toolProvider);
}
public PostPerimeterSensitivityAnalysis(Crac crac,
Set<State> states,
RaoParameters raoParameters,
ToolProvider toolProvider) {
super(crac, states, raoParameters, toolProvider);
}
/**
* This method requires:
* <ul>
* <li> the initialFlowResult to be able to compute mnec and loopflow thresholds </li>
* <li> the previousResultsFuture for countries not sharing CRAs </li>
* <li> the optimizationResult of the given perimeter for action cost </li>
* </ul>
*/
public Future<PostPerimeterResult> runBasedOnInitialPreviousAndOptimizationResults(Network network,
FlowResult initialFlowResult,
Future<PrePerimeterResult> previousResultsFuture,
Set<String> operatorsNotSharingCras,
OptimizationResult optimizationResult,
AppliedRemedialActions appliedCurativeRemedialActions) {
AtomicReference<FlowResult> flowResult = new AtomicReference<>();
AtomicReference<SensitivityResult> sensitivityResult = new AtomicReference<>();
boolean actionWasTaken = actionWasTaken(optimizationResult);
if (actionWasTaken) {
SensitivityComputer sensitivityComputer = buildSensitivityComputer(initialFlowResult, appliedCurativeRemedialActions);
sensitivityComputer.compute(network);
flowResult.set(sensitivityComputer.getBranchResult(network));
sensitivityResult.set(sensitivityComputer.getSensitivityResult());
}
// Thread is executed once previousResultsFuture is fetched
return Executors.newSingleThreadExecutor().submit(() -> {
if (!actionWasTaken) {
flowResult.set(previousResultsFuture.get());
sensitivityResult.set(previousResultsFuture.get());
}
ObjectiveFunction objectiveFunction = ObjectiveFunction.build(
flowCnecs,
toolProvider.getLoopFlowCnecs(flowCnecs),
initialFlowResult,
previousResultsFuture.get(),
operatorsNotSharingCras,
raoParameters,
optimizationResult.getActivatedRangeActionsPerState().keySet()
);
ObjectiveFunctionResult objectiveFunctionResult = objectiveFunction.evaluate(
flowResult.get(),
new RemedialActionActivationResultImpl(optimizationResult, optimizationResult)
);
return new PostPerimeterResult(optimizationResult, new PrePerimeterSensitivityResultImpl(
flowResult.get(),
sensitivityResult.get(),
RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(network, rangeActions),
objectiveFunctionResult
));
});
}
private boolean actionWasTaken(OptimizationResult optimizationResult) {
if (!optimizationResult.getActivatedNetworkActions().isEmpty()) {
return true;
}
return optimizationResult.getActivatedRangeActionsPerState().values().stream()
.anyMatch(set -> !set.isEmpty());
}
}