FbConstraintCracCreatorTest.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.fbconstraint;
import com.powsybl.contingency.Contingency;
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.CracFactory;
import com.powsybl.openrao.data.crac.api.RaUsageLimits;
import com.powsybl.openrao.data.crac.api.cnec.FlowCnec;
import com.powsybl.iidm.network.TwoSides;
import com.powsybl.openrao.data.crac.api.networkaction.NetworkAction;
import com.powsybl.openrao.data.crac.api.parameters.CracCreationParameters;
import com.powsybl.openrao.data.crac.api.range.RangeType;
import com.powsybl.openrao.data.crac.api.range.TapRange;
import com.powsybl.openrao.data.crac.api.rangeaction.PstRangeAction;
import com.powsybl.openrao.data.crac.api.usagerule.OnContingencyState;
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.commons.api.ElementaryCreationContext;
import com.powsybl.openrao.data.crac.io.commons.api.ImportStatus;
import com.powsybl.openrao.data.crac.io.commons.api.stdcreationcontext.BranchCnecCreationContext;
import com.powsybl.openrao.data.crac.impl.NetworkActionImpl;
import com.powsybl.openrao.data.crac.io.fbconstraint.parameters.FbConstraintCracCreationParameters;
import com.powsybl.openrao.data.crac.loopflowextension.LoopFlowThreshold;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.time.OffsetDateTime;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Baptiste Seguinot{@literal <baptiste.seguinot at rte-france.com>}
*/
class FbConstraintCracCreatorTest {
private static final String PREVENTIVE_INSTANT_ID = "preventive";
private static final String OUTAGE_INSTANT_ID = "outage";
private static final String CURATIVE_INSTANT_ID = "curative";
private CracCreationParameters parameters;
private FbConstraintCreationContext creationContext;
@BeforeEach
public void setUp() {
parameters = new CracCreationParameters();
parameters.setCracFactoryName(CracFactory.findDefault().getName());
parameters.addExtension(FbConstraintCracCreationParameters.class, new FbConstraintCracCreationParameters());
}
private void assertCriticalBranchNotImported(String name, ImportStatus importStatus) {
BranchCnecCreationContext context = creationContext.getBranchCnecCreationContext(name);
assertNotNull(context);
assertFalse(context.isImported());
assertEquals(importStatus, context.getImportStatus());
assertTrue(context.getCreatedCnecsIds().isEmpty());
}
private void assertComplexVariantNotImported(String name, ImportStatus importStatus) {
ElementaryCreationContext context = creationContext.getRemedialActionCreationContext(name);
assertNotNull(context);
assertFalse(context.isImported());
assertEquals(importStatus, context.getImportStatus());
}
@Test
void importCracWithParameters() throws IOException {
Network network = Network.read("TestCase12Nodes_with_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_with_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
RaUsageLimits raUsageLimits = new RaUsageLimits();
raUsageLimits.setMaxRa(12);
parameters.addRaUsageLimitsForInstant("preventive", raUsageLimits);
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("without_RA.xml", getClass().getResourceAsStream("/merged_cb/without_RA.xml"), network, parameters);
assertTrue(creationContext.isCreationSuccessful());
assertEquals(12, creationContext.getCrac().getRaUsageLimits(creationContext.getCrac().getInstant("preventive")).getMaxRa());
}
@Test
void importCracWithTimestampFilter() throws IOException {
Network network = Network.read("TestCase12Nodes_with_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_with_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("without_RA.xml", getClass().getResourceAsStream("/merged_cb/without_RA.xml"), network, parameters);
assertTrue(creationContext.isCreationSuccessful());
assertEquals(2, creationContext.getCrac().getContingencies().size());
assertEquals(10, creationContext.getCrac().getFlowCnecs().size());
assertEquals(5, creationContext.getCrac().getStates().size());
timestamp = OffsetDateTime.parse("2019-01-08T10:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("without_RA.xml", getClass().getResourceAsStream("/merged_cb/without_RA.xml"), network, parameters);
assertTrue(creationContext.isCreationSuccessful());
assertEquals(3, creationContext.getCrac().getContingencies().size());
assertEquals(12, creationContext.getCrac().getFlowCnecs().size());
assertEquals(7, creationContext.getCrac().getStates().size());
timestamp = OffsetDateTime.parse("2019-01-10T10:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("without_RA.xml", getClass().getResourceAsStream("/merged_cb/without_RA.xml"), network, parameters);
assertFalse(creationContext.isCreationSuccessful());
}
@Test
void importCriticalBranches() throws IOException {
Network network = Network.read("TestCase12Nodes_with_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_with_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T10:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("without_RA.xml", getClass().getResourceAsStream("/merged_cb/without_RA.xml"), network, parameters);
Crac crac = creationContext.getCrac();
// BE_CBCO_000001
assertTrue(creationContext.getBranchCnecCreationContext("BE_CBCO_000001").isImported());
assertTrue(creationContext.getBranchCnecCreationContext("BE_CBCO_000001").isBaseCase());
assertEquals(1, creationContext.getBranchCnecCreationContext("BE_CBCO_000001").getCreatedCnecsIds().size());
assertEquals("BE_CBCO_000001 - preventive", creationContext.getBranchCnecCreationContext("BE_CBCO_000001").getCreatedCnecsIds().get(PREVENTIVE_INSTANT_ID));
assertNotNull(crac.getFlowCnec("BE_CBCO_000001 - preventive"));
assertEquals("[BE-BE] BBE1 - BBE2 [DIR]", crac.getFlowCnec("BE_CBCO_000001 - preventive").getName());
assertEquals("BE", crac.getFlowCnec("BE_CBCO_000001 - preventive").getOperator());
assertEquals("BBE1AA1 BBE2AA1 1", crac.getFlowCnec("BE_CBCO_000001 - preventive").getNetworkElement().getId());
assertEquals(138., crac.getFlowCnec("BE_CBCO_000001 - preventive").getReliabilityMargin(), 1e-6);
assertEquals(crac.getPreventiveState(), crac.getFlowCnec("BE_CBCO_000001 - preventive").getState());
// BE_CBCO_000003
assertTrue(creationContext.getBranchCnecCreationContext("BE_CBCO_000003").isImported());
assertFalse(creationContext.getBranchCnecCreationContext("BE_CBCO_000003").isBaseCase());
assertEquals(2, creationContext.getBranchCnecCreationContext("BE_CBCO_000003").getCreatedCnecsIds().size());
assertEquals("BE_CBCO_000003 - outage", creationContext.getBranchCnecCreationContext("BE_CBCO_000003").getCreatedCnecsIds().get(OUTAGE_INSTANT_ID));
assertEquals("BE_CBCO_000003 - curative", creationContext.getBranchCnecCreationContext("BE_CBCO_000003").getCreatedCnecsIds().get(CURATIVE_INSTANT_ID));
assertNotNull(crac.getFlowCnec("BE_CBCO_000003 - outage"));
assertEquals("[BE-BE] BBE3 - BBE2 [DIR]", crac.getFlowCnec("BE_CBCO_000003 - outage").getName());
assertEquals("BE", crac.getFlowCnec("BE_CBCO_000003 - outage").getOperator());
assertEquals("BBE2AA1 BBE3AA1 1", crac.getFlowCnec("BE_CBCO_000003 - outage").getNetworkElement().getId());
assertEquals(150., crac.getFlowCnec("BE_CBCO_000003 - outage").getReliabilityMargin(), 1e-6);
assertEquals(OUTAGE_INSTANT_ID, crac.getFlowCnec("BE_CBCO_000003 - outage").getState().getInstant().toString());
assertEquals("BE_CO_00001", crac.getFlowCnec("BE_CBCO_000003 - outage").getState().getContingency().orElseThrow().getId());
assertNotNull(crac.getFlowCnec("BE_CBCO_000003 - curative"));
assertEquals("[BE-BE] BBE3 - BBE2 [DIR]", crac.getFlowCnec("BE_CBCO_000003 - curative").getName());
assertEquals("BE", crac.getFlowCnec("BE_CBCO_000003 - curative").getOperator());
assertEquals("BBE2AA1 BBE3AA1 1", crac.getFlowCnec("BE_CBCO_000003 - curative").getNetworkElement().getId());
assertEquals(150., crac.getFlowCnec("BE_CBCO_000003 - curative").getReliabilityMargin(), 1e-6);
assertEquals(CURATIVE_INSTANT_ID, crac.getFlowCnec("BE_CBCO_000003 - curative").getState().getInstant().toString());
assertEquals("BE_CO_00001", crac.getFlowCnec("BE_CBCO_000003 - curative").getState().getContingency().orElseThrow().getId());
// number of critical branches vs. number of Cnecs
assertEquals(7, creationContext.getBranchCnecCreationContexts().size()); // 2 preventive, 5 curative
assertTrue(creationContext.getBranchCnecCreationContexts().stream().allMatch(BranchCnecCreationContext::isImported));
assertEquals(12, crac.getFlowCnecs().size()); // 2 + 5*2
}
@Test
void importComplexVariants() throws IOException {
Network network = Network.read("TestCase12Nodes_with_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_with_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("with_RA.xml", getClass().getResourceAsStream("/merged_cb/with_RA.xml"), network, parameters);
Crac crac = creationContext.getCrac();
// CNECs
assertEquals(6, crac.getFlowCnecs().size());
// PST
assertEquals(1, crac.getPstRangeActions().size());
PstRangeAction rangeAction = crac.getPstRangeActions().iterator().next();
assertEquals("RA_BE_0001", rangeAction.getId());
assertEquals("PRA_PST_BE", rangeAction.getName());
assertEquals("BE", rangeAction.getOperator());
assertEquals(1, rangeAction.getUsageRules().size());
assertEquals(UsageMethod.AVAILABLE, rangeAction.getUsageRules().iterator().next().getUsageMethod());
assertTrue(rangeAction.getUsageRules().iterator().next() instanceof OnInstant);
assertEquals(crac.getPreventiveState().getInstant(), rangeAction.getUsageRules().iterator().next().getInstant());
assertTrue(rangeAction.getGroupId().isPresent());
assertEquals("1", rangeAction.getGroupId().get());
assertEquals(1, rangeAction.getRanges().size());
TapRange absoluteRange = rangeAction.getRanges().stream().filter(range -> range.getRangeType().equals(RangeType.ABSOLUTE)).findAny().orElse(null);
assertNotNull(absoluteRange);
assertEquals(6, absoluteRange.getMaxTap());
assertEquals(-6, absoluteRange.getMinTap());
// TOPOs
assertEquals(2, crac.getNetworkActions().size());
// TOPO PRA
NetworkAction topoPra = crac.getNetworkAction("RA_FR_0001");
assertEquals(2, topoPra.getNetworkElements().size());
assertEquals("PRA_TOPO_FR", topoPra.getName());
assertEquals("FR", topoPra.getOperator());
assertEquals(1, topoPra.getUsageRules().size());
assertEquals(UsageMethod.AVAILABLE, topoPra.getUsageRules().iterator().next().getUsageMethod());
assertTrue(topoPra.getUsageRules().iterator().next() instanceof OnInstant);
assertEquals(crac.getPreventiveState().getInstant(), topoPra.getUsageRules().iterator().next().getInstant());
assertEquals(NetworkActionImpl.class, topoPra.getClass());
assertEquals(2, topoPra.getElementaryActions().size());
// TOPO CRA
NetworkAction topoCra = crac.getNetworkAction("RA_FR_0002");
assertEquals(1, topoCra.getNetworkElements().size());
assertEquals("CRA_TOPO_FR", topoCra.getName());
assertEquals("FR", topoCra.getOperator());
assertEquals(2, topoCra.getUsageRules().size());
assertEquals(UsageMethod.AVAILABLE, topoCra.getUsageRules().iterator().next().getUsageMethod());
assertTrue(topoCra.getUsageRules().iterator().next() instanceof OnContingencyState);
assertEquals(NetworkActionImpl.class, topoCra.getClass());
assertEquals(1, topoCra.getElementaryActions().size());
// Creation Context
assertEquals(3, creationContext.getRemedialActionCreationContexts().size());
assertTrue(creationContext.getRemedialActionCreationContext("RA_BE_0001").isImported());
assertTrue(creationContext.getRemedialActionCreationContext("RA_FR_0001").isImported());
assertTrue(creationContext.getRemedialActionCreationContext("RA_FR_0002").isImported());
ElementaryCreationContext pstContext = creationContext.getRemedialActionCreationContext("RA_BE_0001");
assertNotNull(pstContext);
assertEquals(ImportStatus.IMPORTED, pstContext.getImportStatus());
assertEquals("RA_BE_0001", pstContext.getNativeObjectId());
assertEquals("RA_BE_0001", pstContext.getCreatedObjectId());
assertTrue(pstContext.isImported());
assertFalse(pstContext.isAltered());
assertTrue(pstContext instanceof PstComplexVariantCreationContext);
assertFalse(((PstComplexVariantCreationContext) pstContext).isInverted());
assertEquals("BBE2AA1 BBE3AA1 1", ((PstComplexVariantCreationContext) pstContext).getNativeNetworkElementId());
ElementaryCreationContext topoContext = creationContext.getRemedialActionCreationContext("RA_FR_0001");
assertNotNull(topoContext);
assertEquals(ImportStatus.IMPORTED, topoContext.getImportStatus());
assertEquals("RA_FR_0001", topoContext.getNativeObjectId());
assertEquals("RA_FR_0001", topoContext.getCreatedObjectId());
assertTrue(topoContext.isImported());
assertFalse(topoContext.isAltered());
}
@Test
void importMnecs() throws IOException {
Network network = Network.read("TestCase12Nodes_with_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_with_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("MNEC_test.xml", getClass().getResourceAsStream("/merged_cb/MNEC_test.xml"), network, parameters);
Crac crac = creationContext.getCrac();
assertEquals(3, crac.getFlowCnecs().size());
assertTrue(crac.getFlowCnec("BE_CBCO_000001 - preventive").isOptimized());
assertFalse(crac.getFlowCnec("BE_CBCO_000001 - preventive").isMonitored());
assertFalse(crac.getFlowCnec("BE_CBCO_000002 - preventive").isOptimized());
assertTrue(crac.getFlowCnec("BE_CBCO_000002 - preventive").isMonitored());
assertTrue(crac.getFlowCnec("BE_CBCO_000003 - preventive").isOptimized());
assertTrue(crac.getFlowCnec("BE_CBCO_000003 - preventive").isMonitored());
assertCriticalBranchNotImported("BE_CBCO_000004", ImportStatus.NOT_FOR_RAO);
}
@Test
void importWithoutMnecs() throws IOException {
Network network = Network.read("TestCase12Nodes_with_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_with_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("no_MNEC_test.xml", getClass().getResourceAsStream("/merged_cb/no_MNEC_test.xml"), network, parameters);
Crac crac = creationContext.getCrac();
assertEquals(1, crac.getFlowCnecs().size());
assertTrue(crac.getFlowCnec("BE_CBCO_000001 - preventive").isOptimized());
assertFalse(crac.getFlowCnec("BE_CBCO_000001 - preventive").isMonitored());
assertCriticalBranchNotImported("BE_CBCO_000002", ImportStatus.NOT_FOR_RAO);
}
private void assertHasThresholds(FlowCnec cnec, Set<TwoSides> monitoredSides, Unit unit, Double min, Double max) {
assertEquals(monitoredSides.size(), cnec.getThresholds().size());
monitoredSides.forEach(side -> assertTrue(cnec.getThresholds().stream().anyMatch(branchThreshold -> branchThreshold.getSide().equals(side))));
cnec.getThresholds().forEach(branchThreshold -> {
assertEquals(unit, branchThreshold.getUnit());
assertEquals(min, branchThreshold.min().orElse(null));
assertEquals(max, branchThreshold.max().orElse(null));
});
}
@Test
void importThresholdsOnLeftSide() throws IOException {
parameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_ONE);
Network network = Network.read("TestCase12Nodes_for_thresholds_test.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_for_thresholds_test.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("thresholds_test.xml", getClass().getResourceAsStream("/merged_cb/thresholds_test.xml"), network, parameters);
Crac crac = creationContext.getCrac();
assertEquals(9, crac.getFlowCnecs().size());
// No threshold specification will be set to default relative-100
assertHasThresholds(crac.getFlowCnec("CBCO_000001 - preventive"), Set.of(TwoSides.ONE), Unit.PERCENT_IMAX, null, 1.);
// ImaxA set to 200
assertHasThresholds(crac.getFlowCnec("CBCO_000002 - preventive"), Set.of(TwoSides.ONE), Unit.AMPERE, null, 200.);
// ImaxFactor set to 0.8
assertHasThresholds(crac.getFlowCnec("CBCO_000003 - preventive"), Set.of(TwoSides.ONE), Unit.PERCENT_IMAX, null, 0.8);
// PermanentImaxA set to 300
assertHasThresholds(crac.getFlowCnec("CBCO_000004 - preventive"), Set.of(TwoSides.ONE), Unit.AMPERE, null, 300.);
// PermanentImaxFactor set to 1.2
assertHasThresholds(crac.getFlowCnec("CBCO_000005 - preventive"), Set.of(TwoSides.ONE), Unit.PERCENT_IMAX, null, 1.2);
// TemporaryImaxA set to 200 will be set to default relative-100
assertHasThresholds(crac.getFlowCnec("CBCO_000006 - preventive"), Set.of(TwoSides.ONE), Unit.PERCENT_IMAX, null, 1.);
// TemporaryImaxFactor set to 0.8 will be set to default relative-100
assertHasThresholds(crac.getFlowCnec("CBCO_000006 - preventive"), Set.of(TwoSides.ONE), Unit.PERCENT_IMAX, null, 1.);
// ImaxA, PermanentImaxA and TemporaryImaxA set to 300, 200 and 100
assertEquals(1, crac.getFlowCnec("CBCO_000008 - preventive").getThresholds().size());
assertEquals(300., crac.getFlowCnec("CBCO_000008 - preventive").getUpperBound(TwoSides.ONE, Unit.AMPERE).orElseThrow(), 0.1);
}
@Test
void importThresholdsOnRightSide() throws IOException {
parameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_TWO);
Network network = Network.read("TestCase12Nodes_for_thresholds_test.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_for_thresholds_test.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
Crac crac = Crac.read("thresholds_test.xml", getClass().getResourceAsStream("/merged_cb/thresholds_test.xml"), network, parameters);
// No threshold specification will be set to default relative-100
assertHasThresholds(crac.getFlowCnec("CBCO_000001 - preventive"), Set.of(TwoSides.TWO), Unit.PERCENT_IMAX, null, 1.);
// ImaxA set to 200
assertHasThresholds(crac.getFlowCnec("CBCO_000002 - preventive"), Set.of(TwoSides.TWO), Unit.AMPERE, null, 200.);
// ImaxFactor set to 0.8
assertHasThresholds(crac.getFlowCnec("CBCO_000003 - preventive"), Set.of(TwoSides.TWO), Unit.PERCENT_IMAX, null, 0.8);
// PermanentImaxA set to 300
assertHasThresholds(crac.getFlowCnec("CBCO_000004 - preventive"), Set.of(TwoSides.TWO), Unit.AMPERE, null, 300.);
// PermanentImaxFactor set to 1.2
assertHasThresholds(crac.getFlowCnec("CBCO_000005 - preventive"), Set.of(TwoSides.TWO), Unit.PERCENT_IMAX, null, 1.2);
// TemporaryImaxA set to 200 will be set to default relative-100
assertHasThresholds(crac.getFlowCnec("CBCO_000006 - preventive"), Set.of(TwoSides.TWO), Unit.PERCENT_IMAX, null, 1.);
// TemporaryImaxFactor set to 0.8 will be set to default relative-100
assertHasThresholds(crac.getFlowCnec("CBCO_000006 - preventive"), Set.of(TwoSides.TWO), Unit.PERCENT_IMAX, null, 1.);
// ImaxA, PermanentImaxA and TemporaryImaxA set to 300, 200 and 100
assertEquals(1, crac.getFlowCnec("CBCO_000008 - preventive").getThresholds().size());
assertEquals(300., crac.getFlowCnec("CBCO_000008 - preventive").getUpperBound(TwoSides.TWO, Unit.AMPERE).orElseThrow(), 0.1);
}
@Test
void importThresholdsOnBothSides() throws IOException {
parameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_BOTH_SIDES);
Network network = Network.read("TestCase12Nodes_for_thresholds_test.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_for_thresholds_test.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
Crac crac = Crac.read("thresholds_test.xml", getClass().getResourceAsStream("/merged_cb/thresholds_test.xml"), network, parameters);
// No threshold specification will be set to default relative-100
assertHasThresholds(crac.getFlowCnec("CBCO_000001 - preventive"), Set.of(TwoSides.ONE, TwoSides.TWO), Unit.PERCENT_IMAX, null, 1.);
// ImaxA set to 200
assertHasThresholds(crac.getFlowCnec("CBCO_000002 - preventive"), Set.of(TwoSides.ONE, TwoSides.TWO), Unit.AMPERE, null, 200.);
// ImaxFactor set to 0.8
assertHasThresholds(crac.getFlowCnec("CBCO_000003 - preventive"), Set.of(TwoSides.ONE, TwoSides.TWO), Unit.PERCENT_IMAX, null, 0.8);
// PermanentImaxA set to 300
assertHasThresholds(crac.getFlowCnec("CBCO_000004 - preventive"), Set.of(TwoSides.ONE, TwoSides.TWO), Unit.AMPERE, null, 300.);
// PermanentImaxFactor set to 1.2
assertHasThresholds(crac.getFlowCnec("CBCO_000005 - preventive"), Set.of(TwoSides.ONE, TwoSides.TWO), Unit.PERCENT_IMAX, null, 1.2);
// TemporaryImaxA set to 200 will be set to default relative-100
assertHasThresholds(crac.getFlowCnec("CBCO_000006 - preventive"), Set.of(TwoSides.ONE, TwoSides.TWO), Unit.PERCENT_IMAX, null, 1.);
// TemporaryImaxFactor set to 0.8 will be set to default relative-100
assertHasThresholds(crac.getFlowCnec("CBCO_000006 - preventive"), Set.of(TwoSides.ONE, TwoSides.TWO), Unit.PERCENT_IMAX, null, 1.);
// ImaxA, PermanentImaxA and TemporaryImaxA set to 300, 200 and 100
assertEquals(2, crac.getFlowCnec("CBCO_000008 - preventive").getThresholds().size());
assertEquals(300., crac.getFlowCnec("CBCO_000008 - preventive").getUpperBound(TwoSides.ONE, Unit.AMPERE).orElseThrow(), 0.1);
assertEquals(300., crac.getFlowCnec("CBCO_000008 - preventive").getUpperBound(TwoSides.TWO, Unit.AMPERE).orElseThrow(), 0.1);
}
@Test
void importLoopFlowExtensions() throws IOException {
Network network = Network.read("TestCase12Nodes_with_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_with_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("with_crosszonal_branches.xml", getClass().getResourceAsStream("/merged_cb/with_crosszonal_branches.xml"), network, parameters);
Crac crac = creationContext.getCrac();
assertEquals(6, crac.getFlowCnecs().size());
assertNull(crac.getFlowCnec("INTRA_ZONAL_PREVENTIVE - preventive").getExtension(LoopFlowThreshold.class));
assertNull(crac.getFlowCnec("INTRA_ZONAL_CURATIVE - curative").getExtension(LoopFlowThreshold.class));
assertNotNull(crac.getFlowCnec("CROSS_ZONAL_PREVENTIVE - preventive").getExtension(LoopFlowThreshold.class));
assertNotNull(crac.getFlowCnec("CROSS_ZONAL_CURATIVE - curative").getExtension(LoopFlowThreshold.class));
assertEquals(.75, crac.getFlowCnec("CROSS_ZONAL_PREVENTIVE - preventive").getExtension(LoopFlowThreshold.class).getThreshold(Unit.PERCENT_IMAX), 1e-3);
assertEquals(Unit.PERCENT_IMAX, crac.getFlowCnec("CROSS_ZONAL_PREVENTIVE - preventive").getExtension(LoopFlowThreshold.class).getUnit());
assertEquals(.30, crac.getFlowCnec("CROSS_ZONAL_CURATIVE - curative").getExtension(LoopFlowThreshold.class).getThreshold(Unit.PERCENT_IMAX), 1e-3);
assertEquals(Unit.PERCENT_IMAX, crac.getFlowCnec("CROSS_ZONAL_CURATIVE - curative").getExtension(LoopFlowThreshold.class).getUnit());
assertTrue(creationContext.getBranchCnecCreationContext("CROSS_ZONAL_PREVENTIVE").isDirectionInvertedInNetwork());
assertFalse(creationContext.getBranchCnecCreationContext("CROSS_ZONAL_PREVENTIVE").isAltered());
assertTrue(creationContext.getBranchCnecCreationContext("CROSS_ZONAL_CURATIVE").isDirectionInvertedInNetwork());
assertFalse(creationContext.getBranchCnecCreationContext("CROSS_ZONAL_CURATIVE").isAltered());
}
@Test
void testImportHvdcVhOutage() throws IOException {
Network network = Network.read("TestCase12NodesHvdc.uct", getClass().getResourceAsStream("/network/TestCase12NodesHvdc.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("hvdcvh-outage.xml", getClass().getResourceAsStream("/merged_cb/hvdcvh-outage.xml"), network, parameters);
Crac crac = creationContext.getCrac();
Contingency contingency = crac.getFlowCnec("Cnec1 - curative").getState().getContingency().orElse(null);
assertNotNull(contingency);
assertEquals(2, contingency.getElements().size());
assertTrue(contingency.getElements().stream().anyMatch(ne -> ne.getId().equals("DDE3AA1 XLI_OB1A 1")));
assertTrue(contingency.getElements().stream().anyMatch(ne -> ne.getId().equals("BBE2AA1 XLI_OB1B 1")));
}
@Test
void testImportAndCleanCriticalBranches() throws IOException {
Network network = Network.read("TestCase_severalVoltageLevels_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase_severalVoltageLevels_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("critical_branches.xml", getClass().getResourceAsStream("/merged_cb/critical_branches.xml"), network, parameters);
Crac crac = creationContext.getCrac();
assertEquals(7, creationContext.getBranchCnecCreationContexts().size());
assertTrue(creationContext.getBranchCnecCreationContext("BE_CBCO_000001").isImported());
assertTrue(creationContext.getBranchCnecCreationContext("BE_CBCO_000002").isImported());
assertTrue(creationContext.getBranchCnecCreationContext("BE_CBCO_000003").isImported());
assertTrue(creationContext.getBranchCnecCreationContext("BE_CBCO_000004").isImported());
assertEquals(1, creationContext.getBranchCnecCreationContext("BE_CBCO_000001").getCreatedCnecsIds().size());
assertEquals(1, creationContext.getBranchCnecCreationContext("BE_CBCO_000002").getCreatedCnecsIds().size());
assertEquals(2, creationContext.getBranchCnecCreationContext("BE_CBCO_000003").getCreatedCnecsIds().size());
assertEquals(2, creationContext.getBranchCnecCreationContext("BE_CBCO_000004").getCreatedCnecsIds().size());
assertCriticalBranchNotImported("FR_CBCO_000001", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK); //unknown branch
assertCriticalBranchNotImported("FR_CBCO_000002", ImportStatus.INCONSISTENCY_IN_DATA); //unknown outage
assertCriticalBranchNotImported("FR_CBCO_000003", ImportStatus.NOT_FOR_RAO); //not a MNEC, not a Cnec
assertEquals(6, crac.getFlowCnecs().size());
}
@Test
void testImportAndCleanComplexVariants() throws IOException {
Network network = Network.read("TestCase_severalVoltageLevels_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase_severalVoltageLevels_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("complex_variants.xml", getClass().getResourceAsStream("/merged_cb/complex_variants.xml"), network, parameters);
Crac crac = creationContext.getCrac();
assertEquals(13, creationContext.getRemedialActionCreationContexts().size());
assertTrue(creationContext.getRemedialActionCreationContext("RA_BE_0001").isImported());
assertComplexVariantNotImported("RA_BE_0002", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK); //unknown branch
assertComplexVariantNotImported("RA_BE_0003", ImportStatus.INCONSISTENCY_IN_DATA); //two PST actions
assertComplexVariantNotImported("RA_BE_0004", ImportStatus.INCOMPLETE_DATA); //two action set
assertTrue(creationContext.getRemedialActionCreationContext("RA_FR_0001").isImported());
assertTrue(creationContext.getRemedialActionCreationContext("RA_FR_0002").isImported()); //same network element/action/usage rule as RA_FR_0005, prioritized due to alphabetical order
assertComplexVariantNotImported("RA_FR_0003", ImportStatus.INCOMPLETE_DATA); //no CO list
assertComplexVariantNotImported("RA_FR_0004", ImportStatus.INCONSISTENCY_IN_DATA); //preventive and curative
assertComplexVariantNotImported("RA_FR_0005", ImportStatus.INCONSISTENCY_IN_DATA); //same network element/usage rule as RA_FR_0002
assertComplexVariantNotImported("RA_FR_0006", ImportStatus.INCONSISTENCY_IN_DATA); //all outage in CO list not ok
assertComplexVariantNotImported("RA_FR_0007", ImportStatus.ELEMENT_NOT_FOUND_IN_NETWORK); //unknown branch
assertTrue(creationContext.getRemedialActionCreationContext("RA_FR_0008").isImported()); //same network element/action as RA_FR_0002, but not same usage rule
assertTrue(creationContext.getRemedialActionCreationContext("RA_FR_0009").isImported()); //same network element/usage rule as RA_FR_0002, but not same action
assertEquals(1, crac.getRangeActions().size());
assertEquals(4, crac.getNetworkActions().size());
assertEquals(1, crac.getNetworkAction("RA_FR_0002").getUsageRules().size()); // one cannot be interpreted
}
@Test
void testInvertPstRangeAction() throws IOException {
Network network = Network.read("TestCase_severalVoltageLevels_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase_severalVoltageLevels_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("complex_variants_invert.xml", getClass().getResourceAsStream("/merged_cb/complex_variants_invert.xml"), network, parameters);
Crac crac = creationContext.getCrac();
// RA_BE_0001 should not be inverted
assertTrue(creationContext.getRemedialActionCreationContext("RA_BE_0001") instanceof PstComplexVariantCreationContext);
PstComplexVariantCreationContext pstContext = (PstComplexVariantCreationContext) creationContext.getRemedialActionCreationContext("RA_BE_0001");
assertTrue(pstContext.isImported());
assertEquals("RA_BE_0001", pstContext.getNativeObjectId());
assertEquals("RA_BE_0001", pstContext.getCreatedObjectId());
assertFalse(pstContext.isInverted());
assertEquals("BBE2AA1 BBE3AA1 PST BE", pstContext.getNativeNetworkElementId());
PstRangeAction pstRangeAction = crac.getPstRangeAction("RA_BE_0001");
assertEquals("BBE2AA1 BBE3AA1 1", pstRangeAction.getNetworkElement().getId());
assertEquals(3, pstRangeAction.getInitialTap());
assertEquals(RangeType.ABSOLUTE, pstRangeAction.getRanges().get(0).getRangeType());
assertEquals(-16, pstRangeAction.getRanges().get(0).getMinTap());
assertEquals(6, pstRangeAction.getRanges().get(0).getMaxTap());
// RA_BE_0002 should be inverted
assertTrue(creationContext.getRemedialActionCreationContext("RA_BE_0002") instanceof PstComplexVariantCreationContext);
pstContext = (PstComplexVariantCreationContext) creationContext.getRemedialActionCreationContext("RA_BE_0002");
assertTrue(pstContext.isImported());
assertEquals("RA_BE_0002", pstContext.getNativeObjectId());
assertEquals("RA_BE_0002", pstContext.getCreatedObjectId());
assertTrue(pstContext.isInverted());
assertFalse(pstContext.isAltered());
assertEquals("BBE3AA1 BBE2AA1 PST BE", pstContext.getNativeNetworkElementId());
pstRangeAction = crac.getPstRangeAction("RA_BE_0002");
assertEquals("BBE2AA1 BBE3AA1 1", pstRangeAction.getNetworkElement().getId());
assertEquals(3, pstRangeAction.getInitialTap());
assertEquals(RangeType.ABSOLUTE, pstRangeAction.getRanges().get(0).getRangeType());
assertEquals(-6, pstRangeAction.getRanges().get(0).getMinTap());
assertEquals(16, pstRangeAction.getRanges().get(0).getMaxTap());
assertEquals(RangeType.RELATIVE_TO_PREVIOUS_INSTANT, pstRangeAction.getRanges().get(1).getRangeType());
assertEquals(-4, pstRangeAction.getRanges().get(1).getMinTap());
assertEquals(10, pstRangeAction.getRanges().get(1).getMaxTap());
}
@Test
void testWrongTsCreationContext() throws IOException {
Network network = Network.read("TestCase12Nodes_with_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_with_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T10:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("wrong_ts.xml", getClass().getResourceAsStream("/merged_cb/wrong_ts.xml"), network, parameters);
Crac crac = creationContext.getCrac();
assertEquals(3, creationContext.getCreationReport().getReport().size());
assertEquals(1, crac.getCnecs().size());
assertCriticalBranchNotImported("BE_CBCO_000001", ImportStatus.NOT_FOR_REQUESTED_TIMESTAMP);
assertTrue(creationContext.getBranchCnecCreationContext("BE_CBCO_000002").isImported());
assertEquals(1, crac.getRemedialActions().size());
assertComplexVariantNotImported("RA_BE_0001", ImportStatus.NOT_FOR_REQUESTED_TIMESTAMP);
assertTrue(creationContext.getRemedialActionCreationContext("RA_FR_0001").isImported());
}
@Test
void testDuplicatePsts() throws IOException {
Network network = Network.read("TestCase_severalVoltageLevels_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase_severalVoltageLevels_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
creationContext = (FbConstraintCreationContext) Crac.readWithContext("complex_variants_duplicate_psts.xml", getClass().getResourceAsStream("/merged_cb/complex_variants_duplicate_psts.xml"), network, parameters);
Crac crac = creationContext.getCrac();
assertEquals(3, creationContext.getCreationReport().getReport().size());
// RA_BE_0001 is one same PST as RA_BE_0002
// RA_BE_0002 has been prioritized due to alphabetical order
assertTrue(creationContext.getRemedialActionCreationContext("RA_BE_0001").isImported());
assertNotNull(crac.getRemedialAction("RA_BE_0001"));
assertFalse(creationContext.getRemedialActionCreationContext("RA_BE_0002").isImported());
assertComplexVariantNotImported("RA_BE_0002", ImportStatus.INCONSISTENCY_IN_DATA);
assertNull(creationContext.getRemedialActionCreationContext("RA_BE_0002").getCreatedObjectId());
assertNull(crac.getRemedialAction("RA_BE_0002"));
// RA_BE_0003 is one same PST as RA_BE_0004
// RA_BE_0004 has been prioritized as it has a groupId
assertFalse(creationContext.getRemedialActionCreationContext("RA_BE_0003").isImported());
assertComplexVariantNotImported("RA_BE_0003", ImportStatus.INCONSISTENCY_IN_DATA);
assertNull(creationContext.getRemedialActionCreationContext("RA_BE_0003").getCreatedObjectId());
assertNull(crac.getRemedialAction("RA_BE_0003"));
assertTrue(creationContext.getRemedialActionCreationContext("RA_BE_0004").isImported());
assertNotNull(crac.getRemedialAction("RA_BE_0004"));
}
@Test
void importHalflineThresholds() throws IOException {
Network network = Network.read("TestCase12Nodes_with_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase12Nodes_with_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T10:30Z");
Crac crac;
parameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_BOTH_SIDES);
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
crac = Crac.read("halflines.xml", getClass().getResourceAsStream("/merged_cb/halflines.xml"), network, parameters);
assertHasThresholds(crac.getFlowCnec("FR_CBCO_000001 - preventive"), Set.of(TwoSides.TWO), Unit.PERCENT_IMAX, -1., null);
assertHasThresholds(crac.getFlowCnec("FR_CBCO_000002 - preventive"), Set.of(TwoSides.ONE), Unit.PERCENT_IMAX, null, 1.);
parameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_ONE);
crac = Crac.read("halflines.xml", getClass().getResourceAsStream("/merged_cb/halflines.xml"), network, parameters);
assertHasThresholds(crac.getFlowCnec("FR_CBCO_000001 - preventive"), Set.of(TwoSides.TWO), Unit.PERCENT_IMAX, -1., null);
assertHasThresholds(crac.getFlowCnec("FR_CBCO_000002 - preventive"), Set.of(TwoSides.ONE), Unit.PERCENT_IMAX, null, 1.);
parameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_TWO);
crac = Crac.read("halflines.xml", getClass().getResourceAsStream("/merged_cb/halflines.xml"), network, parameters);
assertHasThresholds(crac.getFlowCnec("FR_CBCO_000001 - preventive"), Set.of(TwoSides.TWO), Unit.PERCENT_IMAX, -1., null);
assertHasThresholds(crac.getFlowCnec("FR_CBCO_000002 - preventive"), Set.of(TwoSides.ONE), Unit.PERCENT_IMAX, null, 1.);
}
@Test
void testTransformerCnecThresholds() throws IOException {
Network network = Network.read("TestCase_severalVoltageLevels_Xnodes.uct", getClass().getResourceAsStream("/network/TestCase_severalVoltageLevels_Xnodes.uct"));
OffsetDateTime timestamp = OffsetDateTime.parse("2019-01-08T00:30Z");
// CBCO_1 is in %Imax, thresholds should be created depending on default monitored side
// CBCO_2 is in A, threshold should be defined on high voltage level side
parameters.getExtension(FbConstraintCracCreationParameters.class).setTimestamp(timestamp);
parameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_BOTH_SIDES);
Crac crac = Crac.read("transformers.xml", getClass().getResourceAsStream("/merged_cb/transformers.xml"), network, parameters);
assertHasThresholds(crac.getFlowCnec("CBCO_1 - preventive"), Set.of(TwoSides.ONE, TwoSides.TWO), Unit.PERCENT_IMAX, -1.0, null);
assertHasThresholds(crac.getFlowCnec("CBCO_2 - preventive"), Set.of(TwoSides.ONE), Unit.AMPERE, -100., null);
parameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_ONE);
crac = Crac.read("transformers.xml", getClass().getResourceAsStream("/merged_cb/transformers.xml"), network, parameters);
assertHasThresholds(crac.getFlowCnec("CBCO_1 - preventive"), Set.of(TwoSides.ONE), Unit.PERCENT_IMAX, -1.0, null);
assertHasThresholds(crac.getFlowCnec("CBCO_2 - preventive"), Set.of(TwoSides.ONE), Unit.AMPERE, -100., null);
parameters.setDefaultMonitoredLineSide(CracCreationParameters.MonitoredLineSide.MONITOR_LINES_ON_SIDE_TWO);
crac = Crac.read("transformers.xml", getClass().getResourceAsStream("/merged_cb/transformers.xml"), network, parameters);
assertHasThresholds(crac.getFlowCnec("CBCO_1 - preventive"), Set.of(TwoSides.TWO), Unit.PERCENT_IMAX, -1.0, null);
assertHasThresholds(crac.getFlowCnec("CBCO_2 - preventive"), Set.of(TwoSides.ONE), Unit.AMPERE, -100., null);
}
}