CommonCracCreation.java
/*
* Copyright (c) 2020, 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.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.impl.CracImplFactory;
import com.powsybl.openrao.data.crac.api.cnec.FlowCnecAdder;
import com.powsybl.openrao.data.crac.api.networkaction.ActionType;
import com.powsybl.iidm.network.TwoSides;
import com.powsybl.openrao.data.crac.api.range.RangeType;
import com.powsybl.openrao.data.crac.api.usagerule.UsageMethod;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.PhaseTapChanger;
import com.powsybl.iidm.network.TwoWindingsTransformer;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* @author Viktor Terrier {@literal <viktor.terrier at rte-france.com>}
*/
public final class CommonCracCreation {
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";
public static class IidmPstHelper {
private final String pstId;
private int initialTapPosition;
private Map<Integer, Double> tapToAngleConversionMap;
public IidmPstHelper(String pstId, Network network) {
this.pstId = pstId;
interpretWithNetwork(network);
}
public int getInitialTap() {
return initialTapPosition;
}
public Map<Integer, Double> getTapToAngleConversionMap() {
return tapToAngleConversionMap;
}
private void interpretWithNetwork(Network network) {
TwoWindingsTransformer transformer = network.getTwoWindingsTransformer(pstId);
if (Objects.isNull(transformer)) {
return;
}
PhaseTapChanger phaseTapChanger = transformer.getPhaseTapChanger();
if (Objects.isNull(phaseTapChanger)) {
return;
}
this.initialTapPosition = phaseTapChanger.getTapPosition();
buildTapToAngleConversionMap(phaseTapChanger);
}
private void buildTapToAngleConversionMap(PhaseTapChanger phaseTapChanger) {
tapToAngleConversionMap = new HashMap<>();
phaseTapChanger.getAllSteps().forEach((tap, step) -> tapToAngleConversionMap.put(tap, step.getAlpha()));
}
}
private CommonCracCreation() {
// nothing
}
public static Crac create(Set<TwoSides> monitoredCnecSides) {
return create(new CracImplFactory(), monitoredCnecSides);
}
public static Crac create() {
return create(new CracImplFactory(), Set.of(TwoSides.ONE));
}
public static Crac create(CracFactory cracFactory, Set<TwoSides> monitoredCnecSides) {
Crac crac = cracFactory.create("idSimpleCracTestUS", "nameSimpleCracTestUS")
.newInstant(PREVENTIVE_INSTANT_ID, InstantKind.PREVENTIVE)
.newInstant(OUTAGE_INSTANT_ID, InstantKind.OUTAGE)
.newInstant(AUTO_INSTANT_ID, InstantKind.AUTO)
.newInstant(CURATIVE_INSTANT_ID, InstantKind.CURATIVE);
// Contingencies
crac.newContingency()
.withId("Contingency FR1 FR3")
.withName("Trip of FFR1AA1 FFR3AA1 1")
.withContingencyElement("FFR1AA1 FFR3AA1 1", ContingencyElementType.BRANCH)
.add();
crac.newContingency()
.withId("Contingency FR1 FR2")
.withName("Trip of FFR1AA1 FFR2AA1 1")
.withContingencyElement("FFR1AA1 FFR2AA1 1", ContingencyElementType.BRANCH)
.add();
// Cnecs
FlowCnecAdder cnecAdder1 = crac.newFlowCnec()
.withId("cnec1basecase")
.withNetworkElement("BBE2AA1 FFR3AA1 1")
.withInstant(PREVENTIVE_INSTANT_ID)
.withOptimized(true)
.withOperator("operator1")
.withNominalVoltage(380.)
.withIMax(5000.);
monitoredCnecSides.forEach(side ->
cnecAdder1.newThreshold()
.withUnit(Unit.MEGAWATT)
.withSide(side)
.withMin(-1500.)
.withMax(1500.)
.add());
cnecAdder1.add();
FlowCnecAdder cnecAdder2 = crac.newFlowCnec()
.withId("cnec1stateCurativeContingency1")
.withNetworkElement("BBE2AA1 FFR3AA1 1")
.withInstant(CURATIVE_INSTANT_ID)
.withContingency("Contingency FR1 FR3")
.withOptimized(true)
.withOperator("operator1")
.withNominalVoltage(380.)
.withIMax(5000.);
monitoredCnecSides.forEach(side ->
cnecAdder2.newThreshold()
.withUnit(Unit.MEGAWATT)
.withSide(side)
.withMin(-1500.)
.withMax(1500.)
.add());
cnecAdder2.add();
FlowCnecAdder cnecAdder3 = crac.newFlowCnec()
.withId("cnec1stateCurativeContingency2")
.withNetworkElement("BBE2AA1 FFR3AA1 1")
.withInstant(CURATIVE_INSTANT_ID)
.withContingency("Contingency FR1 FR2")
.withOptimized(true)
.withOperator("operator1")
.withNominalVoltage(380.)
.withIMax(5000.);
monitoredCnecSides.forEach(side ->
cnecAdder3.newThreshold()
.withUnit(Unit.MEGAWATT)
.withSide(side)
.withMin(-1500.)
.withMax(1500.)
.add());
cnecAdder3.add();
FlowCnecAdder cnecAdder4 = crac.newFlowCnec()
.withId("cnec2basecase")
.withNetworkElement("FFR2AA1 DDE3AA1 1")
.withInstant(PREVENTIVE_INSTANT_ID)
.withOptimized(true)
.withOperator("operator2")
.withNominalVoltage(380.)
.withIMax(5000.);
monitoredCnecSides.forEach(side ->
cnecAdder4.newThreshold()
.withUnit(Unit.MEGAWATT)
.withSide(side)
.withMin(-1500.)
.withMax(1500.)
.add()
.newThreshold()
.withUnit(Unit.PERCENT_IMAX)
.withSide(side)
.withMin(-0.3)
.withMax(0.3)
.add());
cnecAdder4.add();
FlowCnecAdder cnecAdder5 = crac.newFlowCnec()
.withId("cnec2stateCurativeContingency1")
.withNetworkElement("FFR2AA1 DDE3AA1 1")
.withInstant(CURATIVE_INSTANT_ID)
.withContingency("Contingency FR1 FR3")
.withOptimized(true)
.withOperator("operator2")
.withNominalVoltage(380.)
.withIMax(5000.);
monitoredCnecSides.forEach(side ->
cnecAdder5.newThreshold()
.withUnit(Unit.MEGAWATT)
.withSide(side)
.withMin(-1500.)
.withMax(1500.)
.add()
.newThreshold()
.withUnit(Unit.PERCENT_IMAX)
.withSide(side)
.withMin(-0.3)
.withMax(0.3)
.add());
cnecAdder5.add();
FlowCnecAdder cnecAdder6 = crac.newFlowCnec()
.withId("cnec2stateCurativeContingency2")
.withNetworkElement("FFR2AA1 DDE3AA1 1")
.withInstant(CURATIVE_INSTANT_ID)
.withContingency("Contingency FR1 FR2")
.withOptimized(true)
.withOperator("operator2")
.withReliabilityMargin(95.)
.withNominalVoltage(380.)
.withIMax(5000.);
monitoredCnecSides.forEach(side ->
cnecAdder6.newThreshold()
.withUnit(Unit.MEGAWATT)
.withSide(TwoSides.ONE)
.withMin(-1500.)
.withMax(1500.)
.add()
.newThreshold()
.withUnit(Unit.PERCENT_IMAX)
.withSide(TwoSides.ONE)
.withMin(-0.3)
.withMax(0.3)
.add());
cnecAdder6.add();
return crac;
}
public static Crac createWithPreventivePstRange() {
return createWithPreventivePstRange(Set.of(TwoSides.ONE));
}
public static Crac createWithPreventivePstRange(Set<TwoSides> monitoredCnecSides) {
Crac crac = create(monitoredCnecSides);
Network network = NetworkImportsUtil.import12NodesNetwork();
IidmPstHelper pstHelper = new IidmPstHelper("BBE2AA1 BBE3AA1 1", network);
crac.newPstRangeAction()
.withId("pst")
.withNetworkElement("BBE2AA1 BBE3AA1 1", "BBE2AA1 BBE3AA1 1 name")
.withOperator("operator1")
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.newTapRange()
.withRangeType(RangeType.ABSOLUTE)
.withMinTap(-16)
.withMaxTap(16)
.add()
.withInitialTap(pstHelper.getInitialTap())
.withTapToAngleConversionMap(pstHelper.getTapToAngleConversionMap())
.add();
return crac;
}
public static Crac createWithCurativePstRange() {
Crac crac = create();
Network network = NetworkImportsUtil.import12NodesNetwork();
IidmPstHelper pstHelper = new IidmPstHelper("BBE2AA1 BBE3AA1 1", network);
crac.newPstRangeAction()
.withId("pst")
.withNetworkElement("BBE2AA1 BBE3AA1 1", "BBE2AA1 BBE3AA1 1 name")
.withOperator("operator1")
.newOnContingencyStateUsageRule()
.withInstant(CURATIVE_INSTANT_ID)
.withContingency("Contingency FR1 FR3")
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.newTapRange()
.withRangeType(RangeType.ABSOLUTE)
.withMinTap(-16)
.withMaxTap(16)
.add()
.withInitialTap(pstHelper.getInitialTap())
.withTapToAngleConversionMap(pstHelper.getTapToAngleConversionMap())
.add();
return crac;
}
public static Crac createWithPreventiveAndCurativePstRange() {
Crac crac = create();
Network network = NetworkImportsUtil.import12NodesNetwork();
IidmPstHelper pstHelper = new IidmPstHelper("BBE2AA1 BBE3AA1 1", network);
crac.newPstRangeAction()
.withId("pst")
.withNetworkElement("BBE2AA1 BBE3AA1 1", "BBE2AA1 BBE3AA1 1 name")
.withOperator("operator1")
.newOnInstantUsageRule().withInstant(PREVENTIVE_INSTANT_ID).withUsageMethod(UsageMethod.AVAILABLE).add()
.newOnContingencyStateUsageRule().withInstant(CURATIVE_INSTANT_ID).withContingency("Contingency FR1 FR3").withUsageMethod(UsageMethod.AVAILABLE).add()
.newTapRange()
.withRangeType(RangeType.ABSOLUTE)
.withMinTap(-16)
.withMaxTap(16)
.add()
.withInitialTap(pstHelper.getInitialTap())
.withTapToAngleConversionMap(pstHelper.getTapToAngleConversionMap())
.add();
return crac;
}
public static Crac createCracWithRemedialActions() {
Crac crac = new CracImplFactory().create("cracWithRemedialActions", "cracWithRemedialActions")
.newInstant(PREVENTIVE_INSTANT_ID, InstantKind.PREVENTIVE)
.newInstant(OUTAGE_INSTANT_ID, InstantKind.OUTAGE)
.newInstant(AUTO_INSTANT_ID, InstantKind.AUTO)
.newInstant(CURATIVE_INSTANT_ID, InstantKind.CURATIVE);
// Simple remedial actions (only one elementary action)
//// Topological actions
crac.newNetworkAction()
.withId("open-switch-1")
.newSwitchAction()
.withNetworkElement("switch-1")
.withActionType(ActionType.OPEN)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("close-switch-1")
.newSwitchAction()
.withNetworkElement("switch-1")
.withActionType(ActionType.CLOSE)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("open-switch-2")
.newSwitchAction()
.withNetworkElement("switch-2")
.withActionType(ActionType.OPEN)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("close-switch-2")
.newSwitchAction()
.withNetworkElement("switch-2")
.withActionType(ActionType.CLOSE)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
//// Injection setpoint actions
crac.newNetworkAction()
.withId("generator-1-75-mw")
.newGeneratorAction()
.withNetworkElement("generator-1")
.withActivePowerValue(75d)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("generator-1-100-mw")
.newGeneratorAction()
.withNetworkElement("generator-1")
.withActivePowerValue(100d)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("generator-2-75-mw")
.newGeneratorAction()
.withNetworkElement("generator-2")
.withActivePowerValue(75d)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("generator-2-100-mw")
.newGeneratorAction()
.withNetworkElement("generator-2")
.withActivePowerValue(100d)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
//// PST setpoint actions
crac.newNetworkAction()
.withId("pst-1-tap-3")
.newPhaseTapChangerTapPositionAction()
.withNetworkElement("pst-1")
.withTapPosition(3)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("pst-1-tap-8")
.newPhaseTapChangerTapPositionAction()
.withNetworkElement("pst-1")
.withTapPosition(8)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("pst-2-tap-3")
.newPhaseTapChangerTapPositionAction()
.withNetworkElement("pst-2")
.withTapPosition(3)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("pst-2-tap-8")
.newPhaseTapChangerTapPositionAction()
.withNetworkElement("pst-2")
.withTapPosition(8)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
//// Switch pairs
crac.newNetworkAction()
.withId("open-switch-1-close-switch-2")
.newSwitchPair()
.withSwitchToOpen("switch-1")
.withSwitchToClose("switch-2")
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("open-switch-2-close-switch-1")
.newSwitchPair()
.withSwitchToOpen("switch-2")
.withSwitchToClose("switch-1")
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("open-switch-3-close-switch-4")
.newSwitchPair()
.withSwitchToOpen("switch-3")
.withSwitchToClose("switch-4")
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("open-switch-1-close-switch-3")
.newSwitchPair()
.withSwitchToOpen("switch-1")
.withSwitchToClose("switch-3")
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("open-switch-3-close-switch-2")
.newSwitchPair()
.withSwitchToOpen("switch-3")
.withSwitchToClose("switch-2")
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
// Complex remedial actions (several elementary actions)
crac.newNetworkAction()
.withId("hvdc-fr-es-200-mw")
.newSwitchAction()
.withNetworkElement("switch-fr")
.withActionType(ActionType.OPEN)
.add()
.newSwitchAction()
.withNetworkElement("switch-es")
.withActionType(ActionType.OPEN)
.add()
.newGeneratorAction()
.withNetworkElement("generator-fr-1")
.withActivePowerValue(-100d)
.add()
.newGeneratorAction()
.withNetworkElement("generator-fr-2")
.withActivePowerValue(-100d)
.add()
.newGeneratorAction()
.withNetworkElement("generator-es-1")
.withActivePowerValue(100d)
.add()
.newGeneratorAction()
.withNetworkElement("generator-es-2")
.withActivePowerValue(100d)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("hvdc-es-fr-200-mw")
.newSwitchAction()
.withNetworkElement("switch-fr")
.withActionType(ActionType.OPEN)
.add()
.newSwitchAction()
.withNetworkElement("switch-es")
.withActionType(ActionType.OPEN)
.add()
.newGeneratorAction()
.withNetworkElement("generator-fr-1")
.withActivePowerValue(100d)
.add()
.newGeneratorAction()
.withNetworkElement("generator-fr-2")
.withActivePowerValue(100d)
.add()
.newGeneratorAction()
.withNetworkElement("generator-es-1")
.withActivePowerValue(-100d)
.add()
.newGeneratorAction()
.withNetworkElement("generator-es-2")
.withActivePowerValue(-100d)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("aligned-psts")
.newPhaseTapChangerTapPositionAction()
.withNetworkElement("pst-fr-1")
.withTapPosition(4)
.add()
.newPhaseTapChangerTapPositionAction()
.withNetworkElement("pst-fr-2")
.withTapPosition(4)
.add()
.newPhaseTapChangerTapPositionAction()
.withNetworkElement("pst-fr-3")
.withTapPosition(4)
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
crac.newNetworkAction()
.withId("switch-pair-and-pst")
.newPhaseTapChangerTapPositionAction()
.withNetworkElement("pst-fr-2")
.withTapPosition(-2)
.add()
.newSwitchPair()
.withSwitchToOpen("switch-fr")
.withSwitchToClose("switch-es")
.add()
.newOnInstantUsageRule()
.withInstant(PREVENTIVE_INSTANT_ID)
.withUsageMethod(UsageMethod.AVAILABLE)
.add()
.add();
return crac;
}
}