SumMaxPerTimestampCostEvaluatorResultTest.java
/*
* Copyright (c) 2025, 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.costevaluatorresult;
import com.powsybl.contingency.Contingency;
import com.powsybl.openrao.commons.Unit;
import com.powsybl.openrao.data.crac.api.State;
import com.powsybl.openrao.data.crac.api.cnec.FlowCnec;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author Thomas Bouquet {@literal <thomas.bouquet at rte-france.com>}
* @author Roxane Chen {@literal <roxane.chen at rte-france.com>}
*/
class SumMaxPerTimestampCostEvaluatorResultTest {
private FlowCnec flowCnecPreventiveT1;
private FlowCnec flowCnecPreventiveT2;
private FlowCnec flowCnecPreventiveT3;
private FlowCnec flowCnecCurative1T1;
private FlowCnec flowCnecCurative12T1;
private FlowCnec flowCnecCurativeT2;
private FlowCnec flowCnecCurativeT3;
private State preventiveStateT1;
private State preventiveStateT2;
private State preventiveStateT3;
private State curativeStateT1;
private State curativeStateT2;
private State curativeStateT3;
private OffsetDateTime timestamp1 = OffsetDateTime.parse("2025-02-25T15:11Z");
private OffsetDateTime timestamp2 = OffsetDateTime.parse("2025-02-25T16:11Z");
@BeforeEach
void setUp() {
preventiveStateT1 = Mockito.mock(State.class);
Mockito.when(preventiveStateT1.getContingency()).thenReturn(Optional.empty());
flowCnecPreventiveT1 = Mockito.mock(FlowCnec.class);
Mockito.when(flowCnecPreventiveT1.getState()).thenReturn(preventiveStateT1);
Mockito.when(flowCnecPreventiveT1.getId()).thenReturn("cnec-preventive-t1");
Mockito.when(flowCnecPreventiveT1.isOptimized()).thenReturn(true);
preventiveStateT2 = Mockito.mock(State.class);
Mockito.when(preventiveStateT2.getContingency()).thenReturn(Optional.empty());
flowCnecPreventiveT2 = Mockito.mock(FlowCnec.class);
Mockito.when(flowCnecPreventiveT2.getState()).thenReturn(preventiveStateT2);
Mockito.when(flowCnecPreventiveT2.getId()).thenReturn("cnec-preventive-t2");
Mockito.when(flowCnecPreventiveT2.isOptimized()).thenReturn(true);
preventiveStateT3 = Mockito.mock(State.class);
Mockito.when(preventiveStateT3.getContingency()).thenReturn(Optional.empty());
flowCnecPreventiveT3 = Mockito.mock(FlowCnec.class);
Mockito.when(flowCnecPreventiveT3.getState()).thenReturn(preventiveStateT3);
Mockito.when(flowCnecPreventiveT3.getId()).thenReturn("cnec-preventive-no-timestamp");
Mockito.when(flowCnecPreventiveT3.isOptimized()).thenReturn(true);
Contingency contingency1 = Mockito.mock(Contingency.class);
Mockito.when(contingency1.getId()).thenReturn("contingency-1");
curativeStateT1 = Mockito.mock(State.class);
Mockito.when(curativeStateT1.getContingency()).thenReturn(Optional.of(contingency1));
flowCnecCurative1T1 = Mockito.mock(FlowCnec.class);
Mockito.when(flowCnecCurative1T1.getState()).thenReturn(curativeStateT1);
Mockito.when(flowCnecCurative1T1.getId()).thenReturn("cnec-curative1");
Mockito.when(flowCnecCurative1T1.isOptimized()).thenReturn(true);
flowCnecCurative12T1 = Mockito.mock(FlowCnec.class);
Mockito.when(flowCnecCurative12T1.getState()).thenReturn(curativeStateT1);
Mockito.when(flowCnecCurative12T1.getId()).thenReturn("cnec-curative12");
Mockito.when(flowCnecCurative12T1.isOptimized()).thenReturn(true);
Contingency contingency2 = Mockito.mock(Contingency.class);
Mockito.when(contingency2.getId()).thenReturn("contingency-2");
curativeStateT2 = Mockito.mock(State.class);
Mockito.when(curativeStateT2.getContingency()).thenReturn(Optional.of(contingency2));
flowCnecCurativeT2 = Mockito.mock(FlowCnec.class);
Mockito.when(flowCnecCurativeT2.getState()).thenReturn(curativeStateT2);
Mockito.when(flowCnecCurativeT2.getId()).thenReturn("cnec-curative2");
Mockito.when(flowCnecCurativeT2.isOptimized()).thenReturn(true);
Contingency contingency3 = Mockito.mock(Contingency.class);
Mockito.when(contingency3.getId()).thenReturn("contingency-3");
curativeStateT3 = Mockito.mock(State.class);
Mockito.when(curativeStateT3.getContingency()).thenReturn(Optional.of(contingency3));
flowCnecCurativeT3 = Mockito.mock(FlowCnec.class);
Mockito.when(flowCnecCurativeT3.getState()).thenReturn(curativeStateT3);
Mockito.when(flowCnecCurativeT3.getId()).thenReturn("cnec-curative3");
Mockito.when(flowCnecCurativeT3.isOptimized()).thenReturn(true);
}
void addTimestamp() {
Mockito.when(preventiveStateT1.getTimestamp()).thenReturn(Optional.of(timestamp1));
Mockito.when(preventiveStateT2.getTimestamp()).thenReturn(Optional.of(timestamp2));
Mockito.when(preventiveStateT3.getTimestamp()).thenReturn(Optional.empty());
Mockito.when(curativeStateT1.getTimestamp()).thenReturn(Optional.of(timestamp1));
Mockito.when(curativeStateT2.getTimestamp()).thenReturn(Optional.of(timestamp2));
Mockito.when(curativeStateT3.getTimestamp()).thenReturn(Optional.empty());
}
@Test
void testEvaluator() {
addTimestamp();
Map<FlowCnec, Double> marginPerCnec = Map.of(flowCnecPreventiveT1, -10.0, flowCnecCurative1T1, -50.0, flowCnecCurative12T1, -120.0, flowCnecPreventiveT2, -34.0, flowCnecCurativeT2, -546.0, flowCnecPreventiveT3, 43.0, flowCnecCurativeT3, -76.0);
SumMaxPerTimestampCostEvaluatorResult evaluatorResult = new SumMaxPerTimestampCostEvaluatorResult(
marginPerCnec,
List.of(),
Unit.MEGAWATT
);
// timestamp 1: -120, -10, -50 -> minMargin = -120 -> cost = 120
// timestamp 2: -34, -546 -> minMargin = -546 -> cost = 546
// timestamp 3: 43, -76 -> minMargin = -76 -> cost = 76
// the expected evaluation in the sum of maxes: 120 + 546 + 76 = 742
assertEquals(742, evaluatorResult.getCost(Set.of(), Set.of()));
}
@Test
void testEvaluatorWithExclusion() {
addTimestamp();
Map<FlowCnec, Double> marginPerCnec = Map.of(flowCnecPreventiveT1, -10.0, flowCnecCurative1T1, -50.0, flowCnecCurative12T1, -120.0, flowCnecPreventiveT2, -34.0, flowCnecCurativeT2, -546.0, flowCnecPreventiveT3, 43.0, flowCnecCurativeT3, -76.0);
SumMaxPerTimestampCostEvaluatorResult evaluatorResult = new SumMaxPerTimestampCostEvaluatorResult(
marginPerCnec,
List.of(),
Unit.MEGAWATT
);
// contingencies 2 and 3 are excluded so results associated to flowCnecCurativeT2 and flowCnecCurativeT3 are ignored
// Also exclude cnec-curative12
// timestamp 1: -10, -50 -> minMargin = -50 -> cost = 50
// timestamp 2: 34 -> minMargin = -34 -> cost = 34
// timestamp 3: -43 -> minMargin = 43 -> cost = -43
// the expected evaluation in the sum of maxes: 50 + 34 - 43 = 41
assertEquals(41, evaluatorResult.getCost(Set.of("contingency-3", "contingency-2"), Set.of("cnec-curative12")));
}
@Test
void testWithoutAnyTimestampWithExclusion() {
Map<FlowCnec, Double> marginPerCnec = Map.of(flowCnecPreventiveT1, -10.0, flowCnecCurative1T1, -50.0, flowCnecCurative12T1, -40.0, flowCnecCurativeT2, 20.0, flowCnecCurativeT3, -17.0);
SumMaxPerTimestampCostEvaluatorResult evaluatorResult = new SumMaxPerTimestampCostEvaluatorResult(marginPerCnec, List.of(), Unit.MEGAWATT);
assertEquals(50.0, evaluatorResult.getCost(Set.of(), Set.of()));
assertEquals(17.0, evaluatorResult.getCost(Set.of("contingency-1", "contingency-2"), Set.of()));
assertEquals(40.0, evaluatorResult.getCost(Set.of(), Set.of("cnec-curative1")));
assertEquals(17.0, evaluatorResult.getCost(Set.of("contingency-1"), Set.of("cnec-curative1")));
}
@Test
void testEmptyResult() {
SumMaxPerTimestampCostEvaluatorResult evaluatorResult = new SumMaxPerTimestampCostEvaluatorResult(Map.of(), List.of(), Unit.MEGAWATT);
assertEquals(0, evaluatorResult.getCost(Set.of(), Set.of()));
}
}