ExhaustiveCracCreation.java
/*
* Copyright (c) 2021, 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.impl.utils;
import com.powsybl.contingency.ContingencyElementType;
import com.powsybl.iidm.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.InstantKind;
import com.powsybl.openrao.data.crac.api.networkaction.ActionType;
import com.powsybl.openrao.data.crac.api.range.RangeType;
import com.powsybl.openrao.data.crac.api.rangeaction.VariationDirection;
import com.powsybl.openrao.data.crac.api.usagerule.UsageMethod;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;
import static com.powsybl.openrao.data.crac.impl.utils.NetworkImportsUtil.createNetworkForJsonRetrocompatibilityTest;
/**
* @author Baptiste Seguinot {@literal <baptiste.seguinot at rte-france.com>}
*/
public final class ExhaustiveCracCreation {
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";
/*
Small CRAC used in I/O unit tests of open-rao
The idea of this CRAC is to be quite exhaustive regarding the diversity of the CRAC objects.
It contains numerous variations of the CRAC objects, to ensure that they are all tested in
the manipulations of the CRAC.
*/
private ExhaustiveCracCreation() {
}
public static Crac create() {
return create(CracFactory.findDefault());
}
private static ContingencyElementType randomContingencyElementType() {
return ContingencyElementType.LINE;
}
public static Network createAssociatedNetwork() {
// should be Line because of ContingencyElementType.LINE
return createNetworkForJsonRetrocompatibilityTest();
}
public static Crac create(CracFactory cracFactory) {
Crac crac = cracFactory.create("exhaustiveCracId", "exhaustiveCracName", OffsetDateTime.of(2025, 2, 3, 10, 12, 0, 0, ZoneOffset.UTC))
.newInstant(PREVENTIVE_INSTANT_ID, InstantKind.PREVENTIVE)
.newInstant(OUTAGE_INSTANT_ID, InstantKind.OUTAGE)
.newInstant(AUTO_INSTANT_ID, InstantKind.AUTO)
.newInstant(CURATIVE_INSTANT_ID, InstantKind.CURATIVE);
crac.newRaUsageLimits(CURATIVE_INSTANT_ID)
.withMaxRa(4)
.withMaxTso(2)
.withMaxPstPerTso(new HashMap<>(Map.of("FR", 7)))
.withMaxTopoPerTso(new HashMap<>(Map.of("FR", 5, "BE", 6)))
.withMaxRaPerTso(new HashMap<>(Map.of("FR", 12)))
.withMaxElementaryActionPerTso(new HashMap<>(Map.of("FR", 21)))
.add();
String contingency1Id = "contingency1Id";
crac.newContingency().withId(contingency1Id).withContingencyElement("ne1Id", randomContingencyElementType()).add();
String contingency2Id = "contingency2Id";
crac.newContingency().withId(contingency2Id).withContingencyElement("ne2Id", randomContingencyElementType()).withContingencyElement("ne3Id", randomContingencyElementType()).add();
crac.newFlowCnec().withId("cnec1prevId")
.withNetworkElement("ne4Id")
.withInstant(PREVENTIVE_INSTANT_ID)
.withOperator("operator1")
.withOptimized()
.newThreshold().withSide(TwoSides.TWO).withUnit(Unit.AMPERE).withMin(-500.).add()
.withIMax(1000., TwoSides.TWO)
.withNominalVoltage(220.)
.add();
crac.newFlowCnec().withId("cnec1outageId")
.withNetworkElement("ne4Id")
.withInstant(OUTAGE_INSTANT_ID)
.withContingency(contingency1Id)
.withOperator("operator1")
.withOptimized()
.newThreshold().withSide(TwoSides.TWO).withUnit(Unit.AMPERE).withMin(-800.).add()
.withNominalVoltage(220.)
.add();
crac.newFlowCnec().withId("cnec2prevId")
.withNetworkElement("ne5Id", "ne5Name")
.withInstant(PREVENTIVE_INSTANT_ID)
.withOperator("operator2")
.withOptimized()
.newThreshold().withSide(TwoSides.ONE).withUnit(Unit.PERCENT_IMAX).withMin(-0.3).add()
.newThreshold().withSide(TwoSides.ONE).withUnit(Unit.AMPERE).withMin(-800.).add()
.newThreshold().withSide(TwoSides.TWO).withUnit(Unit.AMPERE).withMin(-800.).add()
.newThreshold().withSide(TwoSides.TWO).withUnit(Unit.AMPERE).withMax(1200.).add()
.withNominalVoltage(220., TwoSides.TWO)
.withNominalVoltage(380., TwoSides.ONE)
.withIMax(2000.)
.add();
crac.newFlowCnec().withId("cnec3prevId")
.withName("cnec3prevName")
.withNetworkElement("ne2Id", "ne2Name")
.withInstant(PREVENTIVE_INSTANT_ID)
.withOperator("operator3")
.newThreshold().withUnit(Unit.MEGAWATT).withMax(500.).withSide(TwoSides.ONE).add()
.newThreshold().withUnit(Unit.MEGAWATT).withMax(500.).withSide(TwoSides.TWO).add()
.withReliabilityMargin(20.)
.withMonitored()
.add();
crac.newFlowCnec().withId("cnec3autoId")
.withName("cnec3autoName")
.withNetworkElement("ne2Id", "ne2Name")
.withInstant(AUTO_INSTANT_ID)
.withContingency(contingency2Id)
.withOperator("operator3")
.newThreshold().withUnit(Unit.MEGAWATT).withMax(500.).withSide(TwoSides.ONE).add()
.newThreshold().withUnit(Unit.MEGAWATT).withMax(500.).withSide(TwoSides.TWO).add()
.withReliabilityMargin(20.)
.withMonitored()
.add();
crac.newFlowCnec().withId("cnec3curId")
.withNetworkElement("ne2Id", "ne2Name")
.withInstant(CURATIVE_INSTANT_ID)
.withContingency(contingency2Id)
.withOperator("operator3")
.newThreshold().withUnit(Unit.MEGAWATT).withMax(500.).withSide(TwoSides.ONE).add()
.newThreshold().withUnit(Unit.MEGAWATT).withMax(500.).withSide(TwoSides.TWO).add()
.withReliabilityMargin(20.)
.withMonitored()
.add();
crac.newFlowCnec().withId("cnec4prevId")
.withName("cnec4prevName")
.withNetworkElement("ne3Id")
.withInstant(PREVENTIVE_INSTANT_ID)
.withOperator("operator4")
.newThreshold().withUnit(Unit.MEGAWATT).withMax(500.).withSide(TwoSides.ONE).add()
.withReliabilityMargin(0.)
.withOptimized()
.withMonitored()
.add();
crac.newAngleCnec().withId("angleCnecId")
.withName("angleCnecName")
.withExportingNetworkElement("eneId", "eneName")
.withImportingNetworkElement("ineId", "ineName")
.withInstant(CURATIVE_INSTANT_ID)
.withContingency(contingency1Id)
.withOperator("operator1")
.newThreshold().withUnit(Unit.DEGREE).withMin(-100.).withMax(100.).add()
.withReliabilityMargin(10.)
.withMonitored()
.add();
crac.newVoltageCnec().withId("voltageCnecId")
.withName("voltageCnecName")
.withNetworkElement("voltageCnecNeId", "voltageCnecNeName")
.withInstant(CURATIVE_INSTANT_ID)
.withContingency(contingency1Id)
.withOperator("operator1")
.newThreshold().withUnit(Unit.KILOVOLT).withMin(380.).add()
.withReliabilityMargin(1.)
.withMonitored()
.add();
// network action with one pst set point
crac.newNetworkAction().withId("pstSetpointRaId")
.withName("pstSetpointRaName")
.withOperator("RTE")
.newPhaseTapChangerTapPositionAction().withTapPosition(15).withNetworkElement("pst").add()
.newOnInstantUsageRule().withUsageMethod(UsageMethod.AVAILABLE).withInstant(PREVENTIVE_INSTANT_ID).add()
.newOnContingencyStateUsageRule().withUsageMethod(UsageMethod.FORCED).withContingency(contingency1Id).withInstant(CURATIVE_INSTANT_ID).add()
.add();
// complex network action with one pst set point and one topology
crac.newNetworkAction().withId("complexNetworkActionId")
.withName("complexNetworkActionName")
.withOperator("RTE")
.newPhaseTapChangerTapPositionAction().withTapPosition(5).withNetworkElement("pst").add()
.newTerminalsConnectionAction().withActionType(ActionType.CLOSE).withNetworkElement("ne1Id").add()
.newOnInstantUsageRule().withUsageMethod(UsageMethod.FORCED).withInstant(PREVENTIVE_INSTANT_ID).add()
.add();
// network action with one injection set point
crac.newNetworkAction().withId("injectionSetpointRaId")
.withName("injectionSetpointRaName")
.withOperator("RTE")
.withActivationCost(75d)
.newGeneratorAction().withActivePowerValue(260.0).withNetworkElement("injection").add()
.newOnConstraintUsageRule().withCnec("cnec3autoId").withInstant(AUTO_INSTANT_ID).withUsageMethod(UsageMethod.FORCED).add()
.add();
// network action with multiple type elementary actions
crac.newNetworkAction().withId("complexNetworkAction2Id")
.withName("complexNetworkAction2Name")
.withOperator("RTE")
.newLoadAction().withActivePowerValue(260.0).withNetworkElement("LD1").add()
.newDanglingLineAction().withActivePowerValue(-120.0).withNetworkElement("DL1").add()
.newSwitchAction().withActionType(ActionType.OPEN).withNetworkElement("BR1").add()
.newShuntCompensatorPositionAction().withSectionCount(13).withNetworkElement("SC1").add()
.newOnFlowConstraintInCountryUsageRule().withInstant(CURATIVE_INSTANT_ID).withContingency("contingency2Id").withCountry(Country.FR).withUsageMethod(UsageMethod.AVAILABLE).add()
.add();
// network action with one switch pair
crac.newNetworkAction().withId("switchPairRaId")
.withName("switchPairRaName")
.withOperator("RTE")
.newSwitchPair().withSwitchToOpen("to-open").withSwitchToClose("to-close", "to-close-name").add()
.newOnContingencyStateUsageRule().withUsageMethod(UsageMethod.AVAILABLE).withContingency(contingency2Id).withInstant(CURATIVE_INSTANT_ID).add()
.add();
// range actions
crac.newPstRangeAction().withId("pstRange1Id")
.withName("pstRange1Name")
.withOperator("RTE")
.withNetworkElement("pst")
.withInitialTap(2)
.withTapToAngleConversionMap(Map.of(-3, 0., -2, .5, -1, 1., 0, 1.5, 1, 2., 2, 2.5, 3, 3.))
.newTapRange().withRangeType(RangeType.ABSOLUTE).withMinTap(1).withMaxTap(7).add()
.newTapRange().withRangeType(RangeType.RELATIVE_TO_INITIAL_NETWORK).withMinTap(-3).withMaxTap(3).add()
.newOnInstantUsageRule().withUsageMethod(UsageMethod.AVAILABLE).withInstant(PREVENTIVE_INSTANT_ID).add()
.add();
crac.newPstRangeAction().withId("pstRange2Id")
.withName("pstRange2Name")
.withOperator("RTE")
.withNetworkElement("pst2")
.withGroupId("group-1-pst")
.withInitialTap(1)
.withTapToAngleConversionMap(Map.of(-3, 0., -2, .5, -1, 1., 0, 1.5, 1, 2., 2, 2.5, 3, 3.))
.newTapRange().withRangeType(RangeType.ABSOLUTE).withMinTap(-4).withMaxTap(3).add()
.newTapRange().withRangeType(RangeType.RELATIVE_TO_INITIAL_NETWORK).withMinTap(-5).withMaxTap(1).add()
.newTapRange().withRangeType(RangeType.RELATIVE_TO_PREVIOUS_TIME_STEP).withMinTap(-2).withMaxTap(5).add()
.newOnConstraintUsageRule().withInstant(PREVENTIVE_INSTANT_ID).withCnec("cnec3prevId").withUsageMethod(UsageMethod.AVAILABLE).add()
.add();
crac.newPstRangeAction().withId("pstRange3Id")
.withName("pstRange3Name")
.withOperator("RTE")
.withNetworkElement("pst3")
.withGroupId("group-3-pst")
.withInitialTap(1)
.withTapToAngleConversionMap(Map.of(-3, 0., -2, .5, -1, 1., 0, 1.5, 1, 2., 2, 2.5, 3, 3.))
.newTapRange().withRangeType(RangeType.ABSOLUTE).withMinTap(1).withMaxTap(7).add()
.newTapRange().withRangeType(RangeType.RELATIVE_TO_INITIAL_NETWORK).withMinTap(-3).withMaxTap(3).add()
.newOnConstraintUsageRule().withInstant(CURATIVE_INSTANT_ID).withCnec("angleCnecId").withUsageMethod(UsageMethod.AVAILABLE).add()
.add();
crac.newPstRangeAction().withId("pstRange4Id")
.withName("pstRange4Name")
.withOperator("RTE")
.withNetworkElement("pst3")
.withGroupId("group-3-pst")
.withInitialTap(1)
.withTapToAngleConversionMap(Map.of(-3, 0., -2, .5, -1, 1., 0, 1.5, 1, 2., 2, 2.5, 3, 3.))
.newTapRange().withRangeType(RangeType.ABSOLUTE).withMinTap(1).withMaxTap(7).add()
.newTapRange().withRangeType(RangeType.RELATIVE_TO_INITIAL_NETWORK).withMinTap(-3).withMaxTap(3).add()
.newOnConstraintUsageRule().withInstant(CURATIVE_INSTANT_ID).withCnec("voltageCnecId").withUsageMethod(UsageMethod.AVAILABLE).add()
.add();
crac.newPstRangeAction().withId("pstRange5Id").withName("pstRange5Name").withOperator("RTE").withNetworkElement("pst3")
.withGroupId("group-3-pst")
.withInitialTap(-3)
.withTapToAngleConversionMap(Map.of(-3, 0., -2, .5))
.newTapRange().withRangeType(RangeType.ABSOLUTE).withMinTap(1).withMaxTap(7).add()
.newTapRange().withRangeType(RangeType.RELATIVE_TO_INITIAL_NETWORK).withMinTap(-3).withMaxTap(3).add()
.newOnInstantUsageRule().withUsageMethod(UsageMethod.FORCED).withInstant(PREVENTIVE_INSTANT_ID).add()
.newOnConstraintUsageRule().withInstant(PREVENTIVE_INSTANT_ID).withCnec("cnec3curId").withUsageMethod(UsageMethod.AVAILABLE).add()
.add();
crac.newHvdcRangeAction().withId("hvdcRange1Id")
.withName("hvdcRange1Name")
.withOperator("RTE")
.withNetworkElement("hvdc")
.newRange().withMin(-1000).withMax(1000).add()
.newOnFlowConstraintInCountryUsageRule().withInstant(PREVENTIVE_INSTANT_ID).withCountry(Country.FR).withUsageMethod(UsageMethod.AVAILABLE).add()
.add();
crac.newHvdcRangeAction().withId("hvdcRange2Id")
.withName("hvdcRange2Name")
.withOperator("RTE")
.withNetworkElement("hvdc2")
.withGroupId("group-1-hvdc")
.newRange().withMin(-1000).withMax(1000).add()
.newOnContingencyStateUsageRule().withContingency("contingency1Id").withInstant(CURATIVE_INSTANT_ID).withUsageMethod(UsageMethod.AVAILABLE).add()
.newOnContingencyStateUsageRule().withContingency("contingency2Id").withInstant(CURATIVE_INSTANT_ID).withUsageMethod(UsageMethod.AVAILABLE).add()
.newOnConstraintUsageRule().withInstant(PREVENTIVE_INSTANT_ID).withCnec("cnec3curId").withUsageMethod(UsageMethod.AVAILABLE).add()
.add();
crac.newInjectionRangeAction().withId("injectionRange1Id")
.withName("injectionRange1Name")
.withNetworkElementAndKey(1., "generator1Id")
.withNetworkElementAndKey(-1., "generator2Id", "generator2Name")
.withActivationCost(100d)
.withVariationCost(750d, VariationDirection.UP)
.withVariationCost(1000d, VariationDirection.DOWN)
.newRange().withMin(-500).withMax(500).add()
.newRange().withMin(-1000).withMax(1000).add()
.newOnFlowConstraintInCountryUsageRule().withInstant(CURATIVE_INSTANT_ID).withContingency("contingency2Id").withCountry(Country.ES).withUsageMethod(UsageMethod.AVAILABLE).add()
.newOnContingencyStateUsageRule().withContingency("contingency1Id").withInstant(CURATIVE_INSTANT_ID).withUsageMethod(UsageMethod.AVAILABLE).add()
.add();
crac.newCounterTradeRangeAction().withId("counterTradeRange1Id")
.withName("counterTradeRange1Name")
.withExportingCountry(Country.FR)
.withImportingCountry(Country.DE)
.withVariationCost(2000d, VariationDirection.UP)
.withVariationCost(1000d, VariationDirection.DOWN)
.newRange().withMin(-500).withMax(500).add()
.newRange().withMin(-1000).withMax(1000).add()
.newOnFlowConstraintInCountryUsageRule().withInstant(CURATIVE_INSTANT_ID).withCountry(Country.ES).withUsageMethod(UsageMethod.AVAILABLE).add()
.newOnContingencyStateUsageRule().withContingency("contingency1Id").withInstant(CURATIVE_INSTANT_ID).withUsageMethod(UsageMethod.AVAILABLE).add()
.add();
return crac;
}
}