CimCracCreatorTest.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.data.crac.io.cim.craccreator;
import com.google.common.base.Suppliers;
import com.powsybl.computation.local.LocalComputationManager;
import com.powsybl.action.GeneratorAction;
import com.powsybl.action.PhaseTapChangerTapPositionAction;
import com.powsybl.action.TerminalsConnectionAction;
import com.powsybl.contingency.ContingencyElement;
import com.powsybl.iidm.network.Country;
import com.powsybl.iidm.network.HvdcLine;
import com.powsybl.iidm.network.ImportConfig;
import com.powsybl.iidm.network.Network;
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.RaUsageLimits;
import com.powsybl.openrao.data.crac.api.RemedialAction;
import com.powsybl.openrao.data.crac.api.networkaction.NetworkAction;
import com.powsybl.openrao.data.crac.api.rangeaction.HvdcRangeAction;
import com.powsybl.openrao.data.crac.api.usagerule.OnConstraint;
import com.powsybl.openrao.data.crac.api.usagerule.OnContingencyState;
import com.powsybl.openrao.data.crac.api.usagerule.OnFlowConstraintInCountry;
import com.powsybl.openrao.data.crac.api.usagerule.OnInstant;
import com.powsybl.openrao.data.crac.api.usagerule.UsageMethod;
import com.powsybl.openrao.data.crac.io.cim.parameters.CimCracCreationParameters;
import com.powsybl.openrao.data.crac.io.cim.parameters.RangeActionSpeed;
import com.powsybl.openrao.data.crac.io.cim.parameters.VoltageCnecsCreationParameters;
import com.powsybl.openrao.data.crac.io.cim.parameters.VoltageMonitoredContingenciesAndThresholds;
import com.powsybl.openrao.data.crac.io.cim.parameters.VoltageThreshold;
import com.powsybl.openrao.data.crac.api.cnec.AngleCnec;
import com.powsybl.openrao.data.crac.api.cnec.FlowCnec;
import com.powsybl.iidm.network.TwoSides;
import com.powsybl.openrao.data.crac.api.parameters.CracCreationParameters;
import com.powsybl.openrao.data.crac.api.parameters.RangeActionGroup;
import com.powsybl.openrao.data.crac.api.range.RangeType;
import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction;
import com.powsybl.openrao.data.crac.api.threshold.BranchThreshold;
import com.powsybl.openrao.data.crac.io.commons.api.ElementaryCreationContext;
import com.powsybl.openrao.data.crac.io.commons.api.ImportStatus;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Godelaine de Montmorillon {@literal <godelaine.demontmorillon at rte-france.com>}
*/
class CimCracCreatorTest {
private static final String PREVENTIVE_INSTANT_ID = "preventive";
private static final String OUTAGE_INSTANT_ID = "outage";
private static final String AUTO_INSTANT_ID = "auto";
private static final String CURATIVE_INSTANT_ID = "curative";
private static final double DOUBLE_TOLERANCE = 1e-6;
private Crac importedCrac;
private CimCracCreationContext cracCreationContext;
private static Network baseNetwork;
private static Network hvdcNetwork;
private Instant preventiveInstant;
private Instant autoInstant;
private Instant curativeInstant;
@BeforeAll
public static void loadNetwork() {
Properties importParams = new Properties();
importParams.put("iidm.import.cgmes.source-for-iidm-id", "rdfID");
baseNetwork = Network.read(Paths.get(new File(CimCracCreatorTest.class.getResource("/networks/MicroGrid_missingImax.zip").getFile()).toString()), LocalComputationManager.getDefault(), Suppliers.memoize(ImportConfig::load).get(), importParams);
}
@BeforeAll
public static void loadHvdcNetwork() {
hvdcNetwork = loadNetworkWithHvdc();
}
private static Network loadNetworkWithHvdc() {
Properties importParams = new Properties();
importParams.put("iidm.import.cgmes.source-for-iidm-id", "rdfID");
return Network.read(Paths.get(new File(CimCracCreatorTest.class.getResource("/networks/TestCase16NodesWith2Hvdc.xiidm").getFile()).toString()), LocalComputationManager.getDefault(), Suppliers.memoize(ImportConfig::load).get(), importParams);
}
private void setUp(String fileName, Network network, CracCreationParameters cracCreationParameters) throws IOException {
InputStream is = getClass().getResourceAsStream(fileName);
cracCreationContext = (CimCracCreationContext) Crac.readWithContext(fileName, is, network, cracCreationParameters);
importedCrac = cracCreationContext.getCrac();
if (!Objects.isNull(importedCrac)) {
preventiveInstant = importedCrac.getInstant(PREVENTIVE_INSTANT_ID);
autoInstant = importedCrac.getInstant(AUTO_INSTANT_ID);
curativeInstant = importedCrac.getInstant(CURATIVE_INSTANT_ID);
} else {
preventiveInstant = null;
autoInstant = null;
curativeInstant = null;
}
}
private void setUpWithGroupId(String fileName, Network network, OffsetDateTime timestamp, List<List<String>> alignedRangeActions) throws IOException {
CracCreationParameters cracCreationParameters = new CracCreationParameters();
cracCreationParameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_ONE);
cracCreationParameters = Mockito.spy(cracCreationParameters);
CimCracCreationParameters cimCracCreationParameters = Mockito.mock(CimCracCreationParameters.class);
Mockito.when(cracCreationParameters.getExtension(CimCracCreationParameters.class)).thenReturn(cimCracCreationParameters);
List<RangeActionGroup> rangeActionGroups = new ArrayList<>();
alignedRangeActions.forEach(listAlignedRangeActions -> rangeActionGroups.add(new RangeActionGroup(listAlignedRangeActions)));
Mockito.when(cimCracCreationParameters.getRangeActionGroups()).thenReturn(rangeActionGroups);
Mockito.when(cimCracCreationParameters.getTimeseriesMrids()).thenReturn(Collections.emptySet());
Mockito.when(cimCracCreationParameters.getTimestamp()).thenReturn(timestamp);
InputStream is = getClass().getResourceAsStream(fileName);
cracCreationContext = (CimCracCreationContext) Crac.readWithContext(fileName, is, network, cracCreationParameters);
importedCrac = cracCreationContext.getCrac();
preventiveInstant = importedCrac.getInstant(PREVENTIVE_INSTANT_ID);
autoInstant = importedCrac.getInstant(AUTO_INSTANT_ID);
curativeInstant = importedCrac.getInstant(CURATIVE_INSTANT_ID);
}
private void setUpWithSpeed(String fileName, Network network, OffsetDateTime timestamp, Set<RangeActionSpeed> rangeActionSpeeds) throws IOException {
CracCreationParameters cracCreationParameters = new CracCreationParameters();
cracCreationParameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_ONE);
cracCreationParameters = Mockito.spy(cracCreationParameters);
CimCracCreationParameters cimCracCreationParameters = Mockito.mock(CimCracCreationParameters.class);
Mockito.when(cracCreationParameters.getExtension(CimCracCreationParameters.class)).thenReturn(cimCracCreationParameters);
Mockito.when(cimCracCreationParameters.getRangeActionSpeedSet()).thenReturn(rangeActionSpeeds);
Mockito.when(cimCracCreationParameters.getTimeseriesMrids()).thenReturn(Collections.emptySet());
Mockito.when(cimCracCreationParameters.getTimestamp()).thenReturn(timestamp);
InputStream is = getClass().getResourceAsStream(fileName);
cracCreationContext = (CimCracCreationContext) Crac.readWithContext(fileName, is, network, cracCreationParameters);
importedCrac = cracCreationContext.getCrac();
preventiveInstant = importedCrac.getInstant(PREVENTIVE_INSTANT_ID);
autoInstant = importedCrac.getInstant(AUTO_INSTANT_ID);
curativeInstant = importedCrac.getInstant(CURATIVE_INSTANT_ID);
}
private void setUpWithTimeseriesMrids(String fileName, Network network, OffsetDateTime timestamp, Set<String> timeseriesMrids) throws IOException {
CracCreationParameters cracCreationParameters = new CracCreationParameters();
cracCreationParameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_ONE);
cracCreationParameters = Mockito.spy(cracCreationParameters);
CimCracCreationParameters cimCracCreationParameters = Mockito.mock(CimCracCreationParameters.class);
Mockito.when(cracCreationParameters.getExtension(CimCracCreationParameters.class)).thenReturn(cimCracCreationParameters);
Mockito.when(cimCracCreationParameters.getTimeseriesMrids()).thenReturn(timeseriesMrids);
Mockito.when(cimCracCreationParameters.getTimestamp()).thenReturn(timestamp);
InputStream is = getClass().getResourceAsStream(fileName);
cracCreationContext = (CimCracCreationContext) Crac.readWithContext(fileName, is, network, cracCreationParameters);
importedCrac = cracCreationContext.getCrac();
preventiveInstant = importedCrac.getInstant(PREVENTIVE_INSTANT_ID);
autoInstant = importedCrac.getInstant(AUTO_INSTANT_ID);
curativeInstant = importedCrac.getInstant(CURATIVE_INSTANT_ID);
}
private void setUpWithTimestamp(String fileName, Network network, OffsetDateTime timestamp) throws IOException {
CracCreationParameters cracCreationParameters = new CracCreationParameters();
CimCracCreationParameters cimCracCreationParameters = Mockito.mock(CimCracCreationParameters.class);
cracCreationParameters = Mockito.spy(cracCreationParameters);
Mockito.when(cracCreationParameters.getExtension(CimCracCreationParameters.class)).thenReturn(cimCracCreationParameters);
Mockito.when(cimCracCreationParameters.getTimeseriesMrids()).thenReturn(Collections.emptySet());
Mockito.when(cimCracCreationParameters.getTimestamp()).thenReturn(timestamp);
InputStream is = getClass().getResourceAsStream(fileName);
cracCreationContext = (CimCracCreationContext) Crac.readWithContext(fileName, is, network, cracCreationParameters);
importedCrac = cracCreationContext.getCrac();
if (!Objects.isNull(importedCrac)) {
preventiveInstant = importedCrac.getInstant(PREVENTIVE_INSTANT_ID);
autoInstant = importedCrac.getInstant(AUTO_INSTANT_ID);
curativeInstant = importedCrac.getInstant(CURATIVE_INSTANT_ID);
} else {
preventiveInstant = null;
autoInstant = null;
curativeInstant = null;
}
}
private void assertContingencyNotImported(String name, String nativeName, ImportStatus importStatus) {
ElementaryCreationContext context = cracCreationContext.getContingencyCreationContextById(name);
assertNotNull(context);
assertEquals(nativeName, context.getNativeObjectName());
assertFalse(context.isImported());
assertEquals(importStatus, context.getImportStatus());
}
private void assertContingencyImported(String id, String nativeName, Set<String> networkElements, boolean isAltered) {
ElementaryCreationContext context = cracCreationContext.getContingencyCreationContextById(id);
assertNotNull(context);
assertEquals(nativeName, context.getNativeObjectName());
assertTrue(context.isImported());
assertEquals(isAltered, context.isAltered());
if (isAltered) {
assertNotNull(context.getImportStatusDetail());
} else {
assertNull(context.getImportStatusDetail());
}
assertEquals(id, context.getCreatedObjectId());
assertNotNull(importedCrac.getContingency(id));
Set<String> actualNetworkElements = importedCrac.getContingency(id).getElements().stream().map(ContingencyElement::getId).collect(Collectors.toSet());
assertEquals(networkElements, actualNetworkElements);
}
private void assertCnecNotImported(String monitoredSeriesId, ImportStatus importStatus) {
MonitoredSeriesCreationContext monitoredSeriesCreationContext = cracCreationContext.getMonitoredSeriesCreationContext(monitoredSeriesId);
assertNotNull(monitoredSeriesCreationContext);
assertFalse(monitoredSeriesCreationContext.isImported());
assertEquals(importStatus, monitoredSeriesCreationContext.getImportStatus());
}
private void assertCnecImported(String monitoredSeriesId, Set<String> expectedCnecIds) {
MonitoredSeriesCreationContext monitoredSeriesCreationContext = cracCreationContext.getMonitoredSeriesCreationContext(monitoredSeriesId);
assertNotNull(monitoredSeriesCreationContext);
Set<String> importedCnecIds =
monitoredSeriesCreationContext.getMeasurementCreationContexts().stream()
.filter(MeasurementCreationContext::isImported)
.map(measurementCreationContext ->
measurementCreationContext.getCnecCreationContexts().values().stream()
.filter(CnecCreationContext::isImported)
.map(CnecCreationContext::getCreatedCnecId)
.collect(Collectors.toSet()))
.flatMap(Collection::stream)
.collect(Collectors.toSet());
assertEquals(expectedCnecIds, importedCnecIds);
}
private void assertAngleCnecImportedWithContingency(String id, String contingencyId, Set<String> networkElementIds, double max) {
AngleCnecCreationContext angleCnecCreationContext = cracCreationContext.getAngleCnecCreationContext(id);
assertNotNull(angleCnecCreationContext);
assertTrue(angleCnecCreationContext.isImported());
assertNotNull(importedCrac.getAngleCnec(id));
Set<String> importedAngleCnecNetworkElements = new HashSet<>();
importedAngleCnecNetworkElements.add(importedCrac.getAngleCnec(id).getImportingNetworkElement().toString());
importedAngleCnecNetworkElements.add(importedCrac.getAngleCnec(id).getExportingNetworkElement().toString());
assertEquals(networkElementIds, importedAngleCnecNetworkElements);
assertEquals(contingencyId, angleCnecCreationContext.getContingencyId());
assertEquals(1, importedCrac.getAngleCnec(id).getThresholds().size());
assertEquals(max, importedCrac.getAngleCnec(id).getThresholds().iterator().next().max().orElseThrow());
assertTrue(importedCrac.getAngleCnec(id).getThresholds().iterator().next().min().isEmpty());
}
private void assertAngleCnecNotImported(String id, ImportStatus importStatus) {
AngleCnecCreationContext angleCnecCreationContext = cracCreationContext.getAngleCnecCreationContext(id);
assertNotNull(angleCnecCreationContext);
assertFalse(angleCnecCreationContext.isImported());
assertEquals(importStatus, angleCnecCreationContext.getImportStatus());
}
private void assertRemedialActionNotImported(String id, ImportStatus importStatus) {
RemedialActionSeriesCreationContext remedialActionSeriesCreationContext = cracCreationContext.getRemedialActionSeriesCreationContext(id);
assertNotNull(remedialActionSeriesCreationContext);
assertFalse(remedialActionSeriesCreationContext.isImported());
assertEquals(importStatus, remedialActionSeriesCreationContext.getImportStatus());
}
private void assertRemedialActionImportedWithOperator(String remedialActionId, String operator) {
RemedialActionSeriesCreationContext remedialActionSeriesCreationContext = cracCreationContext.getRemedialActionSeriesCreationContext(remedialActionId);
assertNotNull(remedialActionSeriesCreationContext);
assertTrue(remedialActionSeriesCreationContext.isImported());
assertEquals(operator, importedCrac.getRemedialAction(remedialActionId).getOperator());
}
private void assertPstRangeActionImported(String id, String networkElement, boolean isAltered) {
RemedialActionSeriesCreationContext remedialActionSeriesCreationContext = cracCreationContext.getRemedialActionSeriesCreationContext(id);
assertNotNull(remedialActionSeriesCreationContext);
assertTrue(remedialActionSeriesCreationContext.isImported());
assertEquals(isAltered, remedialActionSeriesCreationContext.isAltered());
assertNotNull(importedCrac.getPstRangeAction(id));
String actualNetworkElement = importedCrac.getPstRangeAction(id).getNetworkElement().toString();
assertEquals(networkElement, actualNetworkElement);
}
private void assertHvdcRangeActionImported(String expectedNativeId, Set<String> expectedCreatedIds, Set<String> expectedNetworkElements, Set<String> expectedOperators, boolean isInverted) {
RemedialActionSeriesCreationContext remedialActionSeriesCreationContext = cracCreationContext.getRemedialActionSeriesCreationContext(expectedNativeId);
assertNotNull(remedialActionSeriesCreationContext);
assertEquals(expectedCreatedIds, remedialActionSeriesCreationContext.getCreatedObjectsIds());
assertTrue(remedialActionSeriesCreationContext.isImported());
expectedCreatedIds.forEach(createdId -> assertNotNull(importedCrac.getHvdcRangeAction(createdId)));
Set<String> actualNetworkElements = new HashSet<>();
expectedCreatedIds.forEach(createdId -> actualNetworkElements.add(importedCrac.getHvdcRangeAction(createdId).getNetworkElement().toString()));
assertEquals(actualNetworkElements, expectedNetworkElements);
Set<String> actualOperators = new HashSet<>();
expectedCreatedIds.forEach(createdId -> actualOperators.add(importedCrac.getHvdcRangeAction(createdId).getOperator()));
assertEquals(actualOperators, expectedOperators);
assertEquals(isInverted, remedialActionSeriesCreationContext.isInverted());
}
private void assertNetworkActionImported(String id, Set<String> networkElements, boolean isAltered) {
RemedialActionSeriesCreationContext remedialActionSeriesCreationContext = cracCreationContext.getRemedialActionSeriesCreationContext(id);
assertNotNull(remedialActionSeriesCreationContext);
assertTrue(remedialActionSeriesCreationContext.isImported());
assertEquals(isAltered, remedialActionSeriesCreationContext.isAltered());
assertNotNull(importedCrac.getNetworkAction(id));
Set<String> actualNetworkElements = importedCrac.getNetworkAction(id).getNetworkElements().stream().map(NetworkElement::getId).collect(Collectors.toSet());
assertEquals(networkElements, actualNetworkElements);
}
private void assertHasOnFlowConstraintUsageRule(RemedialAction<?> ra, Instant instant, String flowCnecId) {
assertTrue(
ra.getUsageRules().stream()
.filter(OnConstraint.class::isInstance)
.map(OnConstraint.class::cast)
.anyMatch(
ur -> ur.getInstant().equals(instant)
&& ur.getCnec() instanceof FlowCnec
&& ur.getCnec().getId().equals(flowCnecId)
&& ur.getUsageMethod().equals(instant.isAuto() ? UsageMethod.FORCED : UsageMethod.AVAILABLE)
));
}
private void assertHasOnAngleUsageRule(String raId, String angleCnecId) {
RemedialAction<?> ra = importedCrac.getRemedialAction(raId);
assertTrue(
ra.getUsageRules().stream()
.filter(OnConstraint.class::isInstance)
.map(OnConstraint.class::cast)
.anyMatch(
ur -> ur.getInstant().isCurative()
&& ur.getCnec() instanceof AngleCnec
&& ur.getCnec().getId().equals(angleCnecId)
&& ur.getUsageMethod().equals(UsageMethod.AVAILABLE)
));
}
private void assertHasOneThreshold(String cnecId, TwoSides side, Unit unit, double min, double max) {
FlowCnec cnec = importedCrac.getFlowCnec(cnecId);
assertEquals(1, cnec.getThresholds().size());
BranchThreshold threshold = cnec.getThresholds().iterator().next();
assertEquals(side, threshold.getSide());
assertEquals(unit, threshold.getUnit());
assertTrue(threshold.limitsByMin());
assertEquals(min, threshold.min().get(), DOUBLE_TOLERANCE);
assertTrue(threshold.limitsByMax());
assertEquals(max, threshold.max().get(), DOUBLE_TOLERANCE);
}
private void assertHasTwoThresholds(String cnecId, Unit unit, double min, double max) {
FlowCnec cnec = importedCrac.getFlowCnec(cnecId);
assertEquals(2, cnec.getThresholds().size());
assertTrue(cnec.getThresholds().stream().anyMatch(threshold -> threshold.getSide().equals(TwoSides.ONE)));
assertTrue(cnec.getThresholds().stream().anyMatch(threshold -> threshold.getSide().equals(TwoSides.TWO)));
cnec.getThresholds().forEach(threshold -> {
assertEquals(unit, threshold.getUnit());
assertTrue(threshold.limitsByMin());
assertEquals(min, threshold.min().get(), DOUBLE_TOLERANCE);
assertTrue(threshold.limitsByMax());
assertEquals(max, threshold.max().get(), DOUBLE_TOLERANCE);
});
}
@Test
void cracCreationSuccessfulFailureTime() throws IOException {
CracCreationParameters cracParams = new CracCreationParameters();
cracParams.addExtension(CimCracCreationParameters.class, new CimCracCreationParameters());
setUp("/cracs/CIM_21_1_1.xml", baseNetwork, cracParams);
assertFalse(cracCreationContext.isCreationSuccessful());
}
@Test
void cracCreationFailureWrongTime() throws IOException {
setUpWithTimestamp("/cracs/CIM_21_1_1.xml", baseNetwork, OffsetDateTime.parse("2020-04-01T22:00Z"));
assertFalse(cracCreationContext.isCreationSuccessful());
}
@Test
void cracCreationSuccessfulRightTime() throws IOException {
setUpWithTimestamp("/cracs/CIM_21_1_1.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T22:00Z"));
assertTrue(cracCreationContext.isCreationSuccessful());
}
@Test
void cracCreationWithParameters() throws IOException {
CracCreationParameters cracCreationParameters = new CracCreationParameters();
RaUsageLimits raUsageLimits = new RaUsageLimits();
raUsageLimits.setMaxRa(2);
cracCreationParameters.addRaUsageLimitsForInstant("preventive", raUsageLimits);
cracCreationParameters.addExtension(CimCracCreationParameters.class, new CimCracCreationParameters());
cracCreationParameters.getExtension(CimCracCreationParameters.class).setTimestamp(OffsetDateTime.parse("2021-04-01T22:00Z"));
setUp("/cracs/CIM_21_1_1.xml", baseNetwork, cracCreationParameters);
assertTrue(cracCreationContext.isCreationSuccessful());
assertEquals(2, cracCreationContext.getCrac().getRaUsageLimits(preventiveInstant).getMaxRa());
assertEquals(OffsetDateTime.of(2021, 2, 9, 19, 30, 0, 0, ZoneOffset.UTC), cracCreationContext.getNetworkCaseDate());
assertEquals(14, cracCreationContext.getNetworkBranches().size());
}
@Test
void testImportContingencies() throws IOException {
setUpWithTimestamp("/cracs/CIM_21_1_1.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"));
assertEquals(3, importedCrac.getContingencies().size());
assertContingencyImported("Co-1", "Co-1-name", Set.of("_ffbabc27-1ccd-4fdc-b037-e341706c8d29"), false);
assertContingencyImported("Co-2", "Co-2-name", Set.of("_b18cd1aa-7808-49b9-a7cf-605eaf07b006 + _e8acf6b6-99cb-45ad-b8dc-16c7866a4ddc", "_df16b3dd-c905-4a6f-84ee-f067be86f5da"), false);
assertContingencyImported("Co-3", "Co-3-name", Set.of("_b58bf21a-096a-4dae-9a01-3f03b60c24c7"), true);
assertContingencyNotImported("Co-4", "Co-4-name", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK);
assertContingencyNotImported("Co-5", "Co-5-name", ImportStatus.INCOMPLETE_DATA);
assertEquals(4, cracCreationContext.getCreationReport().getReport().size()); // 2 fake contingencies, 1 altered, 1 CRAC content
}
@Test
void testCracPeriodManagementBeforeValidPeriod() throws IOException {
setUpWithTimestamp("/cracs/CIM_21_1_1_multi_period.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T22:00Z"));
assertEquals(0, importedCrac.getContingencies().size());
setUpWithTimestamp("/cracs/CIM_21_1_1_multi_period.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"));
assertEquals(3, importedCrac.getContingencies().size());
setUpWithTimestamp("/cracs/CIM_21_1_1_multi_period.xml", baseNetwork, OffsetDateTime.parse("2021-04-02T01:00Z"));
assertEquals(3, importedCrac.getContingencies().size());
setUpWithTimestamp("/cracs/CIM_21_1_1_multi_period.xml", baseNetwork, OffsetDateTime.parse("2021-04-02T02:00Z"));
assertEquals(1, importedCrac.getContingencies().size());
}
@Test
void testImportContingencyOnTieLine() throws IOException {
setUpWithTimestamp("/cracs/CIM_co_halfline.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"));
assertEquals(1, importedCrac.getContingencies().size());
assertContingencyImported("Co-2", "Co-2-name", Set.of("_b18cd1aa-7808-49b9-a7cf-605eaf07b006 + _e8acf6b6-99cb-45ad-b8dc-16c7866a4ddc", "_df16b3dd-c905-4a6f-84ee-f067be86f5da"), false);
}
@Test
void testImportFakeCnecs() throws IOException {
CracCreationParameters cracCreationParameters = new CracCreationParameters();
cracCreationParameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_ONE);
cracCreationParameters.addExtension(CimCracCreationParameters.class, new CimCracCreationParameters());
cracCreationParameters.getExtension(CimCracCreationParameters.class).setTimestamp(OffsetDateTime.parse("2021-04-01T23:00Z"));
setUp("/cracs/CIM_21_2_1.xml", baseNetwork, cracCreationParameters);
assertEquals(10, importedCrac.getFlowCnecs().size());
// CNEC 2
assertCnecNotImported("CNEC-2", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK);
// CNEC 3
assertCnecImported("CNEC-3", Set.of("CNEC-3 - preventive", "CNEC-3 - Co-1 - auto", "CNEC-3 - Co-2 - auto"));
assertHasOneThreshold("CNEC-3 - preventive", TwoSides.ONE, Unit.MEGAWATT, -3, 3);
assertHasOneThreshold("CNEC-3 - Co-1 - auto", TwoSides.ONE, Unit.AMPERE, -3, 3);
assertHasOneThreshold("CNEC-3 - Co-2 - auto", TwoSides.ONE, Unit.AMPERE, -3, 3);
// CNEC 4
assertCnecImported("CNEC-4", Set.of("CNEC-4 - preventive", "CNEC-4 - Co-1 - curative", "CNEC-4 - Co-2 - curative"));
assertHasOneThreshold("CNEC-4 - preventive", TwoSides.ONE, Unit.PERCENT_IMAX, -0.04, 0.04);
assertHasOneThreshold("CNEC-4 - Co-1 - curative", TwoSides.ONE, Unit.PERCENT_IMAX, -0.04, 0.04);
assertHasOneThreshold("CNEC-4 - Co-2 - curative", TwoSides.ONE, Unit.PERCENT_IMAX, -0.04, 0.04);
// CNEC 5
assertCnecImported("MNEC-1", Set.of("CNEC-5 - ONE - MONITORED - preventive", "CNEC-5 - ONE - MONITORED - Co-1 - curative"));
assertHasOneThreshold("CNEC-5 - ONE - MONITORED - preventive", TwoSides.ONE, Unit.PERCENT_IMAX, -0.05, 0.05);
assertHasOneThreshold("CNEC-5 - ONE - MONITORED - Co-1 - curative", TwoSides.ONE, Unit.PERCENT_IMAX, -0.05, 0.05);
// CNEC 6
assertCnecImported("MNEC-2", Set.of("CNEC-6 - MONITORED - preventive", "CNEC-6 - MONITORED - Co-1 - outage"));
assertHasOneThreshold("CNEC-6 - MONITORED - preventive", TwoSides.ONE, Unit.PERCENT_IMAX, -0.06, 0.06);
assertHasOneThreshold("CNEC-6 - MONITORED - Co-1 - outage", TwoSides.ONE, Unit.PERCENT_IMAX, -0.06, 0.06);
}
@Test
void testImportPstRangeActions() throws IOException {
setUpWithTimestamp("/cracs/CIM_21_3_1.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"));
assertPstRangeActionImported("PRA_1", "_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0", false);
assertRemedialActionImportedWithOperator("PRA_1", "PRA_1");
assertRemedialActionImportedWithOperator("REE-PRA_1", "REE");
assertRemedialActionImportedWithOperator("RTE-PRA_1", "RTE");
assertRemedialActionImportedWithOperator("REN-PRA_1", "REN");
assertRemedialActionNotImported("RA-Series-2", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_5", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_6", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_7", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_8", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_9", ImportStatus.INCOMPLETE_DATA);
assertRemedialActionNotImported("PRA_10", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_11", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_12", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_13", ImportStatus.INCOMPLETE_DATA);
assertRemedialActionNotImported("PRA_14", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_16", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_17", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_18", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_19", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_20", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_21", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK);
assertPstRangeActionImported("PRA_22", "_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0", true);
assertEquals(5, importedCrac.getPstRangeActions().size());
}
@Test
void testImportNetworkActions() throws IOException {
setUpWithTimestamp("/cracs/CIM_21_4_1.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"));
assertNetworkActionImported("PRA_1", Set.of("_e8a7eaec-51d6-4571-b3d9-c36d52073c33", "_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0", "_b94318f6-6d24-4f56-96b9-df2531ad6543", "_2184f365-8cd5-4b5d-8a28-9d68603bb6a4"), false);
assertRemedialActionImportedWithOperator("PRA_1", "PRA_1");
assertRemedialActionImportedWithOperator("REE-PRA_1", "REE");
assertRemedialActionImportedWithOperator("RTE-PRA_1", "RTE");
assertRemedialActionImportedWithOperator("REN-PRA_1", "REN");
// Pst Setpoint
assertRemedialActionNotImported("PRA_2", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_3", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_4", ImportStatus.INCOMPLETE_DATA);
assertRemedialActionNotImported("PRA_5", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_6", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK);
// Injection Setpoint
assertNetworkActionImported("PRA_7", Set.of("_1dc9afba-23b5-41a0-8540-b479ed8baf4b", "_2844585c-0d35-488d-a449-685bcd57afbf"), false);
assertRemedialActionNotImported("PRA_8", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_9", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_10", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_11", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_12", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_13", ImportStatus.INCOMPLETE_DATA);
assertRemedialActionNotImported("PRA_14", ImportStatus.INCOMPLETE_DATA);
assertRemedialActionNotImported("PRA_15", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_16", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK);
// Topological
assertNetworkActionImported("PRA_17", Set.of("_ffbabc27-1ccd-4fdc-b037-e341706c8d29", "_b58bf21a-096a-4dae-9a01-3f03b60c24c7", "_f04ec73d-b94a-4b7e-a3d6-b1234fc37385_SW_fict", "_5a094c9f-0af5-48dc-94e9-89c6c220023c"), false);
assertRemedialActionNotImported("PRA_18", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_19", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_20", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_21", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_22", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_23", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("PRA_24", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK);
assertRemedialActionNotImported("PRA_25", ImportStatus.NOT_YET_HANDLED_BY_OPEN_RAO);
assertRemedialActionNotImported("ARA_28", ImportStatus.INCONSISTENCY_IN_DATA);
// Mix
assertNetworkActionImported("PRA_26", Set.of("_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0", "_2844585c-0d35-488d-a449-685bcd57afbf", "_ffbabc27-1ccd-4fdc-b037-e341706c8d29"), false);
assertRemedialActionNotImported("PRA_27", ImportStatus.INCONSISTENCY_IN_DATA);
}
@Test
void testImportHvdcRangeActions() throws IOException {
setUpWithSpeed("/cracs/CIM_21_6_1.xml", hvdcNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of(new RangeActionSpeed("BBE2AA11 FFR3AA11 1", 1), new RangeActionSpeed("BBE2AA12 FFR3AA12 1", 2)));
// RA-Series-2
assertRemedialActionNotImported("HVDC-direction21", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("HVDC-direction22", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("HVDC-direction2", ImportStatus.INCONSISTENCY_IN_DATA);
// RA-Series-3
assertRemedialActionNotImported("HVDC-direction31", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("HVDC-direction32", ImportStatus.INCONSISTENCY_IN_DATA);
// RA-Series-4
assertRemedialActionNotImported("HVDC-direction41", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("HVDC-direction42", ImportStatus.INCONSISTENCY_IN_DATA);
// RA-Series-5
assertRemedialActionNotImported("HVDC-direction51", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("HVDC-direction52", ImportStatus.INCONSISTENCY_IN_DATA);
// RA-Series-6
assertRemedialActionNotImported("HVDC-direction61", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("HVDC-direction62", ImportStatus.INCONSISTENCY_IN_DATA);
// RA-Series-7
assertRemedialActionNotImported("HVDC-direction71", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("HVDC-direction72", ImportStatus.INCONSISTENCY_IN_DATA);
// RA-Series-8
assertRemedialActionNotImported("HVDC-direction81", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("HVDC-direction82", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK);
// RA-Series-9
assertRemedialActionNotImported("HVDC-direction91", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("HVDC-direction92", ImportStatus.INCONSISTENCY_IN_DATA);
Set<String> createdIds1 = Set.of("HVDC-direction11 + HVDC-direction12 - BBE2AA12 FFR3AA12 1", "HVDC-direction11 + HVDC-direction12 - BBE2AA11 FFR3AA11 1");
Set<String> createdIds2 = Set.of("HVDC-direction11 + HVDC-direction12 - BBE2AA12 FFR3AA12 1", "HVDC-direction11 + HVDC-direction12 - BBE2AA11 FFR3AA11 1");
assertHvdcRangeActionImported("HVDC-direction11", createdIds1, Set.of("BBE2AA11 FFR3AA11 1", "BBE2AA12 FFR3AA12 1"), Set.of("HVDC"), false);
assertHvdcRangeActionImported("HVDC-direction12", createdIds2, Set.of("BBE2AA11 FFR3AA11 1", "BBE2AA12 FFR3AA12 1"), Set.of("HVDC"), true);
assertEquals("BBE2AA11 FFR3AA11 1 + BBE2AA12 FFR3AA12 1", importedCrac.getHvdcRangeAction("HVDC-direction11 + HVDC-direction12 - BBE2AA12 FFR3AA12 1").getGroupId().get());
assertEquals("BBE2AA11 FFR3AA11 1 + BBE2AA12 FFR3AA12 1", importedCrac.getHvdcRangeAction("HVDC-direction11 + HVDC-direction12 - BBE2AA11 FFR3AA11 1").getGroupId().get());
}
@Test
void testImportKOHvdcRangeActions() throws IOException {
setUpWithSpeed("/cracs/CIM_21_6_1.xml", hvdcNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"), null);
assertRemedialActionNotImported("HVDC-direction11", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("HVDC-direction12", ImportStatus.INCONSISTENCY_IN_DATA);
}
@Test
void testImportAlignedRangeActions() throws IOException {
setUpWithGroupId("/cracs/CIM_21_3_1.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"), List.of(List.of("PRA_1", "PRA_22")));
assertPstRangeActionImported("PRA_1", "_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0", false);
assertPstRangeActionImported("PRA_22", "_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0", true);
assertEquals(5, importedCrac.getPstRangeActions().size());
assertTrue(importedCrac.getPstRangeAction("PRA_1").getGroupId().isPresent());
assertTrue(importedCrac.getPstRangeAction("PRA_22").getGroupId().isPresent());
assertEquals("PRA_1 + PRA_22", importedCrac.getPstRangeAction("PRA_1").getGroupId().get());
assertEquals("PRA_1 + PRA_22", importedCrac.getPstRangeAction("PRA_22").getGroupId().get());
}
@Test
void testImportAlignedRangeActionsGroupIdNull() throws IOException {
List<String> groupIds = new ArrayList<>();
groupIds.add(null);
setUpWithGroupId("/cracs/CIM_21_3_1.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"), List.of(groupIds));
assertPstRangeActionImported("PRA_1", "_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0", false);
assertPstRangeActionImported("PRA_22", "_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0", true);
assertEquals(5, importedCrac.getPstRangeActions().size());
assertFalse(importedCrac.getPstRangeAction("PRA_1").getGroupId().isPresent());
assertFalse(importedCrac.getPstRangeAction("PRA_22").getGroupId().isPresent());
}
@Test
void testImportAlignedRangeActionsGroupIdAlreadyDefined() throws IOException {
setUpWithGroupId("/cracs/CIM_21_3_1.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"), List.of(List.of("PRA_1", "PRA_22"), List.of("PRA_1")));
assertRemedialActionNotImported("PRA_1", ImportStatus.INCONSISTENCY_IN_DATA);
assertPstRangeActionImported("PRA_22", "_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0", true);
assertEquals(4, importedCrac.getPstRangeActions().size());
assertTrue(importedCrac.getPstRangeAction("PRA_22").getGroupId().isPresent());
assertEquals("PRA_1 + PRA_22", importedCrac.getPstRangeAction("PRA_22").getGroupId().get());
}
@Test
void testImportOnFlowConstraintUsageRules() throws IOException {
setUpWithSpeed("/cracs/CIM_21_5_1.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of(new RangeActionSpeed("AUTO_1", 1)));
// PRA_1
assertPstRangeActionImported("PRA_1", "_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0", false);
PstRangeAction pra1 = importedCrac.getPstRangeAction("PRA_1");
assertEquals(10, pra1.getUsageRules().size());
assertHasOnFlowConstraintUsageRule(pra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - preventive");
assertHasOnFlowConstraintUsageRule(pra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-1 - outage");
assertHasOnFlowConstraintUsageRule(pra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-1 - auto");
assertHasOnFlowConstraintUsageRule(pra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-1 - curative");
assertHasOnFlowConstraintUsageRule(pra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-2 - outage");
assertHasOnFlowConstraintUsageRule(pra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-2 - auto");
assertHasOnFlowConstraintUsageRule(pra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-2 - curative");
assertHasOnFlowConstraintUsageRule(pra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-3 - outage");
assertHasOnFlowConstraintUsageRule(pra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-3 - auto");
assertHasOnFlowConstraintUsageRule(pra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-3 - curative");
assertEquals(1, pra1.getRanges().size());
assertEquals(RangeType.ABSOLUTE, pra1.getRanges().get(0).getRangeType());
assertEquals(1, pra1.getRanges().get(0).getMinTap());
assertEquals(33, pra1.getRanges().get(0).getMaxTap());
assertEquals(10, pra1.getInitialTap());
// PRA_CRA_1
assertPstRangeActionImported("PRA_CRA_1", "_e8a7eaec-51d6-4571-b3d9-c36d52073c33", true);
PstRangeAction praCra1 = importedCrac.getPstRangeAction("PRA_CRA_1");
assertEquals(8, praCra1.getUsageRules().size());
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-2 - outage");
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-2 - auto");
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-2 - curative");
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-3 - outage");
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-3 - auto");
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-3 - curative");
assertHasOnFlowConstraintUsageRule(praCra1, curativeInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-2 - curative");
assertHasOnFlowConstraintUsageRule(praCra1, curativeInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-3 - curative");
assertEquals(1, praCra1.getRanges().size());
assertEquals(RangeType.RELATIVE_TO_INITIAL_NETWORK, praCra1.getRanges().get(0).getRangeType());
assertEquals(-10, praCra1.getRanges().get(0).getMinTap());
assertEquals(10, praCra1.getRanges().get(0).getMaxTap());
assertEquals(8, praCra1.getInitialTap());
// AUTO_1
assertPstRangeActionImported("AUTO_1", "_e8a7eaec-51d6-4571-b3d9-c36d52073c33", true);
PstRangeAction auto1 = importedCrac.getPstRangeAction("AUTO_1");
assertEquals(4, auto1.getUsageRules().size());
assertHasOnFlowConstraintUsageRule(auto1, autoInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-2 - auto");
assertHasOnFlowConstraintUsageRule(auto1, autoInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-2 - curative");
assertHasOnFlowConstraintUsageRule(auto1, autoInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-3 - auto");
assertHasOnFlowConstraintUsageRule(auto1, autoInstant, "GHIOL_QSDFGH_1_220 - ONE - Co-one-3 - curative");
assertEquals(1, auto1.getRanges().size());
assertEquals(RangeType.RELATIVE_TO_INITIAL_NETWORK, auto1.getRanges().get(0).getRangeType());
assertEquals(-10, auto1.getRanges().get(0).getMinTap());
assertEquals(10, auto1.getRanges().get(0).getMaxTap());
assertEquals(8, auto1.getInitialTap());
}
@Test
void testImportRasAvailableForSpecificCountry() throws IOException {
setUpWithTimestamp("/cracs/CIM_21_5_2.xml", baseNetwork, OffsetDateTime.parse("2021-04-02T20:00Z"));
// RA_1
assertNetworkActionImported("RA_1", Set.of("_2844585c-0d35-488d-a449-685bcd57afbf", "_ffbabc27-1ccd-4fdc-b037-e341706c8d29"), false);
NetworkAction ra1 = importedCrac.getNetworkAction("RA_1");
assertEquals(1, ra1.getUsageRules().size());
assertTrue(ra1.getUsageRules().iterator().next() instanceof OnFlowConstraintInCountry);
assertEquals(preventiveInstant, ra1.getUsageRules().iterator().next().getInstant());
assertEquals(Country.PT, ((OnFlowConstraintInCountry) ra1.getUsageRules().iterator().next()).getCountry());
assertEquals(2, ra1.getElementaryActions().size());
assertTrue(ra1.getElementaryActions().stream()
.filter(GeneratorAction.class::isInstance)
.map(GeneratorAction.class::cast)
.anyMatch(is -> is.getGeneratorId().equals("_2844585c-0d35-488d-a449-685bcd57afbf") && is.getActivePowerValue().getAsDouble() == 380)
);
assertTrue(ra1.getElementaryActions().stream()
.filter(TerminalsConnectionAction.class::isInstance)
.map(TerminalsConnectionAction.class::cast)
.anyMatch(ta -> ta.getElementId().equals("_ffbabc27-1ccd-4fdc-b037-e341706c8d29") && !ta.isOpen())
);
// RA_2
assertNetworkActionImported("RA_2", Set.of("_e8a7eaec-51d6-4571-b3d9-c36d52073c33", "_b58bf21a-096a-4dae-9a01-3f03b60c24c7"), false);
NetworkAction ra2 = importedCrac.getNetworkAction("RA_2");
assertEquals(1, ra2.getUsageRules().size());
assertTrue(ra2.getUsageRules().iterator().next() instanceof OnFlowConstraintInCountry);
assertEquals(curativeInstant, ra2.getUsageRules().iterator().next().getInstant());
assertEquals(Country.ES, ((OnFlowConstraintInCountry) ra2.getUsageRules().iterator().next()).getCountry());
assertEquals(2, ra2.getElementaryActions().size());
assertTrue(ra2.getElementaryActions().stream()
.filter(PhaseTapChangerTapPositionAction.class::isInstance)
.map(PhaseTapChangerTapPositionAction.class::cast)
.anyMatch(ps -> ps.getTransformerId().equals("_e8a7eaec-51d6-4571-b3d9-c36d52073c33") && ps.getTapPosition() == -19) // before it was the tap position before normalization, now it is after normalization
);
assertTrue(ra2.getElementaryActions().stream()
.filter(TerminalsConnectionAction.class::isInstance)
.map(TerminalsConnectionAction.class::cast)
.anyMatch(ta -> ta.getElementId().equals("_b58bf21a-096a-4dae-9a01-3f03b60c24c7") && ta.isOpen())
);
// RA_3
assertNetworkActionImported("RA_3", Set.of("_b94318f6-6d24-4f56-96b9-df2531ad6543", "_1dc9afba-23b5-41a0-8540-b479ed8baf4b"), false);
NetworkAction ra3 = importedCrac.getNetworkAction("RA_3");
assertEquals(2, ra3.getUsageRules().size());
assertTrue(
ra3.getUsageRules().stream()
.filter(OnInstant.class::isInstance)
.map(OnInstant.class::cast)
.anyMatch(ur -> ur.getInstant().isPreventive())
);
assertTrue(
ra3.getUsageRules().stream()
.filter(OnContingencyState.class::isInstance)
.map(OnContingencyState.class::cast)
.anyMatch(ur -> ur.getInstant().isCurative() && ur.getContingency().getId().equals("CO_1"))
);
assertEquals(2, ra3.getElementaryActions().size());
assertTrue(ra3.getElementaryActions().stream()
.filter(PhaseTapChangerTapPositionAction.class::isInstance)
.map(PhaseTapChangerTapPositionAction.class::cast)
.anyMatch(ps -> ps.getTransformerId().equals("_b94318f6-6d24-4f56-96b9-df2531ad6543") && ps.getTapPosition() == 13) // before it was the tap position before normalization, now it is after normalization
);
assertTrue(ra3.getElementaryActions().stream()
.filter(GeneratorAction.class::isInstance)
.map(GeneratorAction.class::cast)
.anyMatch(is -> is.getGeneratorId().equals("_1dc9afba-23b5-41a0-8540-b479ed8baf4b") && is.getActivePowerValue().getAsDouble() == 480)
);
// RA_4
assertNetworkActionImported("RA_4", Set.of("_b94318f6-6d24-4f56-96b9-df2531ad6543", "_1dc9afba-23b5-41a0-8540-b479ed8baf4b"), false);
NetworkAction ra4 = importedCrac.getNetworkAction("RA_4");
assertEquals(2, ra4.getUsageRules().size());
assertTrue(
ra4.getUsageRules().stream()
.filter(OnFlowConstraintInCountry.class::isInstance)
.map(OnFlowConstraintInCountry.class::cast)
.anyMatch(ur -> ur.getInstant().isPreventive() && ur.getContingency().isEmpty() && ur.getCountry().equals(Country.FR))
);
assertTrue(
ra4.getUsageRules().stream()
.filter(OnFlowConstraintInCountry.class::isInstance)
.map(OnFlowConstraintInCountry.class::cast)
.anyMatch(ur -> ur.getInstant().isCurative() && ur.getContingency().orElseThrow().getId().equals("CO_1") && ur.getCountry().equals(Country.FR))
);
assertEquals(2, ra4.getElementaryActions().size());
assertTrue(ra4.getElementaryActions().stream()
.filter(PhaseTapChangerTapPositionAction.class::isInstance)
.map(PhaseTapChangerTapPositionAction.class::cast)
.anyMatch(ps -> ps.getTransformerId().equals("_b94318f6-6d24-4f56-96b9-df2531ad6543") && ps.getTapPosition() == 13) // before it was the tap position before normalization, now it is after normalization
);
assertTrue(ra4.getElementaryActions().stream()
.filter(GeneratorAction.class::isInstance)
.map(GeneratorAction.class::cast)
.anyMatch(is -> is.getGeneratorId().equals("_1dc9afba-23b5-41a0-8540-b479ed8baf4b") && is.getActivePowerValue().getAsDouble() == 480)
);
// RA_5
assertNetworkActionImported("RA_4", Set.of("_b94318f6-6d24-4f56-96b9-df2531ad6543", "_1dc9afba-23b5-41a0-8540-b479ed8baf4b"), false);
NetworkAction ra5 = importedCrac.getNetworkAction("RA_5");
assertEquals(3, ra5.getUsageRules().size());
assertTrue(
ra5.getUsageRules().stream()
.filter(OnFlowConstraintInCountry.class::isInstance)
.map(OnFlowConstraintInCountry.class::cast)
.anyMatch(ur -> ur.getInstant().isPreventive() && ur.getContingency().isEmpty() && ur.getCountry().equals(Country.FR))
);
assertTrue(
ra5.getUsageRules().stream()
.filter(OnFlowConstraintInCountry.class::isInstance)
.map(OnFlowConstraintInCountry.class::cast)
.anyMatch(ur -> ur.getInstant().isCurative() && ur.getContingency().orElseThrow().getId().equals("CO_1") && ur.getCountry().equals(Country.FR))
);
assertTrue(
ra5.getUsageRules().stream()
.filter(OnFlowConstraintInCountry.class::isInstance)
.map(OnFlowConstraintInCountry.class::cast)
.anyMatch(ur -> ur.getInstant().isCurative() && ur.getContingency().orElseThrow().getId().equals("CO_2") && ur.getCountry().equals(Country.FR))
);
assertEquals(2, ra5.getElementaryActions().size());
assertTrue(ra5.getElementaryActions().stream()
.filter(PhaseTapChangerTapPositionAction.class::isInstance)
.map(PhaseTapChangerTapPositionAction.class::cast)
.anyMatch(ps -> ps.getTransformerId().equals("_b94318f6-6d24-4f56-96b9-df2531ad6543") && ps.getTapPosition() == 13) // before it was the tap position before normalization, now it is after normalization
);
assertTrue(ra5.getElementaryActions().stream()
.filter(GeneratorAction.class::isInstance)
.map(GeneratorAction.class::cast)
.anyMatch(is -> is.getGeneratorId().equals("_1dc9afba-23b5-41a0-8540-b479ed8baf4b") && is.getActivePowerValue().getAsDouble() == 480)
);
}
@Test
void testImportOnFlowConstraintRepeatedRa() throws IOException {
setUpWithTimestamp("/cracs/CIM_21_5_3.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"));
// PRA_CRA_1
assertPstRangeActionImported("PRA_CRA_1", "_e8a7eaec-51d6-4571-b3d9-c36d52073c33", true);
PstRangeAction praCra1 = importedCrac.getPstRangeAction("PRA_CRA_1");
assertEquals(8, praCra1.getUsageRules().size());
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - TWO - Co-one-2 - outage");
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - TWO - Co-one-2 - auto");
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - TWO - Co-one-2 - curative");
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - TWO - Co-one-3 - outage");
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - TWO - Co-one-3 - auto");
assertHasOnFlowConstraintUsageRule(praCra1, preventiveInstant, "GHIOL_QSDFGH_1_220 - TWO - Co-one-3 - curative");
assertHasOnFlowConstraintUsageRule(praCra1, curativeInstant, "GHIOL_QSDFGH_1_220 - TWO - Co-one-2 - curative");
assertHasOnFlowConstraintUsageRule(praCra1, curativeInstant, "GHIOL_QSDFGH_1_220 - TWO - Co-one-3 - curative");
assertEquals(1, praCra1.getRanges().size());
assertEquals(RangeType.RELATIVE_TO_INITIAL_NETWORK, praCra1.getRanges().get(0).getRangeType());
assertEquals(-10, praCra1.getRanges().get(0).getMinTap());
assertEquals(10, praCra1.getRanges().get(0).getMaxTap());
assertEquals(8, praCra1.getInitialTap());
}
@Test
void testImportAngleCnecs() throws IOException {
setUpWithTimestamp("/cracs/CIM_21_7_1.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"));
// -- Imported
// Angle cnec and associated RA imported :
assertAngleCnecImportedWithContingency("AngleCnec1", "Co-1", Set.of("_8d8a82ba-b5b0-4e94-861a-192af055f2b8", "_b7998ae6-0cc6-4dfe-8fec-0b549b07b6c3"), 30.);
assertNetworkActionImported("RA1", Set.of("_1dc9afba-23b5-41a0-8540-b479ed8baf4b", "_2844585c-0d35-488d-a449-685bcd57afbf"), false);
assertHasOnAngleUsageRule("RA1", "AngleCnec1");
assertEquals(1, importedCrac.getRemedialAction("RA1").getUsageRules().size());
// -- Partially imported
// Angle cnec without an associated RA :
assertAngleCnecImportedWithContingency("AngleCnec3", "Co-1", Set.of("_8d8a82ba-b5b0-4e94-861a-192af055f2b8", "_b7998ae6-0cc6-4dfe-8fec-0b549b07b6c3"), 40.);
// Angle cnec with ill defined RA :
assertAngleCnecImportedWithContingency("AngleCnec11", "Co-1", Set.of("_8d8a82ba-b5b0-4e94-861a-192af055f2b8", "_b7998ae6-0cc6-4dfe-8fec-0b549b07b6c3"), 60.);
assertRemedialActionNotImported("RA11", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK);
// -- Not imported
assertAngleCnecNotImported("AngleCnec2", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("RA2", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("Angle4", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("Angle5", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("RA6", ImportStatus.INCONSISTENCY_IN_DATA);
assertAngleCnecNotImported("AngleCnec7", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("RA7", ImportStatus.INCONSISTENCY_IN_DATA);
assertAngleCnecNotImported("AngleCnec8", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK);
assertRemedialActionNotImported("RA8", ImportStatus.INCONSISTENCY_IN_DATA);
assertAngleCnecNotImported("AngleCnec9", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("RA9", ImportStatus.INCONSISTENCY_IN_DATA);
assertAngleCnecNotImported("AngleCnec10", ImportStatus.INCONSISTENCY_IN_DATA);
assertRemedialActionNotImported("RA10", ImportStatus.INCONSISTENCY_IN_DATA);
}
@Test
void testFilterOnTimeseries() throws IOException {
setUpWithTimeseriesMrids("/cracs/CIM_2_timeseries.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"), Collections.emptySet());
assertEquals(2, importedCrac.getContingencies().size());
setUpWithTimeseriesMrids("/cracs/CIM_2_timeseries.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of("TimeSeries1", "TimeSeries2", "TimeSeries3"));
assertEquals(2, importedCrac.getContingencies().size());
assertEquals(2, cracCreationContext.getCreationReport().getReport().size());
assertEquals("[WARN] Requested TimeSeries mRID \"TimeSeries3\" in CimCracCreationParameters was not found in the CRAC file.", cracCreationContext.getCreationReport().getReport().get(0));
assertEquals("CRAC was successfully imported with 2 contingencies, 0 FlowCNECs, 0 AngleCNECs, 0 VoltageCNECs and 0 remedial actions (0 range actions and 0 network actions).", cracCreationContext.getCreationReport().getReport().get(1));
setUpWithTimeseriesMrids("/cracs/CIM_2_timeseries.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of("TimeSeries1"));
assertEquals(1, importedCrac.getContingencies().size());
assertNotNull(importedCrac.getContingency("Co-1"));
setUpWithTimeseriesMrids("/cracs/CIM_2_timeseries.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of("TimeSeries2"));
assertEquals(1, importedCrac.getContingencies().size());
assertNotNull(importedCrac.getContingency("Co-2"));
}
@Test
void testImportCnecsWithSameMsMrid() throws IOException {
setUpWithTimestamp("/cracs/CIM_21_2_1_mrid.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"));
assertEquals(10, importedCrac.getFlowCnecs().size());
// CNEC 3
assertCnecImported("CNEC-2", Set.of("CNEC-3 - preventive", "CNEC-3 - Co-1 - auto", "CNEC-3 - Co-2 - auto"));
assertTrue(cracCreationContext.getMonitoredSeriesCreationContext("CNEC-2").isAltered());
// CNEC 4
assertCnecImported("CNEC-4", Set.of("CNEC-4 - preventive", "CNEC-4 - Co-1 - curative", "CNEC-4 - Co-2 - curative",
"CNEC-5 - ONE - MONITORED - preventive", "CNEC-5 - ONE - MONITORED - Co-1 - curative",
"CNEC-6 - MONITORED - preventive", "CNEC-6 - MONITORED - Co-1 - outage"));
assertFalse(cracCreationContext.getMonitoredSeriesCreationContext("CNEC-4").isAltered());
}
private VoltageThreshold mockVoltageThreshold(Double min, Double max) {
VoltageThreshold threshold = Mockito.mock(VoltageThreshold.class);
Mockito.when(threshold.getUnit()).thenReturn(Unit.KILOVOLT);
Mockito.when(threshold.getMin()).thenReturn(min);
Mockito.when(threshold.getMax()).thenReturn(max);
return threshold;
}
@Test
void testImportVoltageCnecs() throws IOException {
Set<String> monitoredElements = Set.of("_d77b61ef-61aa-4b22-95f6-b56ca080788d", "_2844585c-0d35-488d-a449-685bcd57afbf", "_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0");
Map<String, VoltageMonitoredContingenciesAndThresholds> monitoredStatesAndThresholds = Map.of(
PREVENTIVE_INSTANT_ID, new VoltageMonitoredContingenciesAndThresholds(null, Map.of(220., mockVoltageThreshold(220., 230.))),
CURATIVE_INSTANT_ID, new VoltageMonitoredContingenciesAndThresholds(Set.of("Co-1-name", "Co-4-name"), Map.of(220., mockVoltageThreshold(210., 240.))),
OUTAGE_INSTANT_ID, new VoltageMonitoredContingenciesAndThresholds(Set.of("Co-3-name"), Map.of(220., mockVoltageThreshold(200., null))),
AUTO_INSTANT_ID, new VoltageMonitoredContingenciesAndThresholds(Set.of("Co-2-name"), Map.of(220., mockVoltageThreshold(null, null)))
);
VoltageCnecsCreationParameters voltageCnecsCreationParameters = new VoltageCnecsCreationParameters(monitoredStatesAndThresholds, monitoredElements);
CracCreationParameters params = new CracCreationParameters();
CimCracCreationParameters cimParams = new CimCracCreationParameters();
cimParams.setVoltageCnecsCreationParameters(voltageCnecsCreationParameters);
params.addExtension(CimCracCreationParameters.class, cimParams);
params.getExtension(CimCracCreationParameters.class).setTimestamp(OffsetDateTime.parse("2021-04-01T23:00Z"));
setUp("/cracs/CIM_21_1_1.xml", baseNetwork, params);
assertEquals(3, importedCrac.getVoltageCnecs().size());
assertNotNull(importedCrac.getVoltageCnec("[VC] _d77b61ef-61aa-4b22-95f6-b56ca080788d - preventive"));
assertNotNull(importedCrac.getVoltageCnec("[VC] _d77b61ef-61aa-4b22-95f6-b56ca080788d - Co-1 - curative"));
assertNotNull(importedCrac.getVoltageCnec("[VC] _d77b61ef-61aa-4b22-95f6-b56ca080788d - Co-3 - outage"));
assertEquals(7, cracCreationContext.getVoltageCnecCreationContexts().size());
assertEquals(8, cracCreationContext.getCreationReport().getReport().size());
assertTrue(cracCreationContext.getCreationReport().getReport().contains("[REMOVED] VoltageCnec with network element \"_2844585c-0d35-488d-a449-685bcd57afbf\", instant \"all\" and contingency \"all\" was not imported: INCONSISTENCY_IN_DATA. Element _2844585c-0d35-488d-a449-685bcd57afbf is not a voltage level."));
assertTrue(cracCreationContext.getCreationReport().getReport().contains("[REMOVED] VoltageCnec with network element \"_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0\", instant \"all\" and contingency \"all\" was not imported: INCONSISTENCY_IN_DATA. Element _a708c3bc-465d-4fe7-b6ef-6fa6408a62b0 is not a voltage level."));
assertTrue(cracCreationContext.getCreationReport().getReport().contains("[REMOVED] VoltageCnec with network element \"all\", instant \"all\" and contingency \"Co-4-name\" was not imported: OTHER. Contingency does not exist in the CRAC or could not be imported."));
assertTrue(cracCreationContext.getCreationReport().getReport().contains("[REMOVED] VoltageCnec with network element \"_d77b61ef-61aa-4b22-95f6-b56ca080788d\", instant \"auto\" and contingency \"Co-2-name\" was not imported: INCONSISTENCY_IN_DATA. Cannot add a threshold without min nor max values. Please use withMin() or withMax().."));
}
@Test
void testImportCnecOnRightSide() throws IOException {
CracCreationParameters cracCreationParameters = new CracCreationParameters();
cracCreationParameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_TWO);
cracCreationParameters.addExtension(CimCracCreationParameters.class, new CimCracCreationParameters());
cracCreationParameters.getExtension(CimCracCreationParameters.class).setTimestamp(OffsetDateTime.parse("2021-04-01T23:00Z"));
setUp("/cracs/CIM_21_2_1.xml", baseNetwork, cracCreationParameters);
assertEquals(8, importedCrac.getFlowCnecs().size());
// CNEC 2
assertCnecNotImported("CNEC-2", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK);
// CNEC 3
assertCnecImported("CNEC-3", Set.of("CNEC-3 - preventive", "CNEC-3 - Co-1 - auto", "CNEC-3 - Co-2 - auto"));
assertHasOneThreshold("CNEC-3 - preventive", TwoSides.TWO, Unit.MEGAWATT, -3, 3);
assertHasOneThreshold("CNEC-3 - Co-1 - auto", TwoSides.TWO, Unit.AMPERE, -3, 3);
assertHasOneThreshold("CNEC-3 - Co-2 - auto", TwoSides.TWO, Unit.AMPERE, -3, 3);
// CNEC 4
assertCnecImported("CNEC-4", Set.of("CNEC-4 - preventive", "CNEC-4 - Co-1 - curative", "CNEC-4 - Co-2 - curative"));
assertHasOneThreshold("CNEC-4 - preventive", TwoSides.TWO, Unit.PERCENT_IMAX, -0.04, 0.04);
assertHasOneThreshold("CNEC-4 - Co-1 - curative", TwoSides.TWO, Unit.PERCENT_IMAX, -0.04, 0.04);
assertHasOneThreshold("CNEC-4 - Co-2 - curative", TwoSides.TWO, Unit.PERCENT_IMAX, -0.04, 0.04);
// CNEC 5
assertCnecImported("MNEC-1", Set.of("CNEC-5 - ONE - MONITORED - preventive", "CNEC-5 - ONE - MONITORED - Co-1 - curative"));
assertHasOneThreshold("CNEC-5 - ONE - MONITORED - preventive", TwoSides.ONE, Unit.PERCENT_IMAX, -0.05, 0.05);
assertHasOneThreshold("CNEC-5 - ONE - MONITORED - Co-1 - curative", TwoSides.ONE, Unit.PERCENT_IMAX, -0.05, 0.05);
// CNEC 6 - Cannot be imported because has no Imax on right side
assertCnecNotImported("MNEC-2", ImportStatus.OTHER);
}
@Test
void testImportCnecOnBothSides() throws IOException {
CracCreationParameters cracCreationParameters = new CracCreationParameters();
cracCreationParameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_BOTH_SIDES);
cracCreationParameters.addExtension(CimCracCreationParameters.class, new CimCracCreationParameters());
cracCreationParameters.getExtension(CimCracCreationParameters.class).setTimestamp(OffsetDateTime.parse("2021-04-01T23:00Z"));
setUp("/cracs/CIM_21_2_1.xml", baseNetwork, cracCreationParameters);
assertEquals(10, importedCrac.getFlowCnecs().size());
// CNEC 2
assertCnecNotImported("CNEC-2", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK);
// CNEC 3
assertCnecImported("CNEC-3", Set.of("CNEC-3 - preventive", "CNEC-3 - Co-1 - auto", "CNEC-3 - Co-2 - auto"));
assertHasTwoThresholds("CNEC-3 - preventive", Unit.MEGAWATT, -3, 3);
assertHasTwoThresholds("CNEC-3 - Co-1 - auto", Unit.AMPERE, -3, 3);
assertHasTwoThresholds("CNEC-3 - Co-2 - auto", Unit.AMPERE, -3, 3);
// CNEC 4
assertCnecImported("CNEC-4", Set.of("CNEC-4 - preventive", "CNEC-4 - Co-1 - curative", "CNEC-4 - Co-2 - curative"));
assertHasTwoThresholds("CNEC-4 - preventive", Unit.PERCENT_IMAX, -0.04, 0.04);
assertHasTwoThresholds("CNEC-4 - Co-1 - curative", Unit.PERCENT_IMAX, -0.04, 0.04);
assertHasTwoThresholds("CNEC-4 - Co-2 - curative", Unit.PERCENT_IMAX, -0.04, 0.04);
// CNEC 5
assertCnecImported("MNEC-1", Set.of("CNEC-5 - ONE - MONITORED - preventive", "CNEC-5 - ONE - MONITORED - Co-1 - curative"));
assertHasOneThreshold("CNEC-5 - ONE - MONITORED - preventive", TwoSides.ONE, Unit.PERCENT_IMAX, -0.05, 0.05);
assertHasOneThreshold("CNEC-5 - ONE - MONITORED - Co-1 - curative", TwoSides.ONE, Unit.PERCENT_IMAX, -0.05, 0.05);
// CNEC 6 - Only one threshold because has only Imax on ONE side in network
assertCnecImported("MNEC-2", Set.of("CNEC-6 - MONITORED - preventive", "CNEC-6 - MONITORED - Co-1 - outage"));
assertHasOneThreshold("CNEC-6 - MONITORED - preventive", TwoSides.ONE, Unit.PERCENT_IMAX, -0.06, 0.06);
assertHasOneThreshold("CNEC-6 - MONITORED - Co-1 - outage", TwoSides.ONE, Unit.PERCENT_IMAX, -0.06, 0.06);
}
@Test
void testTransformerCnecThresholds() throws IOException {
CracCreationParameters cracCreationParameters = new CracCreationParameters();
cracCreationParameters.addExtension(CimCracCreationParameters.class, new CimCracCreationParameters());
// Preventive threshold is in %Imax, should be created depending on default monitored side
// Outage threshold is in MW, should be created depending on default monitored side
// Curative threshold is in A, should be defined on high voltage level side
cracCreationParameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_BOTH_SIDES);
cracCreationParameters.getExtension(CimCracCreationParameters.class).setTimestamp(OffsetDateTime.parse("2021-04-02T20:00Z"));
setUp("/cracs/CIM_21_5_2.xml", baseNetwork, cracCreationParameters);
assertHasTwoThresholds("OJLJJ_5_400_220 - preventive", Unit.PERCENT_IMAX, -1., 1.);
assertHasTwoThresholds("OJLJJ_5_400_220 - CO_2 - outage", Unit.MEGAWATT, -1000., 1000.);
assertHasTwoThresholds("OJLJJ_5_400_220 - CO_3 - outage", Unit.MEGAWATT, -1000., 1000.);
assertHasOneThreshold("OJLJJ_5_400_220 - CO_2 - curative", TwoSides.TWO, Unit.AMPERE, -2000., 2000.);
assertHasOneThreshold("OJLJJ_5_400_220 - CO_3 - curative", TwoSides.TWO, Unit.AMPERE, -2000., 2000.);
cracCreationParameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_ONE);
cracCreationParameters.getExtension(CimCracCreationParameters.class).setTimestamp(OffsetDateTime.parse("2021-04-02T03:00Z"));
setUp("/cracs/CIM_21_5_2.xml", baseNetwork, cracCreationParameters);
assertHasOneThreshold("OJLJJ_5_400_220 - preventive", TwoSides.ONE, Unit.PERCENT_IMAX, -1., 1.);
assertHasOneThreshold("OJLJJ_5_400_220 - CO_2 - outage", TwoSides.ONE, Unit.MEGAWATT, -1000., 1000.);
assertHasOneThreshold("OJLJJ_5_400_220 - CO_3 - outage", TwoSides.ONE, Unit.MEGAWATT, -1000., 1000.);
assertHasOneThreshold("OJLJJ_5_400_220 - CO_2 - curative", TwoSides.TWO, Unit.AMPERE, -2000., 2000.);
assertHasOneThreshold("OJLJJ_5_400_220 - CO_3 - curative", TwoSides.TWO, Unit.AMPERE, -2000., 2000.);
cracCreationParameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_TWO);
cracCreationParameters.getExtension(CimCracCreationParameters.class).setTimestamp(OffsetDateTime.parse("2021-04-02T05:00Z"));
setUp("/cracs/CIM_21_5_2.xml", baseNetwork, cracCreationParameters);
assertHasOneThreshold("OJLJJ_5_400_220 - preventive", TwoSides.TWO, Unit.PERCENT_IMAX, -1., 1.);
assertHasOneThreshold("OJLJJ_5_400_220 - CO_2 - outage", TwoSides.TWO, Unit.MEGAWATT, -1000., 1000.);
assertHasOneThreshold("OJLJJ_5_400_220 - CO_3 - outage", TwoSides.TWO, Unit.MEGAWATT, -1000., 1000.);
assertHasOneThreshold("OJLJJ_5_400_220 - CO_2 - curative", TwoSides.TWO, Unit.AMPERE, -2000., 2000.);
assertHasOneThreshold("OJLJJ_5_400_220 - CO_3 - curative", TwoSides.TWO, Unit.AMPERE, -2000., 2000.);
}
private void assertCnecHasOutageDuplicate(String flowCnecId) {
FlowCnec flowCnec = importedCrac.getFlowCnec(flowCnecId);
assertNotNull(flowCnec);
FlowCnec duplicate = importedCrac.getFlowCnec(flowCnec.getId() + " - OUTAGE DUPLICATE");
assertNotNull(duplicate);
assertEquals(flowCnec.getNetworkElement().getId(), duplicate.getNetworkElement().getId());
assertEquals(flowCnec.getState().getContingency(), duplicate.getState().getContingency());
assertEquals(InstantKind.OUTAGE, duplicate.getState().getInstant().getKind());
assertEquals(flowCnec.isOptimized(), duplicate.isOptimized());
assertEquals(flowCnec.isMonitored(), duplicate.isMonitored());
assertEquals(flowCnec.getReliabilityMargin(), duplicate.getReliabilityMargin(), 1e-6);
assertEquals(flowCnec.getIMax(TwoSides.ONE), duplicate.getIMax(TwoSides.ONE), 1e-6);
assertEquals(flowCnec.getIMax(TwoSides.TWO), duplicate.getIMax(TwoSides.TWO), 1e-6);
assertEquals(flowCnec.getNominalVoltage(TwoSides.ONE), duplicate.getNominalVoltage(TwoSides.ONE), 1e-6);
assertEquals(flowCnec.getNominalVoltage(TwoSides.TWO), duplicate.getNominalVoltage(TwoSides.TWO), 1e-6);
assertEquals(flowCnec.getThresholds(), duplicate.getThresholds());
assertTrue(cracCreationContext.getCreationReport().getReport().contains(String.format("[ADDED] CNEC \"%s\" has no associated automaton. It will be cloned on the OUTAGE instant in order to be secured during preventive RAO.", flowCnecId)));
}
@Test
void importAndDuplicateAutoCnecs() throws IOException {
CracCreationParameters cracCreationParameters = new CracCreationParameters();
cracCreationParameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_BOTH_SIDES);
cracCreationParameters.addExtension(CimCracCreationParameters.class, new CimCracCreationParameters());
cracCreationParameters.getExtension(CimCracCreationParameters.class).setTimestamp(OffsetDateTime.parse("2021-04-01T23:00Z"));
setUp("/cracs/CIM_21_2_1_ARA.xml", baseNetwork, cracCreationParameters);
assertEquals(12, importedCrac.getCnecs().size());
assertCnecHasOutageDuplicate("CNEC-4 - Co-1 - auto");
assertCnecHasOutageDuplicate("CNEC-4 - Co-2 - auto");
}
@Test
void testPermissiveImports() throws IOException {
// Test that we can import contingencies from B56 & B57, and CNECs from B56
setUpWithSpeed("/cracs/CIM_21_5_1_permissive.xml", baseNetwork, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of(new RangeActionSpeed("AUTO_1", 1)));
// Contingencies
assertEquals(3, importedCrac.getContingencies().size());
assertContingencyImported("Co-one-1", "OIUYTR-QSCV-1 400 kV", Set.of("_ffbabc27-1ccd-4fdc-b037-e341706c8d29"), false);
assertContingencyImported("Co-one-2", "OIUYTR-LKJHGOI-1 400 kV", Set.of("_b58bf21a-096a-4dae-9a01-3f03b60c24c7"), false);
assertContingencyImported("Co-one-3", "AZERTY-LKJHG-1 400 kV", Set.of("_df16b3dd-c905-4a6f-84ee-f067be86f5da"), false);
// FlowCNECs
assertEquals(14, importedCrac.getFlowCnecs().size());
assertCnecImported("TUU_MR_31", Set.of(
"GHIOL_QSDFGH_1_220 - TWO - Co-one-1 - auto", "GHIOL_QSDFGH_1_220 - TWO - preventive", "GHIOL_QSDFGH_1_220 - TWO - Co-one-1 - outage",
"GHIOL_QSDFGH_1_220 - TWO - Co-one-3 - outage", "GHIOL_QSDFGH_1_220 - TWO - Co-one-3 - curative", "GHIOL_QSDFGH_1_220 - TWO - Co-one-2 - curative",
"GHIOL_QSDFGH_1_220 - TWO - Co-one-3 - auto", "GHIOL_QSDFGH_1_220 - TWO - Co-one-1 - curative", "GHIOL_QSDFGH_1_220 - TWO - Co-one-2 - auto",
"GHIOL_QSDFGH_1_220 - TWO - Co-one-2 - outage"
));
assertHasOneThreshold("GHIOL_QSDFGH_1_220 - TWO - preventive", TwoSides.TWO, Unit.PERCENT_IMAX, -1, 1);
assertHasOneThreshold("GHIOL_QSDFGH_1_220 - TWO - Co-one-1 - outage", TwoSides.TWO, Unit.PERCENT_IMAX, -1.15, 1.15);
assertHasOneThreshold("GHIOL_QSDFGH_1_220 - TWO - Co-one-2 - auto", TwoSides.TWO, Unit.PERCENT_IMAX, -1.1, 1.1);
assertHasOneThreshold("GHIOL_QSDFGH_1_220 - TWO - Co-one-3 - curative", TwoSides.TWO, Unit.PERCENT_IMAX, -1.05, 1.05);
assertCnecImported("TUU_MR_56", Set.of(
"GHIOL_QSRBJH_1_400 - TWO - Co-one-1 - auto", "GHIOL_QSRBJH_1_400 - TWO - preventive", "GHIOL_QSRBJH_1_400 - TWO - Co-one-1 - outage",
"GHIOL_QSRBJH_1_400 - TWO - Co-one-1 - curative"
));
assertHasOneThreshold("GHIOL_QSRBJH_1_400 - TWO - preventive", TwoSides.TWO, Unit.PERCENT_IMAX, -1, 1);
assertHasOneThreshold("GHIOL_QSRBJH_1_400 - TWO - Co-one-1 - outage", TwoSides.TWO, Unit.PERCENT_IMAX, -1.5, 1.5);
assertHasOneThreshold("GHIOL_QSRBJH_1_400 - TWO - Co-one-1 - auto", TwoSides.TWO, Unit.PERCENT_IMAX, -1.3, 1.3);
assertHasOneThreshold("GHIOL_QSRBJH_1_400 - TWO - Co-one-1 - curative", TwoSides.TWO, Unit.PERCENT_IMAX, -1.05, 1.05);
// PRA_1
assertPstRangeActionImported("PRA_1", "_a708c3bc-465d-4fe7-b6ef-6fa6408a62b0", false);
PstRangeAction pra1 = importedCrac.getPstRangeAction("PRA_1");
assertEquals(10, pra1.getUsageRules().size());
// PRA_CRA_1
assertPstRangeActionImported("PRA_CRA_1", "_e8a7eaec-51d6-4571-b3d9-c36d52073c33", true);
PstRangeAction praCra1 = importedCrac.getPstRangeAction("PRA_CRA_1");
assertEquals(8, praCra1.getUsageRules().size());
// AUTO_1
assertPstRangeActionImported("AUTO_1", "_e8a7eaec-51d6-4571-b3d9-c36d52073c33", true);
PstRangeAction auto1 = importedCrac.getPstRangeAction("AUTO_1");
assertEquals(4, auto1.getUsageRules().size());
}
@Test
void testImportHvdcAutomatonWithFullyConnectedHvdc() throws IOException {
Network network = loadNetworkWithHvdc();
setUpWithSpeed("/cracs/CIM_with_HVDC.xml", network, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of(new RangeActionSpeed("BBE2AA11 FFR3AA11 1", 1), new RangeActionSpeed("BBE2AA12 FFR3AA12 1", 2)));
Crac crac = cracCreationContext.getCrac();
assertEquals(2, crac.getHvdcRangeActions().size());
HvdcRangeAction hvdcRangeAction1 = crac.getHvdcRangeAction("HVDC-direction11 + HVDC-direction12 - BBE2AA11 FFR3AA11 1");
assertEquals(1, hvdcRangeAction1.getRanges().size());
assertEquals(-4000, hvdcRangeAction1.getRanges().iterator().next().getMin());
assertEquals(5000, hvdcRangeAction1.getRanges().iterator().next().getMax());
assertEquals(Optional.of("BBE2AA11 FFR3AA11 1 + BBE2AA12 FFR3AA12 1"), hvdcRangeAction1.getGroupId());
HvdcRangeAction hvdcRangeAction2 = crac.getHvdcRangeAction("HVDC-direction11 + HVDC-direction12 - BBE2AA12 FFR3AA12 1");
assertEquals(1, hvdcRangeAction2.getRanges().size());
assertEquals(-3000, hvdcRangeAction2.getRanges().iterator().next().getMin());
assertEquals(3500, hvdcRangeAction2.getRanges().iterator().next().getMax());
assertEquals(Optional.of("BBE2AA11 FFR3AA11 1 + BBE2AA12 FFR3AA12 1"), hvdcRangeAction2.getGroupId());
}
private static void disconnectHvdcLine(HvdcLine hvdcLine) {
hvdcLine.getConverterStation1().getTerminal().disconnect();
hvdcLine.getConverterStation2().getTerminal().disconnect();
}
@Test
void testImportHvdcAutomatonWithPartiallyConnectedHvdc1() throws IOException {
Network network = loadNetworkWithHvdc();
disconnectHvdcLine(network.getHvdcLine("BBE2AA11 FFR3AA11 1"));
setUpWithSpeed("/cracs/CIM_with_HVDC.xml", network, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of(new RangeActionSpeed("BBE2AA11 FFR3AA11 1", 1), new RangeActionSpeed("BBE2AA12 FFR3AA12 1", 2)));
Crac crac = cracCreationContext.getCrac();
assertEquals(1, crac.getHvdcRangeActions().size());
HvdcRangeAction hvdcRangeAction = crac.getHvdcRangeAction("HVDC-direction11 + HVDC-direction12 - BBE2AA12 FFR3AA12 1");
assertEquals(1, hvdcRangeAction.getRanges().size());
assertEquals(-3000, hvdcRangeAction.getRanges().iterator().next().getMin());
assertEquals(3500, hvdcRangeAction.getRanges().iterator().next().getMax());
assertEquals(Optional.of("BBE2AA12 FFR3AA12 1"), hvdcRangeAction.getGroupId());
assertEquals(3, cracCreationContext.getCreationReport().getReport().size());
assert cracCreationContext.getCreationReport().getReport().contains("[ALTERED] RemedialAction_Series \"HVDC-direction11\" was modified: HVDC line BBE2AA11 FFR3AA11 1 has terminals 1 and 2 disconnected. ");
assert cracCreationContext.getCreationReport().getReport().contains("[ALTERED] RemedialAction_Series \"HVDC-direction12\" was modified: HVDC line BBE2AA11 FFR3AA11 1 has terminals 1 and 2 disconnected. ");
}
@Test
void testImportHvdcAutomatonWithPartiallyConnectedHvdc2() throws IOException {
Network network = loadNetworkWithHvdc();
disconnectHvdcLine(network.getHvdcLine("BBE2AA12 FFR3AA12 1"));
setUpWithSpeed("/cracs/CIM_with_HVDC.xml", network, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of(new RangeActionSpeed("BBE2AA11 FFR3AA11 1", 1), new RangeActionSpeed("BBE2AA12 FFR3AA12 1", 2)));
Crac crac = cracCreationContext.getCrac();
assertEquals(1, crac.getHvdcRangeActions().size());
HvdcRangeAction hvdcRangeAction = crac.getHvdcRangeAction("HVDC-direction11 + HVDC-direction12 - BBE2AA11 FFR3AA11 1");
assertEquals(1, hvdcRangeAction.getRanges().size());
assertEquals(-4000, hvdcRangeAction.getRanges().iterator().next().getMin());
assertEquals(5000, hvdcRangeAction.getRanges().iterator().next().getMax());
assertEquals(Optional.of("BBE2AA11 FFR3AA11 1"), hvdcRangeAction.getGroupId());
assertEquals(3, cracCreationContext.getCreationReport().getReport().size());
assert cracCreationContext.getCreationReport().getReport().contains("[ALTERED] RemedialAction_Series \"HVDC-direction11\" was modified: HVDC line BBE2AA12 FFR3AA12 1 has terminals 1 and 2 disconnected. ");
assert cracCreationContext.getCreationReport().getReport().contains("[ALTERED] RemedialAction_Series \"HVDC-direction12\" was modified: HVDC line BBE2AA12 FFR3AA12 1 has terminals 1 and 2 disconnected. ");
}
@Test
void testImportHvdcAutomatonWithDisconnectedHvdc() throws IOException {
Network network = loadNetworkWithHvdc();
disconnectHvdcLine(network.getHvdcLine("BBE2AA11 FFR3AA11 1"));
disconnectHvdcLine(network.getHvdcLine("BBE2AA12 FFR3AA12 1"));
setUpWithSpeed("/cracs/CIM_with_HVDC.xml", network, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of(new RangeActionSpeed("BBE2AA11 FFR3AA11 1", 1), new RangeActionSpeed("BBE2AA12 FFR3AA12 1", 2)));
Crac crac = cracCreationContext.getCrac();
assertTrue(crac.getHvdcRangeActions().isEmpty());
assertEquals(3, cracCreationContext.getCreationReport().getReport().size());
assert cracCreationContext.getCreationReport().getReport().contains("[REMOVED] RemedialAction_Series \"HVDC-direction11\" was not imported: INCONSISTENCY_IN_DATA. All terminals on HVDC lines are disconnected.");
assert cracCreationContext.getCreationReport().getReport().contains("[REMOVED] RemedialAction_Series \"HVDC-direction12\" was not imported: INCONSISTENCY_IN_DATA. All terminals on HVDC lines are disconnected.");
}
@Test
void testImportHvdcAutomatonWithErrorInCimFullyConnected() throws IOException {
// only one error in any of the in/out nodes in CIM CRAC leads to not importing nay HVDC RA
Network network = loadNetworkWithHvdc();
disconnectHvdcLine(network.getHvdcLine("BBE2AA11 FFR3AA11 1"));
disconnectHvdcLine(network.getHvdcLine("BBE2AA12 FFR3AA12 1"));
setUpWithSpeed("/cracs/CIM_with_HVDC_error.xml", network, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of(new RangeActionSpeed("BBE2AA11 FFR3AA11 1", 1), new RangeActionSpeed("BBE2AA12 FFR3AA12 1", 2)));
Crac crac = cracCreationContext.getCrac();
assertTrue(crac.getHvdcRangeActions().isEmpty());
assertEquals(3, cracCreationContext.getCreationReport().getReport().size());
assert cracCreationContext.getCreationReport().getReport().contains("[REMOVED] RemedialAction_Series \"HVDC-direction12\" was not imported: INCONSISTENCY_IN_DATA. Other RemedialActionSeries in the same HVDC Series failed.");
assert cracCreationContext.getCreationReport().getReport().contains("[REMOVED] RemedialAction_Series \"HVDC-direction11\" was not imported: ELEMENT_NOT_FOUND_IN_NETWORK. Not a HVDC line.");
}
@Test
void testImportHvdcAutomatonWithPartiallyConnectedHvdc2AndInvalidContingencies() throws IOException {
Network network = loadNetworkWithHvdc();
disconnectHvdcLine(network.getHvdcLine("BBE2AA12 FFR3AA12 1"));
setUpWithSpeed("/cracs/CIM_with_HVDC_and_invalid_contingencies.xml", network, OffsetDateTime.parse("2021-04-01T23:00Z"), Set.of(new RangeActionSpeed("BBE2AA11 FFR3AA11 1", 1), new RangeActionSpeed("BBE2AA12 FFR3AA12 1", 2)));
Crac crac = cracCreationContext.getCrac();
assertEquals(1, crac.getHvdcRangeActions().size());
HvdcRangeAction hvdcRangeAction = crac.getHvdcRangeAction("HVDC-direction11 + HVDC-direction12 - BBE2AA11 FFR3AA11 1");
assertEquals(1, hvdcRangeAction.getRanges().size());
assertEquals(-4000, hvdcRangeAction.getRanges().iterator().next().getMin());
assertEquals(5000, hvdcRangeAction.getRanges().iterator().next().getMax());
assertEquals(Optional.of("BBE2AA11 FFR3AA11 1"), hvdcRangeAction.getGroupId());
assertEquals(4, cracCreationContext.getCreationReport().getReport().size());
assert cracCreationContext.getCreationReport().getReport().contains("[ALTERED] RemedialAction_Series \"HVDC-direction12\" was modified: HVDC line BBE2AA12 FFR3AA12 1 has terminals 1 and 2 disconnected; Contingencies Co-2 were not imported. ");
assert cracCreationContext.getCreationReport().getReport().contains("[ALTERED] RemedialAction_Series \"HVDC-direction11\" was modified: HVDC line BBE2AA12 FFR3AA12 1 has terminals 1 and 2 disconnected; Contingencies Co-2 were not imported. ");
}
}