Skip to content

Commit

Permalink
Merge branch 'main' into bug/fixHvdcNullPointerGetBusView
Browse files Browse the repository at this point in the history
  • Loading branch information
Godelaine authored Feb 10, 2025
2 parents 288123b + fa3935f commit b37ed54
Show file tree
Hide file tree
Showing 10 changed files with 417 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,10 @@ private Object runScenario(PrePerimeterResult prePerimeterSensitivityOutput, boo
boolean autoStateSensiFailed = false;
if (automatonState.isPresent()) {
AutomatonPerimeterResultImpl automatonResult = automatonSimulator.simulateAutomatonState(automatonState.get(), curativeStates, networkClone, stateTree, automatonTreeParameters);
contingencyScenarioResults.put(automatonState.get(), automatonResult);
if (automatonResult.getComputationStatus() == ComputationStatus.FAILURE) {
autoStateSensiFailed = true;
contingencyScenarioResults.put(automatonState.get(), new SkippedOptimizationResultImpl(automatonState.get(), automatonResult.getActivatedNetworkActions(), automatonResult.getActivatedRangeActions(automatonState.get()), ComputationStatus.FAILURE, sensitivityFailureOvercost));
} else {
contingencyScenarioResults.put(automatonState.get(), automatonResult);
preCurativeResult = automatonResult.getPostAutomatonSensitivityAnalysisOutput();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,15 +189,15 @@ public static Pair<RangeAction<?>, State> getLastAvailableRangeActionOnSameNetwo
} else if (state.getInstant().isCurative()) {

// look if a preventive range action acts on the same network elements
State preventiveState = optimizationContext.getMainOptimizationState();
State previousUsageState = optimizationContext.getMainOptimizationState();

if (preventiveState.isPreventive()) {
Optional<RangeAction<?>> correspondingRa = optimizationContext.getRangeActionsPerState().get(preventiveState).stream()
if (previousUsageState.getInstant().comesBefore(state.getInstant())) {
Optional<RangeAction<?>> correspondingRa = optimizationContext.getRangeActionsPerState().get(previousUsageState).stream()
.filter(ra -> ra.getId().equals(rangeAction.getId()) || ra.getNetworkElements().equals(rangeAction.getNetworkElements()))
.findAny();

if (correspondingRa.isPresent()) {
return Pair.of(correspondingRa.get(), preventiveState);
return Pair.of(correspondingRa.get(), previousUsageState);
}
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@

package com.powsybl.openrao.searchtreerao.commons;

import com.powsybl.contingency.Contingency;
import com.powsybl.openrao.commons.OpenRaoException;
import com.powsybl.openrao.commons.Unit;
import com.powsybl.openrao.data.crac.api.Crac;
import com.powsybl.openrao.data.crac.api.Instant;
import com.powsybl.openrao.data.crac.api.InstantKind;
import com.powsybl.openrao.data.crac.api.NetworkElement;
import com.powsybl.openrao.data.crac.api.RemedialAction;
import com.powsybl.openrao.data.crac.api.State;
import com.powsybl.openrao.data.crac.api.cnec.FlowCnec;
import com.powsybl.iidm.network.TwoSides;
import com.powsybl.openrao.data.crac.api.networkaction.ActionType;
import com.powsybl.openrao.data.crac.api.networkaction.NetworkAction;
import com.powsybl.openrao.data.crac.api.rangeaction.RangeAction;
import com.powsybl.openrao.data.crac.api.usagerule.OnConstraint;
import com.powsybl.openrao.data.crac.api.usagerule.OnInstant;
import com.powsybl.openrao.data.crac.api.usagerule.UsageMethod;
Expand All @@ -25,16 +29,18 @@
import com.powsybl.openrao.raoapi.RaoInput;
import com.powsybl.openrao.raoapi.parameters.ObjectiveFunctionParameters;
import com.powsybl.openrao.raoapi.parameters.RaoParameters;
import com.powsybl.openrao.raoapi.parameters.RelativeMarginsParameters;
import com.powsybl.openrao.raoapi.parameters.extensions.OpenRaoSearchTreeParameters;
import com.powsybl.openrao.raoapi.parameters.extensions.SearchTreeRaoRangeActionsOptimizationParameters;
import com.powsybl.openrao.raoapi.parameters.RelativeMarginsParameters;
import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter;
import com.powsybl.openrao.searchtreerao.result.api.FlowResult;
import com.powsybl.openrao.searchtreerao.result.api.PrePerimeterResult;
import com.powsybl.glsk.commons.ZonalData;
import com.powsybl.glsk.ucte.UcteGlskDocument;
import com.powsybl.iidm.network.Country;
import com.powsybl.iidm.network.Network;
import com.powsybl.sensitivity.SensitivityVariableSet;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
Expand Down Expand Up @@ -357,4 +363,54 @@ void testElementaryActionsLimitWithNonDiscretePsts() {
OpenRaoException exception = assertThrows(OpenRaoException.class, () -> RaoUtil.checkParameters(raoParameters, raoInput));
assertEquals("The PSTs must be approximated as integers to use the limitations of elementary actions as a constraint in the RAO.", exception.getMessage());
}

@Test
void testGetLastAvailableRangeActionOnSameNetworkElementWithOutageState() {
OptimizationPerimeter optimizationContext = Mockito.mock(OptimizationPerimeter.class);
Mockito.when(optimizationContext.getMainOptimizationState()).thenReturn(crac.getPreventiveState());
State outageState = Mockito.mock(State.class);
Mockito.when(outageState.getContingency()).thenReturn(Optional.of(crac.getContingency("Contingency FR1 FR3")));
Mockito.when(outageState.getInstant()).thenReturn(crac.getInstant(InstantKind.OUTAGE));
OpenRaoException exception = assertThrows(OpenRaoException.class, () -> RaoUtil.getLastAvailableRangeActionOnSameNetworkElement(optimizationContext, crac.getRangeActions().iterator().next(), outageState));
assertEquals("Linear optimization does not handle range actions which are neither PREVENTIVE nor CURATIVE.", exception.getMessage());
}

@Test
void testGetLastAvailableRangeActionOnSameNetworkElementMultiCurative() {
Contingency contingency = crac.getContingency("Contingency FR1 FR3");

Instant curative1Instant = Mockito.mock(Instant.class);
Mockito.when(curative1Instant.getKind()).thenReturn(InstantKind.CURATIVE);

State curativeState1 = Mockito.mock(State.class);
Mockito.when(curativeState1.getInstant()).thenReturn(curative1Instant);
Mockito.when(curativeState1.getContingency()).thenReturn(Optional.of(contingency));

Instant curative3Instant = Mockito.mock(Instant.class);
Mockito.when(curative3Instant.getKind()).thenReturn(InstantKind.CURATIVE);
Mockito.when(curative3Instant.isCurative()).thenReturn(true);

State curativeState3 = Mockito.mock(State.class);
Mockito.when(curativeState3.getInstant()).thenReturn(curative3Instant);
Mockito.when(curativeState3.getContingency()).thenReturn(Optional.of(contingency));

Mockito.when(curative1Instant.comesBefore(curative3Instant)).thenReturn(true);

NetworkElement pst = Mockito.mock(NetworkElement.class);
Mockito.when(pst.getId()).thenReturn("pst");

RangeAction<?> rangeAction1 = Mockito.mock(RangeAction.class);
Mockito.when(rangeAction1.getNetworkElements()).thenReturn(Set.of(pst));
Mockito.when(rangeAction1.getId()).thenReturn("range-action-1");

RangeAction<?> rangeAction2 = Mockito.mock(RangeAction.class);
Mockito.when(rangeAction2.getNetworkElements()).thenReturn(Set.of(pst));
Mockito.when(rangeAction2.getId()).thenReturn("range-action-2");

OptimizationPerimeter optimizationContext = Mockito.mock(OptimizationPerimeter.class);
Mockito.when(optimizationContext.getMainOptimizationState()).thenReturn(curativeState1);
Mockito.when(optimizationContext.getRangeActionsPerState()).thenReturn(Map.of(curativeState1, Set.of(rangeAction1)));

assertEquals(Pair.of(rangeAction1, curativeState1), RaoUtil.getLastAvailableRangeActionOnSameNetworkElement(optimizationContext, rangeAction2, curativeState3));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,12 @@ static SystematicSensitivityResult runSensitivity(Network network,
sensitivityComputationParameters), state.getInstant().getOrder());
} catch (Exception e) {
TECHNICAL_LOGS.error(String.format("Systematic sensitivity analysis failed for state %s : %s", state.getId(), e.getMessage()));
result.completeDataWithFailingPerimeter(state.getInstant().getOrder(), optContingency.get().getId());
SensitivityAnalysisResult failedResult = new SensitivityAnalysisResult(
cnecSensitivityProvider.getContingencyFactors(network, contingencyList),
List.of(new SensitivityAnalysisResult.SensitivityContingencyStatus(optContingency.get().getId(), SensitivityAnalysisResult.Status.FAILURE)),
List.of()
);
result.completeData(failedResult, state.getInstant().getOrder());
}
counterForLogs++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
public class SystematicSensitivityResult {

private static class StateResult {
private SensitivityComputationStatus status;
private SensitivityComputationStatus status = SensitivityComputationStatus.SUCCESS;
private final Map<String, Map<TwoSides, Double>> referenceFlows = new HashMap<>();
private final Map<String, Map<TwoSides, Double>> referenceIntensities = new HashMap<>();
private final Map<String, Map<String, Map<TwoSides, Double>>> flowSensitivities = new HashMap<>();
Expand All @@ -54,6 +54,10 @@ private Map<String, Map<String, Map<TwoSides, Double>>> getFlowSensitivities() {
private Map<String, Map<String, Map<TwoSides, Double>>> getIntensitySensitivities() {
return intensitySensitivities;
}

private boolean isEmpty() {
return referenceFlows.isEmpty() && referenceIntensities.isEmpty() && flowSensitivities.isEmpty() && intensitySensitivities.isEmpty();
}
}

public enum SensitivityComputationStatus {
Expand Down Expand Up @@ -98,24 +102,15 @@ public SystematicSensitivityResult completeData(SensitivityAnalysisResult result
);
postContingencyResults.get(instantOrder).put(contingencyStatus.getContingencyId(), contingencyStateResult);
}

nStateResult.status = this.status;

if (nStateResult.status != SensitivityComputationStatus.FAILURE && anyContingencyFailure) {
if (!results.getPreContingencyValues().isEmpty()) {
nStateResult.status = this.status;
}
if (nStateResult.status != SensitivityComputationStatus.FAILURE && anyContingencyFailure && !nStateResult.isEmpty()) {
this.status = SensitivityComputationStatus.PARTIAL_FAILURE;
}
return this;
}

public SystematicSensitivityResult completeDataWithFailingPerimeter(int instantOrder, String contingencyId) {
this.status = SensitivityComputationStatus.PARTIAL_FAILURE;
StateResult contingencyStateResult = new StateResult();
contingencyStateResult.status = SensitivityComputationStatus.FAILURE;
postContingencyResults.putIfAbsent(instantOrder, new HashMap<>());
postContingencyResults.get(instantOrder).put(contingencyId, contingencyStateResult);
return this;
}

public SystematicSensitivityResult postTreatIntensities() {
postTreatIntensitiesOnState(nStateResult);
postContingencyResults.values().forEach(map -> map.values().forEach(this::postTreatIntensitiesOnState));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ void testPostTreatHvdcInvert() {
}

@Test
// Test case where N succeeds and all N-1 fail
void testPartialContingencyFailures() {
setUpWith12Nodes();

Expand Down Expand Up @@ -373,20 +374,70 @@ void testCurativeResultAtOutageInstant() {
}

@Test
void testCompleteDataWithFailingPerimeter() {
void testCompleteDataWithFailingPerimeterIn2P() {

setUpWith12Nodes();
// When

// A first call to complete data with a sensitivity analysis N and N-1 succeed.
// Simulate the first call to completeData of the sensi computation pre 2P.
SensitivityAnalysisResult sensitivityAnalysisResult = SensitivityAnalysis.find().run(network,
rangeActionSensitivityProvider.getAllFactors(network),
rangeActionSensitivityProvider.getContingencies(network),
new ArrayList<>(),
SensitivityAnalysisParameters.load());

SystematicSensitivityResult result = new SystematicSensitivityResult().completeData(sensitivityAnalysisResult, outageInstantOrder);
assertEquals(SystematicSensitivityResult.SensitivityComputationStatus.SUCCESS, result.getStatus());

result.completeDataWithFailingPerimeter(outageInstantOrder, "Contingency FR1 FR3");
// after computation failure on contingency
// Simulate a second call to completeData during sensitivity computation pre 2P on a state with RAs that failed (a N-1 state fails).
Contingency contingency = new Contingency("contingency", new BranchContingency("branch"));

SensitivityFactor sensitivityFactor1 = new SensitivityFactor(
SensitivityFunctionType.BRANCH_ACTIVE_POWER_1,
"BBE2AA1 FFR3AA1 1",
SensitivityVariableType.TRANSFORMER_PHASE,
"BBE2AA1 BBE3AA1 1",
false,
new ContingencyContext(contingency.getId(), ContingencyContextType.SPECIFIC)
);

sensitivityAnalysisResult = new SensitivityAnalysisResult(
List.of(sensitivityFactor1),
List.of(new SensitivityAnalysisResult.SensitivityContingencyStatus(contingency.getId(), SensitivityAnalysisResult.Status.FAILURE)),
List.of()
);

result.completeData(sensitivityAnalysisResult, outageInstantOrder);

// success in n and a n-1 fails -> PARTIAL_FAILURE
assertEquals(SystematicSensitivityResult.SensitivityComputationStatus.PARTIAL_FAILURE, result.getStatus());
}

@Test
void testFailingCurativePerimeter() {
setUpWith12Nodes();
// Simulate a second call to completeData during sensitivity computation pre 2P on a state with RAs that failed (a N-1 state fails).
Contingency contingency = new Contingency("contingency", new BranchContingency("branch"));

SensitivityFactor sensitivityFactor1 = new SensitivityFactor(
SensitivityFunctionType.BRANCH_ACTIVE_POWER_1,
"BBE2AA1 FFR3AA1 1",
SensitivityVariableType.TRANSFORMER_PHASE,
"BBE2AA1 BBE3AA1 1",
false,
new ContingencyContext(contingency.getId(), ContingencyContextType.SPECIFIC)
);

SensitivityAnalysisResult sensitivityAnalysisResult = new SensitivityAnalysisResult(
List.of(sensitivityFactor1),
List.of(new SensitivityAnalysisResult.SensitivityContingencyStatus(contingency.getId(), SensitivityAnalysisResult.Status.FAILURE)),
List.of()
);

SystematicSensitivityResult result = new SystematicSensitivityResult();
result.completeData(sensitivityAnalysisResult, outageInstantOrder);

assertEquals(SystematicSensitivityResult.SensitivityComputationStatus.FAILURE, result.getStatus());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public void objectiveFunctionValueAfterAraShouldBe(double expectedValue) {

@Then("the value of the objective function after CRA should be {double}")
public void objectiveFunctionValueAfterCraShouldBe(double expectedValue) {
assertEquals(expectedValue, raoResult.getCost(crac.getInstant(InstantKind.CURATIVE)), flowAmpereTolerance(expectedValue));
assertEquals(expectedValue, raoResult.getCost(crac.getLastInstant()), flowAmpereTolerance(expectedValue));
}

@Then("the value of the objective function before optimisation should be {double}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Feature: US 12.15: export different reason per perimeter in SWE CNE
And the worst margin is -1419.4 A

@fast @rao @mock @ac @contingency-scenarios @second-preventive
# sensi pre 2P fails
# sensi pre 2P partially fails
Scenario: US 12.15.2.2: one contingency failing during 1st ARAO, with 2P
Given network file is "epic12/nordic32.xiidm"
Given crac file is "epic12/CIM_12_15_2.xml"
Expand All @@ -99,7 +99,7 @@ Feature: US 12.15: export different reason per perimeter in SWE CNE
And the worst margin is -1419.4 A

@fast @rao @mock @ac @contingency-scenarios @second-preventive
# sensi pre 2P fails
# sensi pre 2P partially fails
Scenario: US 12.15.2.3: one contingency failing during 1st ARAO, with global 2P
Given network file is "epic12/nordic32.xiidm"
Given crac file is "epic12/CIM_12_15_2.xml"
Expand Down
Loading

0 comments on commit b37ed54

Please sign in to comment.