diff --git a/data/crac/crac-api/src/main/java/com/powsybl/openrao/data/cracapi/RemedialAction.java b/data/crac/crac-api/src/main/java/com/powsybl/openrao/data/cracapi/RemedialAction.java index 414529adad..4c717c9b4c 100644 --- a/data/crac/crac-api/src/main/java/com/powsybl/openrao/data/cracapi/RemedialAction.java +++ b/data/crac/crac-api/src/main/java/com/powsybl/openrao/data/cracapi/RemedialAction.java @@ -76,4 +76,6 @@ default Set> getLocation(Network network) { } OnContingencyStateAdderToRemedialAction newOnStateUsageRule(); + + double getActivationCost(); } diff --git a/data/crac/crac-api/src/main/java/com/powsybl/openrao/data/cracapi/RemedialActionAdder.java b/data/crac/crac-api/src/main/java/com/powsybl/openrao/data/cracapi/RemedialActionAdder.java index acd6a3eb0e..83df6d029e 100644 --- a/data/crac/crac-api/src/main/java/com/powsybl/openrao/data/cracapi/RemedialActionAdder.java +++ b/data/crac/crac-api/src/main/java/com/powsybl/openrao/data/cracapi/RemedialActionAdder.java @@ -18,6 +18,8 @@ public interface RemedialActionAdder> extends I T withSpeed(Integer speed); + T withActivationCost(double activationCost); + RemedialAction add(); OnInstantAdder newOnInstantUsageRule(); diff --git a/data/crac/crac-api/src/test/java/com/powsybl/openrao/data/cracapi/NetworkActionUtils.java b/data/crac/crac-api/src/test/java/com/powsybl/openrao/data/cracapi/NetworkActionUtils.java index fe7f1e102d..2c1ca6e106 100644 --- a/data/crac/crac-api/src/test/java/com/powsybl/openrao/data/cracapi/NetworkActionUtils.java +++ b/data/crac/crac-api/src/test/java/com/powsybl/openrao/data/cracapi/NetworkActionUtils.java @@ -63,6 +63,7 @@ public String getId() { public static class NetworkActionImplTest implements NetworkAction { private final Set elementaryActions; + private final double activationCost = 0; public NetworkActionImplTest(Set elementaryActions) { this.elementaryActions = new HashSet<>(elementaryActions); @@ -97,6 +98,11 @@ public UsageMethod getUsageMethod(State state) { return null; } + @Override + public double getActivationCost() { + return activationCost; + } + @Override public Optional getSpeed() { return Optional.empty(); diff --git a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRangeAction.java b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRangeAction.java index c0bc73aa51..9ef7c2c35b 100644 --- a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRangeAction.java +++ b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRangeAction.java @@ -24,6 +24,11 @@ public abstract class AbstractRangeAction> extends Abst this.groupId = groupId; } + AbstractRangeAction(String id, String name, String operator, Set usageRules, String groupId, Integer speed, double activationCost) { + super(id, name, operator, usageRules, speed, activationCost); + this.groupId = groupId; + } + @Override public Optional getGroupId() { return Optional.ofNullable(groupId); diff --git a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRemedialAction.java b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRemedialAction.java index 6746140fb2..487a9b42c1 100644 --- a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRemedialAction.java +++ b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRemedialAction.java @@ -32,6 +32,7 @@ public abstract class AbstractRemedialAction> extend private boolean computedUsageMethods = false; private Map usageMethodPerState; private Map usageMethodPerInstant; + private double activationCost = 0; protected AbstractRemedialAction(String id, String name, String operator, Set usageRules, Integer speed) { super(id, name); @@ -40,6 +41,14 @@ protected AbstractRemedialAction(String id, String name, String operator, Set usageRules, Integer speed, double activationCost) { + super(id, name); + this.operator = operator; + this.usageRules = usageRules; + this.speed = speed; + this.activationCost = activationCost; + } + void addUsageRule(UsageRule usageRule) { computedUsageMethods = false; this.usageRules.add(usageRule); @@ -79,6 +88,11 @@ public UsageMethod getUsageMethod(State state) { usageMethodPerInstant.getOrDefault(state.getInstant(), UsageMethod.UNDEFINED))); } + @Override + public double getActivationCost() { + return activationCost; + } + private void computeUsageMethodPerStateAndInstant() { usageMethodPerState = new HashMap<>(); usageMethodPerInstant = new HashMap<>(); diff --git a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRemedialActionAdder.java b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRemedialActionAdder.java index 024f46ab4a..6d0bc8df36 100644 --- a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRemedialActionAdder.java +++ b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/AbstractRemedialActionAdder.java @@ -20,10 +20,11 @@ */ public abstract class AbstractRemedialActionAdder> extends AbstractIdentifiableAdder implements RemedialActionAdder { + private final CracImpl crac; protected String operator; protected Integer speed; protected Set usageRules = new HashSet<>(); - private final CracImpl crac; + protected double activationCost; AbstractRemedialActionAdder(CracImpl crac) { Objects.requireNonNull(crac); @@ -42,6 +43,12 @@ public T withSpeed(Integer speed) { return (T) this; } + @Override + public T withActivationCost(double activationCost) { + this.activationCost = activationCost; + return (T) this; + } + @Override public OnInstantAdder newOnInstantUsageRule() { return new OnInstantAdderImpl(this); diff --git a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/CounterTradeRangeActionAdderImpl.java b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/CounterTradeRangeActionAdderImpl.java index 0f098a9089..05a2d59d67 100644 --- a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/CounterTradeRangeActionAdderImpl.java +++ b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/CounterTradeRangeActionAdderImpl.java @@ -67,7 +67,7 @@ public CounterTradeRangeAction add() { BUSINESS_WARNS.warn("CounterTradeRangeAction {} does not contain any usage rule, by default it will never be available", id); } - CounterTradeRangeAction counterTradeRangeAction = new CounterTradeRangeActionImpl(this.id, this.name, this.operator, this.groupId, this.usageRules, this.ranges, this.initialSetpoint, speed, this.exportingCountry, this.importingCountry); + CounterTradeRangeAction counterTradeRangeAction = new CounterTradeRangeActionImpl(this.id, this.name, this.operator, this.groupId, this.usageRules, this.ranges, this.initialSetpoint, speed, this.exportingCountry, this.importingCountry, activationCost); getCrac().addCounterTradeRangeAction(counterTradeRangeAction); return counterTradeRangeAction; diff --git a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/CounterTradeRangeActionImpl.java b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/CounterTradeRangeActionImpl.java index 44d1fd9813..f6f2468305 100644 --- a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/CounterTradeRangeActionImpl.java +++ b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/CounterTradeRangeActionImpl.java @@ -37,6 +37,15 @@ public class CounterTradeRangeActionImpl extends AbstractRangeAction usageRules, + List ranges, double initialSetpoint, Integer speed, Country exportingCountry, Country importingCountry, double activationCost) { + super(id, name, operator, usageRules, groupId, speed, activationCost); + this.ranges = ranges; + this.initialSetpoint = initialSetpoint; + this.exportingCountry = exportingCountry; + this.importingCountry = importingCountry; + } + @Override public List getRanges() { return ranges; diff --git a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/HvdcRangeActionAdderImpl.java b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/HvdcRangeActionAdderImpl.java index 061e694a80..e11f64185a 100644 --- a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/HvdcRangeActionAdderImpl.java +++ b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/HvdcRangeActionAdderImpl.java @@ -67,7 +67,7 @@ public HvdcRangeAction add() { } NetworkElement networkElement = this.getCrac().addNetworkElement(networkElementId, networkElementName); - HvdcRangeActionImpl hvdcWithRange = new HvdcRangeActionImpl(this.id, this.name, this.operator, this.usageRules, ranges, initialSetpoint, networkElement, groupId, speed); + HvdcRangeActionImpl hvdcWithRange = new HvdcRangeActionImpl(this.id, this.name, this.operator, this.usageRules, ranges, initialSetpoint, networkElement, groupId, speed, activationCost); this.getCrac().addHvdcRangeAction(hvdcWithRange); return hvdcWithRange; } diff --git a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/HvdcRangeActionImpl.java b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/HvdcRangeActionImpl.java index 19233aad30..f41c91748a 100644 --- a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/HvdcRangeActionImpl.java +++ b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/HvdcRangeActionImpl.java @@ -44,6 +44,14 @@ public class HvdcRangeActionImpl extends AbstractRangeAction im this.initialSetpoint = initialSetpoint; } + HvdcRangeActionImpl(String id, String name, String operator, Set usageRules, List ranges, + double initialSetpoint, NetworkElement networkElement, String groupId, Integer speed, double activationCost) { + super(id, name, operator, usageRules, groupId, speed, activationCost); + this.networkElement = networkElement; + this.ranges = ranges; + this.initialSetpoint = initialSetpoint; + } + @Override public NetworkElement getNetworkElement() { return networkElement; diff --git a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/InjectionRangeActionAdderImpl.java b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/InjectionRangeActionAdderImpl.java index cb4cdecff4..b18d8fae41 100644 --- a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/InjectionRangeActionAdderImpl.java +++ b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/InjectionRangeActionAdderImpl.java @@ -67,7 +67,7 @@ public InjectionRangeAction add() { } Map neAndDk = addNetworkElements(); - InjectionRangeAction injectionRangeAction = new InjectionRangeActionImpl(this.id, this.name, this.operator, this.groupId, this.usageRules, this.ranges, this.initialSetpoint, neAndDk, speed); + InjectionRangeAction injectionRangeAction = new InjectionRangeActionImpl(this.id, this.name, this.operator, this.groupId, this.usageRules, this.ranges, this.initialSetpoint, neAndDk, speed, activationCost); this.getCrac().addInjectionRangeAction(injectionRangeAction); return injectionRangeAction; } diff --git a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/InjectionRangeActionImpl.java b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/InjectionRangeActionImpl.java index 87f9adad66..347fe5bd37 100644 --- a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/InjectionRangeActionImpl.java +++ b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/InjectionRangeActionImpl.java @@ -41,6 +41,14 @@ public class InjectionRangeActionImpl extends AbstractRangeAction usageRules, + List ranges, double initialSetpoint, Map injectionDistributionKeys, Integer speed, double activationCost) { + super(id, name, operator, usageRules, groupId, speed, activationCost); + this.ranges = ranges; + this.initialSetpoint = initialSetpoint; + this.injectionDistributionKeys = injectionDistributionKeys; + } + @Override public Set getNetworkElements() { return injectionDistributionKeys.keySet(); diff --git a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/PstRangeActionAdderImpl.java b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/PstRangeActionAdderImpl.java index 22ab4fcd23..91cf3c80bd 100644 --- a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/PstRangeActionAdderImpl.java +++ b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/PstRangeActionAdderImpl.java @@ -98,7 +98,7 @@ public PstRangeAction add() { } NetworkElement networkElement = this.getCrac().addNetworkElement(networkElementId, networkElementName); - PstRangeActionImpl pstWithRange = new PstRangeActionImpl(this.id, this.name, this.operator, this.usageRules, validRanges, networkElement, groupId, initialTap, tapToAngleConversionMap, speed); + PstRangeActionImpl pstWithRange = new PstRangeActionImpl(this.id, this.name, this.operator, this.usageRules, validRanges, networkElement, groupId, initialTap, tapToAngleConversionMap, speed, activationCost); this.getCrac().addPstRangeAction(pstWithRange); return pstWithRange; } diff --git a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/PstRangeActionImpl.java b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/PstRangeActionImpl.java index ff5db65fb8..a6326c8eab 100644 --- a/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/PstRangeActionImpl.java +++ b/data/crac/crac-impl/src/main/java/com/powsybl/openrao/data/cracimpl/PstRangeActionImpl.java @@ -51,6 +51,18 @@ public final class PstRangeActionImpl extends AbstractRangeAction usageRules, List ranges, + NetworkElement networkElement, String groupId, int initialTap, Map tapToAngleConversionMap, Integer speed, double activationCost) { + super(id, name, operator, usageRules, groupId, speed, activationCost); + this.networkElement = networkElement; + this.ranges = ranges; + this.initialTapPosition = initialTap; + this.tapToAngleConversionMap = tapToAngleConversionMap; + this.lowTapPosition = Collections.min(tapToAngleConversionMap.keySet()); + this.highTapPosition = Collections.max(tapToAngleConversionMap.keySet()); + this.smallestAngleStep = computeSmallestAngleStep(); + } + @Override public NetworkElement getNetworkElement() { return networkElement; diff --git a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/JsonSerializationConstants.java b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/JsonSerializationConstants.java index b2a0625290..5eaec5fedb 100644 --- a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/JsonSerializationConstants.java +++ b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/JsonSerializationConstants.java @@ -70,6 +70,7 @@ private JsonSerializationConstants() { public static final String GROUP_ID = "groupId"; public static final String SPEED = "speed"; + public static final String COST = "cost"; public static final String CONTINGENCIES = "contingencies"; public static final String CONTINGENCY_ID = "contingencyId"; diff --git a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/PstRangeActionArrayDeserializer.java b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/PstRangeActionArrayDeserializer.java index c7cd381d4d..88766c173c 100644 --- a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/PstRangeActionArrayDeserializer.java +++ b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/PstRangeActionArrayDeserializer.java @@ -102,6 +102,10 @@ public static void deserialize(JsonParser jsonParser, String version, Crac crac, jsonParser.nextToken(); pstRangeActionAdder.withSpeed(jsonParser.getIntValue()); break; + case COST: + jsonParser.nextToken(); + pstRangeActionAdder.withActivationCost(jsonParser.getDoubleValue()); + break; default: throw new OpenRaoException("Unexpected field in PstRangeAction: " + jsonParser.getCurrentName()); } diff --git a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/StandardRangeActionDeserializer.java b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/StandardRangeActionDeserializer.java index 245911f93a..6c7625550a 100644 --- a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/StandardRangeActionDeserializer.java +++ b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/StandardRangeActionDeserializer.java @@ -99,6 +99,10 @@ public static boolean addCommonElement(StandardRangeActionAdder standardRange jsonParser.nextToken(); standardRangeActionAdder.withSpeed(jsonParser.getIntValue()); break; + case COST: + jsonParser.nextToken(); + standardRangeActionAdder.withActivationCost(jsonParser.getDoubleValue()); + break; default: return false; } diff --git a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/PstRangeActionSerializer.java b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/PstRangeActionSerializer.java index 23de2c9147..2e7edcce15 100644 --- a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/PstRangeActionSerializer.java +++ b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/PstRangeActionSerializer.java @@ -38,6 +38,7 @@ public void serialize(PstRangeAction value, JsonGenerator gen, SerializerProvide gen.writeObjectField(TAP_TO_ANGLE_CONVERSION_MAP, value.getTapToAngleConversionMap()); serializeRemedialActionSpeed(value, gen); serializeRanges(value, gen); + gen.writeNumberField(COST, value.getActivationCost()); gen.writeEndObject(); } diff --git a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/StandardRangeActionSerializer.java b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/StandardRangeActionSerializer.java index 8c8840a968..2a83b8700e 100644 --- a/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/StandardRangeActionSerializer.java +++ b/data/crac/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/StandardRangeActionSerializer.java @@ -32,6 +32,7 @@ public static void serializeCommon(StandardRangeAction value, JsonGenerator g serializeGroupId(value, gen); gen.writeNumberField(INITIAL_SETPOINT, value.getInitialSetpoint()); serializeRanges(value, gen); + gen.writeNumberField(COST, value.getActivationCost()); } private static void serializeGroupId(StandardRangeAction value, JsonGenerator gen) throws IOException { diff --git a/data/crac/crac-io/crac-io-json/src/test/java/com/powsybl/openrao/data/cracio/json/JsonRetrocompatibilityTest.java b/data/crac/crac-io/crac-io-json/src/test/java/com/powsybl/openrao/data/cracio/json/JsonRetrocompatibilityTest.java index 7453a279b9..c5c1e9bed4 100644 --- a/data/crac/crac-io/crac-io-json/src/test/java/com/powsybl/openrao/data/cracio/json/JsonRetrocompatibilityTest.java +++ b/data/crac/crac-io/crac-io-json/src/test/java/com/powsybl/openrao/data/cracio/json/JsonRetrocompatibilityTest.java @@ -21,6 +21,7 @@ import com.powsybl.openrao.data.cracapi.range.RangeType; import com.powsybl.openrao.data.cracapi.range.StandardRange; import com.powsybl.openrao.data.cracapi.range.TapRange; +import com.powsybl.openrao.data.cracapi.rangeaction.PstRangeAction; import com.powsybl.openrao.data.cracapi.rangeaction.RangeAction; import com.powsybl.openrao.data.cracapi.threshold.BranchThreshold; import com.powsybl.openrao.data.cracapi.threshold.Threshold; @@ -746,23 +747,27 @@ private void testContentOfV2Point2Crac(Crac crac) { private void testContentOfV2Point3Crac(Crac crac) { testContentOfV2Point2Crac(crac); + PstRangeAction pstRangeAction4 = crac.getPstRangeAction("pstRange4Id"); // check that RangeAction4 is present with new range relative to previous instant - assertNotNull(crac.getRangeAction("pstRange4Id")); - assertEquals(2, crac.getPstRangeAction("pstRange4Id").getRanges().size()); - TapRange absRange = crac.getPstRangeAction("pstRange4Id").getRanges().stream() - .filter(tapRange -> tapRange.getRangeType().equals(RangeType.ABSOLUTE)) - .findAny().orElse(null); - TapRange relTimeStepRange = crac.getPstRangeAction("pstRange4Id").getRanges().stream() - .filter(tapRange -> tapRange.getRangeType().equals(RangeType.RELATIVE_TO_PREVIOUS_TIME_STEP)) - .findAny().orElse(null); + assertNotNull(pstRangeAction4); - assertNotNull(absRange); - assertEquals(-2, absRange.getMinTap()); - assertEquals(7, absRange.getMaxTap()); - assertNotNull(relTimeStepRange); - assertEquals(-1, relTimeStepRange.getMinTap()); - assertEquals(4, relTimeStepRange.getMaxTap()); - assertEquals(Unit.TAP, relTimeStepRange.getUnit()); + // check Tap Range + assertEquals(2, pstRangeAction4.getRanges().size()); + + TapRange pstAbsRange = pstRangeAction4.getRanges().stream() + .filter(tapRange -> tapRange.getRangeType().equals(RangeType.ABSOLUTE)) + .findAny().orElse(null); + TapRange pstRelTimeStepRange = pstRangeAction4.getRanges().stream() + .filter(tapRange -> tapRange.getRangeType().equals(RangeType.RELATIVE_TO_PREVIOUS_TIME_STEP)) + .findAny().orElse(null); + assertNotNull(pstAbsRange); + assertEquals(-2, pstAbsRange.getMinTap()); + assertEquals(7, pstAbsRange.getMaxTap()); + assertNotNull(pstRelTimeStepRange); + assertEquals(-1, pstRelTimeStepRange.getMinTap()); + assertEquals(4, pstRelTimeStepRange.getMaxTap()); + assertEquals(Unit.TAP, pstRelTimeStepRange.getUnit()); + assertEquals(3.2, pstRangeAction4.getActivationCost()); // check new border attribute assertEquals("border1", crac.getCnec("cnec1outageId").getBorder()); diff --git a/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.3.json b/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.3.json index 46b68ec1a4..737a113e87 100644 --- a/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.3.json +++ b/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.3.json @@ -319,7 +319,8 @@ "min" : -1, "max" : 4, "rangeType" : "relativeToPreviousTimeStep" - } ] + } ], + "cost" : 3.2 } ], "hvdcRangeActions" : [ { "id" : "hvdcRange1Id", diff --git a/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.4.json b/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.4.json index b0052a082b..53cfbc5540 100644 --- a/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.4.json +++ b/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.4.json @@ -319,7 +319,8 @@ "min" : -1, "max" : 4, "rangeType" : "relativeToPreviousTimeStep" - } ] + } ], + "cost" : 3.2 } ], "hvdcRangeActions" : [ { "id" : "hvdcRange1Id", diff --git a/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.5.json b/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.5.json index 2f1fc42923..939f9b386b 100644 --- a/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.5.json +++ b/data/crac/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.5.json @@ -319,7 +319,8 @@ "min" : -1, "max" : 4, "rangeType" : "relativeToPreviousTimeStep" - } ] + } ], + "cost" : 3.2 } ], "hvdcRangeActions" : [ { "id" : "hvdcRange1Id", diff --git a/docs/castor/linear-problem.md b/docs/castor/linear-problem.md index 09927cd639..f16dad0436 100644 --- a/docs/castor/linear-problem.md +++ b/docs/castor/linear-problem.md @@ -5,6 +5,7 @@ linear-problem/core-problem-filler.md linear-problem/max-min-margin-filler.md linear-problem/max-min-relative-margin-filler.md +linear-problem/min-cost-filler.md linear-problem/max-loop-flow-filler.md linear-problem/mnec-filler.md linear-problem/continuous-range-action-group-filler.md diff --git a/docs/castor/linear-problem/min-cost-filler.md b/docs/castor/linear-problem/min-cost-filler.md new file mode 100644 index 0000000000..07fc512bd6 --- /dev/null +++ b/docs/castor/linear-problem/min-cost-filler.md @@ -0,0 +1,86 @@ +# Modelling the minimum cost objective + +## Used input data + + +| Name | Symbol | Details | +|--------------------|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| OptimisedFlowCnecs | $c \in \mathcal{C} ^{o}$ | Set of FlowCnecs[^1] which are ['optimised'](/input-data/crac/json.md#optimised-and-monitored-cnecs). OptimisedFlowCnecs is a subset of [FlowCnecs](core-problem-filler.md#used-input-data): $\mathcal{C} ^{o} \subset \mathcal{C}$ | +| RangeActions | $r \in \mathcal{RA(s)}$ | set of RangeActions available on state $s$, could be PSTs, HVDCs, or injection range actions | +| upper threshold | $f^{+}_{threshold} (c)$ | Upper threshold of FlowCnec $c$, in MW, as defined in the CRAC | +| lower threshold | $f^{-}_{threshold} (c)$ | Lower threshold of FlowCnec $c$, in MW, defined in the CRAC | +| activation cost | $ac(r)$ | Activation cost of RangeAction $r$, defined in the CRAC | + +[^1]: CNECs that belong to a state for which sensitivity computations failed are ignored in the MILP + +## Used parameters + +| Name | Details | +|------------------------------|-------------------------------------------------------------------------------------------------------------| +| [type](/parameters.md#type) | Used to set the unit (AMPERE/MW) of the flow values. The unit is only relevent for logging the worst CNECs. | + +## Defined optimization variables + +| Name | Symbol | Details | Type | Index | Unit | Lower bound | Upper bound | +|------------------|----------|------------------------------------------------------------------------------------------------------------------------------|-------------|--------------------------------------------------|-----------------------------------------------------------------------------------------------------|-------------|-------------| +| Minimum margin | $MM$ | The minimum margin over all OptimizedFlowCnecs. Serve as a penalty if margin is negative. Set to 0 if all Cnecs are secure. | Real value | one scalar variable for the whole problem | MW or AMPERE (depending on [objective-function](/parameters.md#objective-function-parameters) unit) | $-\infty$ | 0 | +| Total cost | $TC$ | The total cost for all RangeActions. | Real value | one scalar variable for the whole problem | | 0 | $+\infty$ | +| RangeAction cost | $C(r)$ | The cost for one RangeAction. | Real value | one variable for every element of (RangeActions) | | 0 | $+\infty$ | + +## Used optimization variables + +| Name | Symbol | Defined in | +|--------------------------------|-----------------|-----------------------------------------------------------------------------| +| Flow | $F(c)$ | [CoreProblemFiller](core-problem-filler.md#defined-optimization-variables) | +| RA setpoint absolute variation | $\Delta A(r,s)$ | [CoreProblemFiller](core-problem-filler.md#defined-optimization-variables) | + +## Defined constraints + +### Define the minimum margin variable + +$$ +\begin{equation} +MM \leq f^{+}_{threshold} (c) - F(c), \forall c \in \mathcal{C} ^{o} +\end{equation} +$$ + +$$ +\begin{equation} +MM \leq F(c) - f^{-}_{threshold} (c), \forall c \in \mathcal{C} ^{o} +\end{equation} +$$ + +Note that OptimizedFlowCnec might have only one threshold (upper or lower), in that case, only one of the two above constraints is defined. +
+ +$MM$ is non-positive, so if all CNECs are safe, the value of $MM$ will be $0$ + +### Define the RangeAction cost + +$$ +\begin{equation} +C(r) = ac(r) * \Delta A(r,s) +\end{equation} +$$ + +The cost of a RangeAction depends on the AbsoluteVariation of the setpoint. + +### Define the total cost + +$$ +\begin{equation} +TC = \sum_{r \in \mathcal{RA(s)}}C(r) +\end{equation} +$$ + +## Contribution to the objective function + +The total cost should be minimized, with a penalty added if min margin is negative: + +$$ +\begin{equation} +\min (TC - 1000 * MM) +\end{equation} +$$ + +The penalty coefficient was arbitrarily chosen to be $1000$. The coefficient needs to be high enough so that any solution that secures the network would have a lower cost that an unsecured network. \ No newline at end of file diff --git a/docs/parameters.md b/docs/parameters.md index dfca226a3e..3e63dbc64e 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -27,6 +27,8 @@ These parameters (objective-function) configure the remedial action optimisation - "MAX_MIN_MARGIN_IN_AMPERE" - "MAX_MIN_RELATIVE_MARGIN_IN_MEGAWATT" - "MAX_MIN_RELATIVE_MARGIN_IN_AMPERE" + - "MIN_COST_MEGAWATT" + - "MIN_COST_AMPERE" - **Default value**: "MAX_MIN_MARGIN_IN_MEGAWATT" - **Usage**: this parameter sets the objective function of the RAO. For now, the existing objective function are: - **MAX_MIN_MARGIN_IN_MEGAWATT**: maximization of the min(margin), where min(margin) is the smallest margin of all @@ -39,6 +41,8 @@ These parameters (objective-function) configure the remedial action optimisation (divided by the absolute sum of PTDFs) when they are positive. - **MAX_MIN_RELATIVE_MARGIN_IN_AMPERE**: same as MAX_MIN_MARGIN_IN_AMPERE, but the margins will be relative (divided by the absolute sum of PTDFs) when they are positive. + - **MIN_COST_MEGAWATT**: minimization of the cost of all active RangeActions. CNECs being secure is made through a constraint. + - **MIN_COST_AMPERE**: same as MIN_COST_MEGAWATT, but the worst margin logger will show flow values in ampere #### forbid-cost-increase - **Expected value**: true/false diff --git a/ra-optimisation/rao-api/src/main/java/com/powsybl/openrao/raoapi/parameters/ObjectiveFunctionParameters.java b/ra-optimisation/rao-api/src/main/java/com/powsybl/openrao/raoapi/parameters/ObjectiveFunctionParameters.java index f6d53f1491..6f04425b2a 100644 --- a/ra-optimisation/rao-api/src/main/java/com/powsybl/openrao/raoapi/parameters/ObjectiveFunctionParameters.java +++ b/ra-optimisation/rao-api/src/main/java/com/powsybl/openrao/raoapi/parameters/ObjectiveFunctionParameters.java @@ -40,7 +40,10 @@ public enum ObjectiveFunctionType { MAX_MIN_MARGIN_IN_MEGAWATT(Unit.MEGAWATT), MAX_MIN_MARGIN_IN_AMPERE(Unit.AMPERE), MAX_MIN_RELATIVE_MARGIN_IN_MEGAWATT(Unit.MEGAWATT), - MAX_MIN_RELATIVE_MARGIN_IN_AMPERE(Unit.AMPERE); + MAX_MIN_RELATIVE_MARGIN_IN_AMPERE(Unit.AMPERE), + // Unit is used for flow values, not for the cost + MIN_COST_MEGAWATT(Unit.MEGAWATT), + MIN_COST_AMPERE(Unit.AMPERE); private final Unit unit; @@ -55,6 +58,10 @@ public Unit getUnit() { public boolean relativePositiveMargins() { return this.equals(MAX_MIN_RELATIVE_MARGIN_IN_MEGAWATT) || this.equals(MAX_MIN_RELATIVE_MARGIN_IN_AMPERE); } + + public boolean isMinCost() { + return this.equals(MIN_COST_MEGAWATT) || this.equals(MIN_COST_AMPERE); + } } public enum PreventiveStopCriterion { diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/AutomatonSimulator.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/AutomatonSimulator.java index 3e75182a67..4ef91d4254 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/AutomatonSimulator.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/AutomatonSimulator.java @@ -40,6 +40,7 @@ import com.powsybl.iidm.network.extensions.HvdcAngleDroopActivePowerControl; import com.powsybl.loadflow.LoadFlow; import com.powsybl.loadflow.LoadFlowParameters; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; import com.powsybl.openrao.searchtreerao.searchtree.algorithms.SearchTree; import com.powsybl.openrao.searchtreerao.searchtree.inputs.SearchTreeInput; import com.powsybl.openrao.searchtreerao.searchtree.parameters.SearchTreeParameters; @@ -138,6 +139,7 @@ AutomatonPerimeterResultImpl simulateAutomatonState(State automatonState, Set() : new HashSet<>(autoSearchTreeResult.getActivatedNetworkActions()), rangeAutomatonSimulationResult.activatedRangeActions(), rangeAutomatonSimulationResult.rangeActionsWithSetpoint(), + prePerimeterSensitivityOutput, automatonState); TECHNICAL_LOGS.info("Automaton state {} has failed during sensitivity computation during range automaton simulation.", automatonState.getId()); RaoLogger.logFailedOptimizationSummary(BUSINESS_LOGS, automatonState, failedAutomatonPerimeterResultImpl.getActivatedNetworkActions(), getRangeActionsAndTheirTapsAppliedOnState(failedAutomatonPerimeterResultImpl, automatonState)); @@ -153,6 +155,7 @@ AutomatonPerimeterResultImpl simulateAutomatonState(State automatonState, Set() : new HashSet<>(autoSearchTreeResult.getActivatedNetworkActions()), rangeAutomatonSimulationResult.activatedRangeActions(), rangeActionsWithSetpoint, + prePerimeterSensitivityOutput, automatonState); TECHNICAL_LOGS.info("Automaton state {} has been optimized.", automatonState.getId()); RaoLogger.logOptimizationSummary(BUSINESS_LOGS, automatonState, automatonPerimeterResultImpl.getActivatedNetworkActions(), getRangeActionsAndTheirTapsAppliedOnState(automatonPerimeterResultImpl, automatonState), null, automatonPerimeterResultImpl); @@ -208,6 +211,7 @@ AutomatonPerimeterResultImpl createFailedAutomatonPerimeterResult(State autoStat new HashSet<>(), new HashSet<>(), new HashMap<>(), + prePerimeterSensitivityOutput, autoState); TECHNICAL_LOGS.info("Automaton state {} has failed during sensitivity computation {} topological automaton simulation.", autoState.getId(), defineMoment); RaoLogger.logFailedOptimizationSummary(BUSINESS_LOGS, autoState, failedAutomatonPerimeterResultImpl.getActivatedNetworkActions(), getRangeActionsAndTheirTapsAppliedOnState(failedAutomatonPerimeterResultImpl, autoState)); @@ -764,12 +768,13 @@ private PrePerimeterResult buildPrePerimeterResultForOptimizedState(PrePerimeter FlowResult flowResult = postAutoResult.getFlowResult(); SensitivityResult sensitivityResult = postAutoResult.getSensitivityResult(); RangeActionSetpointResult rangeActionSetpointResult = postAutoResult.getRangeActionSetpointResult(); + RangeActionActivationResult rangeActionActivationResult = new RangeActionActivationResultImpl(rangeActionSetpointResult); // Gather flowCnecs defined on optimizedState Set cnecsForOptimizedState = postAutoResult.getObjectiveFunction().getFlowCnecs().stream() .filter(flowCnec -> flowCnec.getState().equals(optimizedState)).collect(Collectors.toSet()); // Build ObjectiveFunctionResult based on cnecsForOptimizedState ObjectiveFunction objectiveFunction = ObjectiveFunction.create().build(cnecsForOptimizedState, toolProvider.getLoopFlowCnecs(cnecsForOptimizedState), initialFlowResult, prePerimeterSensitivityOutput, operatorsNotSharingCras, raoParameters); - ObjectiveFunctionResult objectiveFunctionResult = new ObjectiveFunctionResultImpl(objectiveFunction, flowResult); + ObjectiveFunctionResult objectiveFunctionResult = new ObjectiveFunctionResultImpl(objectiveFunction, flowResult, rangeActionActivationResult); return new PrePerimeterSensitivityResultImpl(flowResult, sensitivityResult, rangeActionSetpointResult, objectiveFunctionResult); } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorContingencyScenarios.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorContingencyScenarios.java index 179aba00f2..917987eb3d 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorContingencyScenarios.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorContingencyScenarios.java @@ -193,18 +193,16 @@ private OptimizationResult optimizeCurativePerimeter(Perimeter curativePerimeter .collect(Collectors.toSet()); Set loopFlowCnecs = AbstractOptimizationPerimeter.getLoopFlowCnecs(flowCnecs, raoParameters, network); - + Map, Double> rangeActionSetpointMap = crac.getPotentiallyAvailableRangeActions(curativeState) + .stream() + .collect(Collectors.toMap(rangeAction -> rangeAction, prePerimeterSensitivityOutput::getSetpoint)); + RangeActionSetpointResult rangeActionSetpointResult = new RangeActionSetpointResultImpl(rangeActionSetpointMap); + RangeActionActivationResult rangeActionsResult = new RangeActionActivationResultImpl(rangeActionSetpointResult); ObjectiveFunction objectiveFunction = ObjectiveFunction.create().build(flowCnecs, loopFlowCnecs, initialSensitivityOutput, prePerimeterSensitivityOutput, stateTree.getOperatorsNotSharingCras(), raoParameters); - ObjectiveFunctionResult objectiveFunctionResult = objectiveFunction.evaluate(prePerimeterSensitivityOutput); + ObjectiveFunctionResult objectiveFunctionResult = objectiveFunction.evaluate(prePerimeterSensitivityOutput, rangeActionsResult); boolean stopCriterionReached = isStopCriterionChecked(objectiveFunctionResult, curativeTreeParameters); if (stopCriterionReached) { NetworkActionsResult networkActionsResult = new NetworkActionsResultImpl(Collections.emptySet()); - - Map, Double> rangeActionSetpointMap = crac.getPotentiallyAvailableRangeActions(curativeState) - .stream() - .collect(Collectors.toMap(rangeAction -> rangeAction, prePerimeterSensitivityOutput::getSetpoint)); - RangeActionSetpointResult rangeActionSetpointResult = new RangeActionSetpointResultImpl(rangeActionSetpointMap); - RangeActionActivationResult rangeActionsResult = new RangeActionActivationResultImpl(rangeActionSetpointResult); return new OptimizationResultImpl(objectiveFunctionResult, prePerimeterSensitivityOutput, prePerimeterSensitivityOutput, networkActionsResult, rangeActionsResult); } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java index f3382a9cd6..47cb3b4ea4 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java @@ -87,6 +87,7 @@ public CompletableFuture run() { } RaoLogger.logSensitivityAnalysisResults("Initial sensitivity analysis: ", prePerimeterSensitivityAnalysis.getObjectiveFunction(), + new RangeActionActivationResultImpl(RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(raoInput.getNetwork(), raoInput.getCrac().getRangeActions())), initialOutput, raoParameters, NUMBER_LOGGED_ELEMENTS_DURING_RAO); @@ -130,6 +131,7 @@ public CompletableFuture run() { } RaoLogger.logSensitivityAnalysisResults("Systematic sensitivity analysis after preventive remedial actions: ", prePerimeterSensitivityAnalysis.getObjectiveFunction(), + new RangeActionActivationResultImpl(RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(network, crac.getRangeActions())), preCurativeSensitivityAnalysisOutput, raoParameters, NUMBER_LOGGED_ELEMENTS_DURING_RAO); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorSecondPreventive.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorSecondPreventive.java index 58fbb2c1bb..dcd6a591fd 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorSecondPreventive.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorSecondPreventive.java @@ -264,6 +264,7 @@ private SecondPreventiveRaoResult runSecondPreventiveRao(PrePerimeterSensitivity } RaoLogger.logSensitivityAnalysisResults("Systematic sensitivity analysis after curative remedial actions before second preventive optimization: ", prePerimeterSensitivityAnalysis.getObjectiveFunction(), + new RangeActionActivationResultImpl(RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(network, crac.getRangeActions())), sensiWithPostContingencyRemedialActions, raoParameters, NUMBER_LOGGED_ELEMENTS_DURING_RAO); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PrePerimeterSensitivityAnalysis.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PrePerimeterSensitivityAnalysis.java index e8842eac05..e5022cb2f7 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PrePerimeterSensitivityAnalysis.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/PrePerimeterSensitivityAnalysis.java @@ -17,6 +17,7 @@ import com.powsybl.openrao.searchtreerao.commons.SensitivityComputer; import com.powsybl.openrao.searchtreerao.commons.ToolProvider; import com.powsybl.openrao.searchtreerao.commons.objectivefunctionevaluator.ObjectiveFunction; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl; import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; import com.powsybl.iidm.network.Network; @@ -117,7 +118,8 @@ private PrePerimeterResult runAndGetResult(Network network, ObjectiveFunction ob FlowResult flowResult = sensitivityComputer.getBranchResult(network); SensitivityResult sensitivityResult = sensitivityComputer.getSensitivityResult(); RangeActionSetpointResult rangeActionSetpointResult = RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(network, rangeActions); - ObjectiveFunctionResult objectiveFunctionResult = getResult(objectiveFunction, flowResult); + RangeActionActivationResult rangeActionActivationResult = new RangeActionActivationResultImpl(rangeActionSetpointResult); + ObjectiveFunctionResult objectiveFunctionResult = getResult(objectiveFunction, flowResult, rangeActionActivationResult); return new PrePerimeterSensitivityResultImpl( flowResult, sensitivityResult, @@ -126,7 +128,7 @@ private PrePerimeterResult runAndGetResult(Network network, ObjectiveFunction ob ); } - private ObjectiveFunctionResult getResult(ObjectiveFunction objectiveFunction, FlowResult flowResult) { - return objectiveFunction.evaluate(flowResult); + private ObjectiveFunctionResult getResult(ObjectiveFunction objectiveFunction, FlowResult flowResult, RangeActionActivationResult rangeActionActivationResult) { + return objectiveFunction.evaluate(flowResult, rangeActionActivationResult); } } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/RaoLogger.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/RaoLogger.java index 6985636af1..9e07ed7803 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/RaoLogger.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/RaoLogger.java @@ -44,6 +44,7 @@ private RaoLogger() { public static void logSensitivityAnalysisResults(String prefix, ObjectiveFunction objectiveFunction, + RangeActionActivationResult rangeActionActivationResult, PrePerimeterResult sensitivityAnalysisResult, RaoParameters raoParameters, int numberOfLoggedLimitingElements) { @@ -52,7 +53,7 @@ public static void logSensitivityAnalysisResults(String prefix, return; } - ObjectiveFunctionResult prePerimeterObjectiveFunctionResult = objectiveFunction.evaluate(sensitivityAnalysisResult); + ObjectiveFunctionResult prePerimeterObjectiveFunctionResult = objectiveFunction.evaluate(sensitivityAnalysisResult, rangeActionActivationResult); BUSINESS_LOGS.info(prefix + "cost = {} (functional: {}, virtual: {})", formatDoubleBasedOnMargin(prePerimeterObjectiveFunctionResult.getCost(), -prePerimeterObjectiveFunctionResult.getCost()), diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ActivationCostEvaluator.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ActivationCostEvaluator.java new file mode 100644 index 0000000000..3c95736e5d --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ActivationCostEvaluator.java @@ -0,0 +1,95 @@ +/* + * 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.searchtreerao.commons.objectivefunctionevaluator; + +import com.powsybl.openrao.commons.Unit; +import com.powsybl.openrao.data.cracapi.cnec.Cnec; +import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; +import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionActivationResult; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +/** + * @author Jeremy Wang {@literal } + */ +public class ActivationCostEvaluator implements CostEvaluator { + private final Set flowCnecs; + private final Unit unit; + private final MarginEvaluator marginEvaluator; + private static final double MARGIN_PENALTY_COEFFICIENT = 1000; + + public ActivationCostEvaluator(Set flowCnecs, Unit unit, MarginEvaluator marginEvaluator) { + this.flowCnecs = flowCnecs; + this.unit = unit; + this.marginEvaluator = marginEvaluator; + } + + @Override + public String getName() { + return "activation-cost-evaluator"; + } + + @Override + public Unit getUnit() { + return unit; + } + + private List getCostlyElements(FlowResult flowResult, Set contingenciesToExclude) { + Map margins = new HashMap<>(); + + flowCnecs.stream() + .filter(cnec -> cnec.getState().getContingency().isEmpty() || !contingenciesToExclude.contains(cnec.getState().getContingency().get().getId())) + .filter(Cnec::isOptimized) + .forEach(flowCnec -> margins.put(flowCnec, marginEvaluator.getMargin(flowResult, flowCnec, unit))); + + return margins.keySet().stream() + .filter(Cnec::isOptimized) + .sorted(Comparator.comparing(margins::get)) + .toList(); + } + + @Override + public Set getFlowCnecs() { + return flowCnecs; + } + + @Override + public Pair> computeCostAndLimitingElements(FlowResult flowResult, RangeActionActivationResult rangeActionActivationResult, Set contingenciesToExclude) { + List costlyElements = getCostlyElements(flowResult, contingenciesToExclude); + FlowCnec limitingElement; + if (costlyElements.isEmpty()) { + limitingElement = null; + } else { + limitingElement = costlyElements.get(0); + } + // Cost is the activation cost of the range action + // + need to add a huge penalty if not secure + + double activationCost = getTotalActivationCostFromRangeActions(rangeActionActivationResult); + + double margin = marginEvaluator.getMargin(flowResult, limitingElement, unit); + if (margin < 0) { + activationCost -= MARGIN_PENALTY_COEFFICIENT * margin; + } + return Pair.of(activationCost, costlyElements); + } + + private double getTotalActivationCostFromRangeActions(RangeActionActivationResult rangeActionActivationResult) { + AtomicReference totalActivationCost = new AtomicReference<>((double) 0); + + rangeActionActivationResult.getStatesPerRangeAction().forEach((rangeAction, states) -> states.forEach(state -> { + double absoluteVariation = Math.abs(rangeActionActivationResult.getOptimizedSetpoint(rangeAction, state) - rangeActionActivationResult.getOptimizedSetpointOnStatePreceding(rangeAction, state)); + totalActivationCost.updateAndGet(v -> v + rangeAction.getActivationCost() * absoluteVariation); + })); + + return totalActivationCost.get(); + } +} diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/CostEvaluator.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/CostEvaluator.java index dd643d289f..e9e3e97b18 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/CostEvaluator.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/CostEvaluator.java @@ -10,6 +10,7 @@ import com.powsybl.openrao.commons.Unit; import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionActivationResult; import org.apache.commons.lang3.tuple.Pair; import java.util.HashSet; @@ -30,11 +31,11 @@ public interface CostEvaluator { * @param flowResult : the flow computation result * @return Double value of the RaoData cost. */ - default Pair> computeCostAndLimitingElements(FlowResult flowResult) { - return computeCostAndLimitingElements(flowResult, new HashSet<>()); + default Pair> computeCostAndLimitingElements(FlowResult flowResult, RangeActionActivationResult rangeActionActivationResult) { + return computeCostAndLimitingElements(flowResult, rangeActionActivationResult, new HashSet<>()); } - Pair> computeCostAndLimitingElements(FlowResult flowResult, Set contingenciesToExclude); + Pair> computeCostAndLimitingElements(FlowResult flowResult, RangeActionActivationResult rangeActionActivationResult, Set contingenciesToExclude); Unit getUnit(); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/LoopFlowViolationCostEvaluator.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/LoopFlowViolationCostEvaluator.java index 31d10a9421..e8feb1ffe4 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/LoopFlowViolationCostEvaluator.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/LoopFlowViolationCostEvaluator.java @@ -13,6 +13,7 @@ import com.powsybl.openrao.data.cracloopflowextension.LoopFlowThreshold; import com.powsybl.openrao.raoapi.parameters.extensions.LoopFlowParametersExtension; import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionActivationResult; import org.apache.commons.lang3.tuple.Pair; import java.util.*; @@ -43,7 +44,7 @@ public String getName() { } @Override - public Pair> computeCostAndLimitingElements(FlowResult flowResult, Set contingenciesToExclude) { + public Pair> computeCostAndLimitingElements(FlowResult flowResult, RangeActionActivationResult rangeActionActivationResult, Set contingenciesToExclude) { List costlyElements = getCostlyElements(flowResult, contingenciesToExclude); double cost = costlyElements .stream() diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MinMarginEvaluator.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MinMarginEvaluator.java index f0f3b9af45..48112a6ad4 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MinMarginEvaluator.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MinMarginEvaluator.java @@ -12,6 +12,7 @@ import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; import com.powsybl.iidm.network.TwoSides; import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionActivationResult; import org.apache.commons.lang3.tuple.Pair; import java.util.*; @@ -61,7 +62,7 @@ public Set getFlowCnecs() { } @Override - public Pair> computeCostAndLimitingElements(FlowResult flowResult, Set contingenciesToExclude) { + public Pair> computeCostAndLimitingElements(FlowResult flowResult, RangeActionActivationResult rangeActionActivationResult, Set contingenciesToExclude) { List costlyElements = getCostlyElements(flowResult, contingenciesToExclude); FlowCnec limitingElement; if (costlyElements.isEmpty()) { diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MnecViolationCostEvaluator.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MnecViolationCostEvaluator.java index ff66d30ea8..82eb24649f 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MnecViolationCostEvaluator.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MnecViolationCostEvaluator.java @@ -12,6 +12,7 @@ import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; import com.powsybl.openrao.raoapi.parameters.extensions.MnecParametersExtension; import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionActivationResult; import org.apache.commons.lang3.tuple.Pair; import java.util.*; @@ -51,7 +52,7 @@ private double computeCost(FlowResult flowResult, FlowCnec mnec) { } @Override - public Pair> computeCostAndLimitingElements(FlowResult flowResult, Set contingenciesToExclude) { + public Pair> computeCostAndLimitingElements(FlowResult flowResult, RangeActionActivationResult rangeActionActivationResult, Set contingenciesToExclude) { if (Math.abs(mnecViolationCost) < 1e-10) { return Pair.of(0., new ArrayList<>()); } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunction.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunction.java index ce55040e9a..5c1d88dff7 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunction.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunction.java @@ -30,8 +30,8 @@ private ObjectiveFunction(CostEvaluator functionalCostEvaluator, List getFlowCnecs() { return allFlowCnecs; } - public Pair> getFunctionalCostAndLimitingElements(FlowResult flowResult) { - return functionalCostEvaluator.computeCostAndLimitingElements(flowResult); + public Pair> getFunctionalCostAndLimitingElements(FlowResult flowResult, RangeActionActivationResult rangeActionActivationResult) { + return functionalCostEvaluator.computeCostAndLimitingElements(flowResult, rangeActionActivationResult); } - public Pair> getFunctionalCostAndLimitingElements(FlowResult flowResult, Set contingenciesToExclude) { - return functionalCostEvaluator.computeCostAndLimitingElements(flowResult, contingenciesToExclude); + public Pair> getFunctionalCostAndLimitingElements(FlowResult flowResult, RangeActionActivationResult rangeActionActivationResult, Set contingenciesToExclude) { + return functionalCostEvaluator.computeCostAndLimitingElements(flowResult, rangeActionActivationResult, contingenciesToExclude); } public Set getVirtualCostNames() { return virtualCostEvaluators.stream().map(CostEvaluator::getName).collect(Collectors.toSet()); } - public Pair> getVirtualCostAndCostlyElements(FlowResult flowResult, String virtualCostName, Set contingenciesToExclude) { + public Pair> getVirtualCostAndCostlyElements(FlowResult flowResult, RangeActionActivationResult rangeActionActivationResult, String virtualCostName, Set contingenciesToExclude) { return virtualCostEvaluators.stream() .filter(costEvaluator -> costEvaluator.getName().equals(virtualCostName)) .findAny() - .map(costEvaluator -> costEvaluator.computeCostAndLimitingElements(flowResult, contingenciesToExclude)) + .map(costEvaluator -> costEvaluator.computeCostAndLimitingElements(flowResult, rangeActionActivationResult, contingenciesToExclude)) .orElse(Pair.of(Double.NaN, new ArrayList<>())); } @@ -78,8 +78,11 @@ public ObjectiveFunction buildForInitialSensitivityComputation(Set flo marginEvaluator = new BasicMarginEvaluator(); } - this.withFunctionalCostEvaluator(new MinMarginEvaluator(flowCnecs, raoParameters.getObjectiveFunctionParameters().getType().getUnit(), marginEvaluator)); - + if (raoParameters.getObjectiveFunctionParameters().getType().isMinCost()) { + this.withFunctionalCostEvaluator(new ActivationCostEvaluator(flowCnecs, raoParameters.getObjectiveFunctionParameters().getType().getUnit(), marginEvaluator)); + } else { + this.withFunctionalCostEvaluator(new MinMarginEvaluator(flowCnecs, raoParameters.getObjectiveFunctionParameters().getType().getUnit(), marginEvaluator)); + } // sensitivity failure over-cost should be computed on initial sensitivity result too // (this allows the RAO to prefer RAs that can remove sensitivity failures) if (raoParameters.getLoadFlowAndSensitivityParameters().getSensitivityFailureOvercost() > 0) { @@ -96,6 +99,13 @@ public ObjectiveFunction build(Set flowCnecs, Set operatorsNotToOptimizeInCurative, RaoParameters raoParameters) { + withFunctionalCostEvaluator(flowCnecs, prePerimeterFlowResult, operatorsNotToOptimizeInCurative, raoParameters); + withVirtualCostEvaluators(flowCnecs, loopFlowCnecs, initialFlowResult, raoParameters); + + return this.build(); + } + + private void withFunctionalCostEvaluator(Set flowCnecs, FlowResult prePerimeterFlowResult, Set operatorsNotToOptimizeInCurative, RaoParameters raoParameters) { // min margin objective function MarginEvaluator marginEvaluator; if (raoParameters.getObjectiveFunctionParameters().getType().relativePositiveMargins()) { @@ -107,13 +117,17 @@ public ObjectiveFunction build(Set flowCnecs, // Unoptimized cnecs in operatorsNotToOptimizeInCurative countries if (raoParameters.getNotOptimizedCnecsParameters().getDoNotOptimizeCurativeCnecsForTsosWithoutCras() && !operatorsNotToOptimizeInCurative.isEmpty()) { + marginEvaluator = new MarginEvaluatorWithMarginDecreaseUnoptimizedCnecs(marginEvaluator, operatorsNotToOptimizeInCurative, prePerimeterFlowResult); + } - this.withFunctionalCostEvaluator(new MinMarginEvaluator(flowCnecs, raoParameters.getObjectiveFunctionParameters().getType().getUnit(), - new MarginEvaluatorWithMarginDecreaseUnoptimizedCnecs(marginEvaluator, operatorsNotToOptimizeInCurative, prePerimeterFlowResult))); + if (raoParameters.getObjectiveFunctionParameters().getType().isMinCost()) { + this.withFunctionalCostEvaluator(new ActivationCostEvaluator(flowCnecs, raoParameters.getObjectiveFunctionParameters().getType().getUnit(), marginEvaluator)); } else { this.withFunctionalCostEvaluator(new MinMarginEvaluator(flowCnecs, raoParameters.getObjectiveFunctionParameters().getType().getUnit(), marginEvaluator)); } + } + private void withVirtualCostEvaluators(Set flowCnecs, Set loopFlowCnecs, FlowResult initialFlowResult, RaoParameters raoParameters) { // mnec virtual cost evaluator if (raoParameters.hasExtension(MnecParametersExtension.class)) { this.withVirtualCostEvaluator(new MnecViolationCostEvaluator( @@ -138,8 +152,6 @@ public ObjectiveFunction build(Set flowCnecs, if (raoParameters.getLoadFlowAndSensitivityParameters().getSensitivityFailureOvercost() > 0) { this.withVirtualCostEvaluator(new SensitivityFailureOvercostEvaluator(flowCnecs, raoParameters.getLoadFlowAndSensitivityParameters().getSensitivityFailureOvercost())); } - - return this.build(); } public ObjectiveFunctionBuilder withFunctionalCostEvaluator(CostEvaluator costEvaluator) { diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunctionResultImpl.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunctionResultImpl.java index db67beae4c..6ee7c4654d 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunctionResultImpl.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunctionResultImpl.java @@ -10,6 +10,7 @@ import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; import com.powsybl.openrao.searchtreerao.result.api.FlowResult; import com.powsybl.openrao.searchtreerao.result.api.ObjectiveFunctionResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionActivationResult; import org.apache.commons.lang3.tuple.Pair; import java.util.*; @@ -20,6 +21,7 @@ public class ObjectiveFunctionResultImpl implements ObjectiveFunctionResult { private final ObjectiveFunction objectiveFunction; private final FlowResult flowResult; + private final RangeActionActivationResult rangeActionActivationResult; private boolean areCostsComputed; private Double functionalCost; private Map virtualCosts; @@ -29,9 +31,11 @@ public class ObjectiveFunctionResultImpl implements ObjectiveFunctionResult { private Set excludedContingencies; public ObjectiveFunctionResultImpl(ObjectiveFunction objectiveFunction, - FlowResult flowResult) { + FlowResult flowResult, + RangeActionActivationResult rangeActionActivationResult) { this.objectiveFunction = objectiveFunction; this.flowResult = flowResult; + this.rangeActionActivationResult = rangeActionActivationResult; this.areCostsComputed = false; } @@ -96,13 +100,13 @@ public void excludeContingencies(Set contingenciesToExclude) { } private void computeCosts(Set contingenciesToExclude) { - Pair> functionalCostAndLimitingElements = objectiveFunction.getFunctionalCostAndLimitingElements(flowResult, contingenciesToExclude); + Pair> functionalCostAndLimitingElements = objectiveFunction.getFunctionalCostAndLimitingElements(flowResult, rangeActionActivationResult, contingenciesToExclude); functionalCost = functionalCostAndLimitingElements.getLeft(); orderedLimitingElements = functionalCostAndLimitingElements.getRight(); virtualCosts = new HashMap<>(); orderedCostlyElements = new HashMap<>(); getVirtualCostNames().forEach(vcn -> { - Pair> virtualCostAndCostlyElements = objectiveFunction.getVirtualCostAndCostlyElements(flowResult, vcn, contingenciesToExclude); + Pair> virtualCostAndCostlyElements = objectiveFunction.getVirtualCostAndCostlyElements(flowResult, rangeActionActivationResult, vcn, contingenciesToExclude); virtualCosts.put(vcn, virtualCostAndCostlyElements.getLeft()); orderedCostlyElements.put(vcn, virtualCostAndCostlyElements.getRight()); }); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/SensitivityFailureOvercostEvaluator.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/SensitivityFailureOvercostEvaluator.java index 2c87d7dcef..f3d6a2a76f 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/SensitivityFailureOvercostEvaluator.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/SensitivityFailureOvercostEvaluator.java @@ -14,6 +14,7 @@ import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; import com.powsybl.openrao.data.raoresultapi.ComputationStatus; import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionActivationResult; import org.apache.commons.lang3.tuple.Pair; import java.util.*; @@ -39,7 +40,7 @@ public String getName() { } @Override - public Pair> computeCostAndLimitingElements(FlowResult flowResult, Set contingenciesToExclude) { + public Pair> computeCostAndLimitingElements(FlowResult flowResult, RangeActionActivationResult rangeActionActivationResult, Set contingenciesToExclude) { if (flowResult.getComputationStatus() == ComputationStatus.FAILURE) { TECHNICAL_LOGS.info(String.format("Sensitivity failure : assigning virtual overcost of %s", sensitivityFailureOvercost)); return Pair.of(sensitivityFailureOvercost, new ArrayList<>()); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizer.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizer.java index 28db4217c9..80e52a5fe9 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizer.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizer.java @@ -216,7 +216,7 @@ private static IteratingLinearOptimizationResultImpl createResult(FlowResult flo int nbOfIterations, ObjectiveFunction objectiveFunction) { return new IteratingLinearOptimizationResultImpl(LinearProblemStatus.OPTIMAL, nbOfIterations, rangeActionActivation, flowResult, - objectiveFunction.evaluate(flowResult), sensitivityResult); + objectiveFunction.evaluate(flowResult, rangeActionActivation), sensitivityResult); } private static Pair updateBestResultAndCheckStopCondition(boolean raRangeShrinking, LinearProblem linearProblem, IteratingLinearOptimizerInput input, int iteration, IteratingLinearOptimizationResultImpl currentResult, IteratingLinearOptimizationResultImpl bestResult) { diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFiller.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFiller.java new file mode 100644 index 0000000000..82d2ee8196 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFiller.java @@ -0,0 +1,184 @@ +/* + * 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.searchtreerao.linearoptimisation.algorithms.fillers; + +import com.powsybl.openrao.data.cracapi.Identifiable; +import com.powsybl.openrao.data.cracapi.State; +import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; +import com.powsybl.openrao.data.cracapi.rangeaction.RangeAction; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.LinearProblem; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPConstraint; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPVariable; +import com.powsybl.openrao.searchtreerao.result.api.FlowResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionActivationResult; +import com.powsybl.openrao.searchtreerao.result.api.SensitivityResult; + +import java.util.*; + +import static com.powsybl.openrao.commons.Unit.MEGAWATT; + +/** + * @author Jeremy Wang {@literal } + */ +public class MinCostFiller implements ProblemFiller { + private static final double MARGIN_PENALTY_COEFFICIENT = 1000; + protected final Set optimizedCnecs; + private final Map>> rangeActions; + + public MinCostFiller(Set optimizedCnecs, + Map>> rangeActions) { + this.rangeActions = rangeActions; + this.optimizedCnecs = new TreeSet<>(Comparator.comparing(Identifiable::getId)); + this.optimizedCnecs.addAll(optimizedCnecs); + } + + @Override + public void fill(LinearProblem linearProblem, FlowResult flowResult, SensitivityResult sensitivityResult, RangeActionActivationResult rangeActionActivationResult) { + Set validFlowCnecs = FillersUtil.getFlowCnecsComputationStatusOk(optimizedCnecs, sensitivityResult); + + // build variables + buildTotalCostVariable(linearProblem); + buildRangeActionCostVariable(linearProblem); + buildMinimumMarginVariable(linearProblem, validFlowCnecs); + + // build constraints + buildSecureCnecsConstraints(linearProblem, validFlowCnecs); + buildRangeActionCostConstraints(linearProblem); + buildTotalCostConstraint(linearProblem); + + // complete objective + fillObjectiveWithActivationCost(linearProblem); + } + + @Override + public void updateBetweenMipIteration(LinearProblem linearProblem, RangeActionActivationResult rangeActionActivationResult) { + // Objective does not change, nothing to do + } + + /** + * Build the total cost variable TC. + * TC represents the activation cost of all range actions. + */ + private void buildTotalCostVariable(LinearProblem linearProblem) { + linearProblem.addTotalCostVariable(0, linearProblem.infinity()); + } + + /** + * Build one varible cost C[r] for each RangeAction r. + * This variable describes the cost of applying a RangeAction. + */ + private void buildRangeActionCostVariable(LinearProblem linearProblem) { + rangeActions.forEach((state, rangeActionSet) -> + rangeActionSet.forEach(rangeAction -> linearProblem.addRangeActionCostVariable(0, linearProblem.infinity(), rangeAction, state))); + } + + /** + * Build the minimum margin variable MM. + * MM represents the smallest margin of all Cnecs. + * It is given in MEGAWATT. + * MM is used for penalty if the network is unsecure. + */ + private void buildMinimumMarginVariable(LinearProblem linearProblem, Set validFlowCnecs) { + if (!validFlowCnecs.isEmpty()) { + // ub is set to 0: MM value is 0 if network is secure + linearProblem.addMinimumMarginVariable(-linearProblem.infinity(), 0); + } else { + // if there is no Cnecs, the minMarginVariable is forced to zero. + // otherwise it would be unbounded in the LP + linearProblem.addMinimumMarginVariable(0.0, 0.0); + } + } + + /** + * Build two min/max constraints for each Cnec c. + * If network is secure MM value is 0. + * If network is unsecure MM value is inferior 0 and serve as a penalty. + *

+ * For each Cnec c, the constraints are: + *

+ * MM <= fmax[c] - F[c] (ABOVE_THRESHOLD) + * MM <= F[c] - fmin[c] (BELOW_THRESHOLD) + */ + private void buildSecureCnecsConstraints(LinearProblem linearProblem, Set validFlowCnecs) { + OpenRaoMPVariable minimumMarginVariable = linearProblem.getMinimumMarginVariable(); + + validFlowCnecs.forEach(cnec -> cnec.getMonitoredSides().forEach(side -> { + OpenRaoMPVariable flowVariable = linearProblem.getFlowVariable(cnec, side); + + Optional minFlow; + Optional maxFlow; + minFlow = cnec.getLowerBound(side, MEGAWATT); + maxFlow = cnec.getUpperBound(side, MEGAWATT); + + if (minFlow.isPresent()) { + OpenRaoMPConstraint minimumMarginNegative = linearProblem.addMinimumMarginConstraint(-linearProblem.infinity(), -minFlow.get(), cnec, side, LinearProblem.MarginExtension.BELOW_THRESHOLD); + minimumMarginNegative.setCoefficient(minimumMarginVariable, 1); + minimumMarginNegative.setCoefficient(flowVariable, -1); + } + + if (maxFlow.isPresent()) { + OpenRaoMPConstraint minimumMarginPositive = linearProblem.addMinimumMarginConstraint(-linearProblem.infinity(), maxFlow.get(), cnec, side, LinearProblem.MarginExtension.ABOVE_THRESHOLD); + minimumMarginPositive.setCoefficient(minimumMarginVariable, 1); + minimumMarginPositive.setCoefficient(flowVariable, 1); + } + })); + } + + /** + * Build constraint for total cost + * total cost is the sum of all costs for all RangeActions + * TC = sum(C[r]) + */ + private void buildTotalCostConstraint(LinearProblem linearProblem) { + // create constraint & add variable cost (objective function) + OpenRaoMPVariable totalCostVariable = linearProblem.getTotalCostVariable(); + OpenRaoMPConstraint totalCostConstraint = linearProblem.addTotalCostConstraint(0, 0); + totalCostConstraint.setCoefficient(totalCostVariable, 1); + + // create constraint to set margin to 0 + + rangeActions.forEach((state, rangeActionSet) -> + rangeActionSet.forEach(rangeAction -> { + OpenRaoMPVariable rangeActionCostVariable = linearProblem.getRangeActionCostVariable(rangeAction, state); + totalCostConstraint.setCoefficient(rangeActionCostVariable, -1); + })); + } + + /** + * Build constraints for each RangeAction cost C[r]. + * The cost is + * C[r] = activationCost * AV[r] + * where AV[r] is the absolute variation variable + */ + private void buildRangeActionCostConstraints(LinearProblem linearProblem) { + rangeActions.forEach((state, rangeActionSet) -> + rangeActionSet.forEach(rangeAction -> { + OpenRaoMPConstraint rangeActionCostConstraint = linearProblem.addRangeActionCostConstraint(0, 0, rangeAction, state); + OpenRaoMPVariable rangeActionCostVariable = linearProblem.getRangeActionCostVariable(rangeAction, state); + OpenRaoMPVariable absoluteVariationVariable = linearProblem.getAbsoluteRangeActionVariationVariable(rangeAction, state); + rangeActionCostConstraint.setCoefficient(rangeActionCostVariable, 1); + rangeActionCostConstraint.setCoefficient(absoluteVariationVariable, -rangeAction.getActivationCost()); + })); + } + + /** + * Add in the objective function of the linear problem the total cost TC + * Add min margin as penalty if unsecure. + * min(TC - MARGIN_PENALTY_COEFFICIENT * MM) + */ + private void fillObjectiveWithActivationCost(LinearProblem linearProblem) { + OpenRaoMPVariable totalCostVariable = linearProblem.getTotalCostVariable(); + linearProblem.getObjective().setCoefficient(totalCostVariable, 1); + OpenRaoMPVariable minimumMarginVariable = linearProblem.getMinimumMarginVariable(); + // MARGIN_PENALTY_COEFFICIENT value is arbitrary for now + linearProblem.getObjective().setCoefficient(minimumMarginVariable, -MARGIN_PENALTY_COEFFICIENT); + + } + +} + diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblem.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblem.java index 67c731a3ff..cdd80894c7 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblem.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblem.java @@ -331,6 +331,38 @@ public OpenRaoMPVariable getMinimumRelativeMarginSignBinaryVariable() { return solver.getVariable(minimumRelativeMarginSignBinaryVariableId()); } + public OpenRaoMPVariable addTotalCostVariable(double lb, double ub) { + return solver.makeNumVar(lb, ub, totalCostVariableId()); + } + + public OpenRaoMPVariable getTotalCostVariable() { + return solver.getVariable(totalCostVariableId()); + } + + public OpenRaoMPVariable addRangeActionCostVariable(double lb, double ub, RangeAction rangeAction, State state) { + return solver.makeNumVar(lb, ub, rangeActionCostVariableId(rangeAction, state)); + } + + public OpenRaoMPVariable getRangeActionCostVariable(RangeAction rangeAction, State state) { + return solver.getVariable(rangeActionCostVariableId(rangeAction, state)); + } + + public OpenRaoMPConstraint addTotalCostConstraint(double lb, double ub) { + return solver.makeConstraint(lb, ub, totalCostConstraintId()); + } + + public OpenRaoMPConstraint getTotalCostConstraint() { + return solver.getConstraint(totalCostConstraintId()); + } + + public OpenRaoMPConstraint addRangeActionCostConstraint(double lb, double ub, RangeAction rangeAction, State state) { + return solver.makeConstraint(lb, ub, rangeActionCostConstraintId(rangeAction, state)); + } + + public OpenRaoMPConstraint getRangeActionCostConstraint(RangeAction rangeAction, State state) { + return solver.getConstraint(rangeActionCostConstraintId(rangeAction, state)); + } + //Begin MaxLoopFlowFiller section public OpenRaoMPConstraint addMaxLoopFlowConstraint(double lb, double ub, FlowCnec cnec, TwoSides side, BoundExtension lbOrUb) { return solver.makeConstraint(lb, ub, maxLoopFlowConstraintId(cnec, side, lbOrUb)); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemBuilder.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemBuilder.java index 9baf225217..627d35e5f8 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemBuilder.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemBuilder.java @@ -46,6 +46,8 @@ public LinearProblem buildFromInputsAndParameters(IteratingLinearOptimizerInput // max.min margin, or max.min relative margin if (parameters.getObjectiveFunction().relativePositiveMargins()) { this.withProblemFiller(buildMaxMinRelativeMarginFiller()); + } else if (parameters.getObjectiveFunction().isMinCost()) { + this.withProblemFiller(buildMinCostFiller()); } else { this.withProblemFiller(buildMaxMinMarginFiller()); } @@ -144,6 +146,13 @@ private ProblemFiller buildMaxMinMarginFiller() { ); } + private ProblemFiller buildMinCostFiller() { + return new MinCostFiller( + inputs.getOptimizationPerimeter().getOptimizedFlowCnecs(), + inputs.getOptimizationPerimeter().getRangeActionsPerState() + ); + } + private ProblemFiller buildMnecFiller() { return new MnecFiller( inputs.getInitialFlowResult(), diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemIdGenerator.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemIdGenerator.java index fc086ef412..2731e8fd49 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemIdGenerator.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/LinearProblemIdGenerator.java @@ -36,6 +36,8 @@ public final class LinearProblemIdGenerator { private static final String MIN_MARGIN = "minmargin"; private static final String MIN_RELATIVE_MARGIN = "minrelmargin"; private static final String MIN_RELATIVE_MARGIN_SIGN_BINARY = "minrelmarginispositive"; + private static final String ACTIVATION_COST = "activationcost"; + private static final String TOTAL_COST = "totalcost"; private static final String MAX_LOOPFLOW = "maxloopflow"; private static final String LOOPFLOWVIOLATION = "loopflowviolation"; private static final String MNEC_VIOLATION = "mnecviolation"; @@ -157,6 +159,22 @@ public static String minimumRelativeMarginSetToZeroConstraintId() { return MIN_RELATIVE_MARGIN + SEPARATOR + CONSTRAINT_SUFFIX; } + public static String totalCostVariableId() { + return TOTAL_COST + SEPARATOR + VARIABLE_SUFFIX; + } + + public static String totalCostConstraintId() { + return TOTAL_COST + SEPARATOR + CONSTRAINT_SUFFIX; + } + + public static String rangeActionCostVariableId(RangeAction rangeAction, State state) { + return ACTIVATION_COST + SEPARATOR + rangeAction.getId() + SEPARATOR + state.getId() + SEPARATOR + VARIABLE_SUFFIX; + } + + public static String rangeActionCostConstraintId(RangeAction rangeAction, State state) { + return ACTIVATION_COST + SEPARATOR + rangeAction.getId() + SEPARATOR + state.getId() + SEPARATOR + CONSTRAINT_SUFFIX; + } + public static String maxLoopFlowConstraintId(FlowCnec flowCnec, TwoSides side, LinearProblem.BoundExtension lbOrUb) { return String.join(SEPARATOR, flowCnec.getId(), side.toString().toLowerCase(), MAX_LOOPFLOW, lbOrUb.toString().toLowerCase(), CONSTRAINT_SUFFIX); } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/api/RangeActionActivationResult.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/api/RangeActionActivationResult.java index a12ea5a3fc..e70e6b9092 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/api/RangeActionActivationResult.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/api/RangeActionActivationResult.java @@ -21,10 +21,14 @@ public interface RangeActionActivationResult { Set> getRangeActions(); + Map, Set> getStatesPerRangeAction(); + Set> getActivatedRangeActions(State state); double getOptimizedSetpoint(RangeAction rangeAction, State state); + double getOptimizedSetpointOnStatePreceding(RangeAction rangeAction, State state); + Map, Double> getOptimizedSetpointsOnState(State state); int getOptimizedTap(PstRangeAction pstRangeAction, State state); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/AutomatonPerimeterResultImpl.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/AutomatonPerimeterResultImpl.java index 3bd1ce3df7..7eb76a26c4 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/AutomatonPerimeterResultImpl.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/AutomatonPerimeterResultImpl.java @@ -22,6 +22,8 @@ import com.powsybl.sensitivity.SensitivityVariableSet; import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; /** * Represents the optimization result of automatons @@ -37,13 +39,15 @@ public class AutomatonPerimeterResultImpl implements OptimizationResult { private final Set> activatedRangeActions; private final Map, Double> rangeActionsWithSetpoint; private final State optimizedState; + private final PrePerimeterResult previousPerimeterResult; - public AutomatonPerimeterResultImpl(PrePerimeterResult postAutomatonSensitivityAnalysisOutput, Set forcedNetworkActions, Set selectedNetworkActions, Set> activatedRangeActions, Map, Double> rangeActionsWithSetpoint, State optimizedState) { + public AutomatonPerimeterResultImpl(PrePerimeterResult postAutomatonSensitivityAnalysisOutput, Set forcedNetworkActions, Set selectedNetworkActions, Set> activatedRangeActions, Map, Double> rangeActionsWithSetpoint, PrePerimeterResult previousPerimeterResult, State optimizedState) { this.postAutomatonSensitivityAnalysisOutput = postAutomatonSensitivityAnalysisOutput; this.forcedNetworkActions = forcedNetworkActions; this.selectedNetworkActions = selectedNetworkActions; this.activatedRangeActions = activatedRangeActions; this.rangeActionsWithSetpoint = rangeActionsWithSetpoint; + this.previousPerimeterResult = previousPerimeterResult; this.optimizedState = optimizedState; } @@ -148,6 +152,12 @@ public Set> getRangeActions() { return rangeActionsWithSetpoint.keySet(); } + @Override + public Map, Set> getStatesPerRangeAction() { + return rangeActionsWithSetpoint.keySet().stream() + .collect(Collectors.toMap(Function.identity(), rangeAction -> Set.of(optimizedState))); + } + @Override public Set> getActivatedRangeActions(State state) { checkState(state); @@ -160,6 +170,11 @@ public double getOptimizedSetpoint(RangeAction rangeAction, State state) { return rangeActionsWithSetpoint.get(rangeAction); } + @Override + public double getOptimizedSetpointOnStatePreceding(RangeAction rangeAction, State state) { + return previousPerimeterResult.getSetpoint(rangeAction); + } + @Override public Map, Double> getOptimizedSetpointsOnState(State state) { checkState(state); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResult.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResult.java index 68ebed4f37..0d0c14b190 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResult.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/CurativeWithSecondPraoResult.java @@ -23,10 +23,7 @@ import com.powsybl.openrao.searchtreerao.result.api.*; import com.powsybl.sensitivity.SensitivityVariableSet; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; /** @@ -179,6 +176,15 @@ public Set> getRangeActions() { return rangeActions; } + @Override + public Map, Set> getStatesPerRangeAction() { + // Some range actions can be excluded from first CRAO (for example if they are only available after a constraint) + // but re-optimised in second PRAO + Map, Set> statesPerRangeAction = new HashMap<>(firstCraoResult.getStatesPerRangeAction()); + statesPerRangeAction.putAll(secondPraoResult.getStatesPerRangeAction()); + return statesPerRangeAction; + } + @Override public Set> getActivatedRangeActions(State state) { checkState(state); @@ -197,6 +203,16 @@ public double getOptimizedSetpoint(RangeAction rangeAction, State state) { } } + @Override + public double getOptimizedSetpointOnStatePreceding(RangeAction rangeAction, State state) { + checkState(state); + if (isCraIncludedInSecondPreventiveRao(rangeAction)) { + return secondPraoResult.getOptimizedSetpointOnStatePreceding(rangeAction, state); + } else { + return firstCraoResult.getOptimizedSetpointOnStatePreceding(rangeAction, state); + } + } + @Override public Map, Double> getOptimizedSetpointsOnState(State state) { checkState(state); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/IteratingLinearOptimizationResultImpl.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/IteratingLinearOptimizationResultImpl.java index 280bff2b83..354025c43f 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/IteratingLinearOptimizationResultImpl.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/IteratingLinearOptimizationResultImpl.java @@ -153,6 +153,11 @@ public Set> getRangeActions() { return rangeActionActivationResult.getRangeActions(); } + @Override + public Map, Set> getStatesPerRangeAction() { + return rangeActionActivationResult.getStatesPerRangeAction(); + } + @Override public Set> getActivatedRangeActions(State state) { return rangeActionActivationResult.getActivatedRangeActions(state); @@ -163,6 +168,11 @@ public double getOptimizedSetpoint(RangeAction rangeAction, State state) { return rangeActionActivationResult.getOptimizedSetpoint(rangeAction, state); } + @Override + public double getOptimizedSetpointOnStatePreceding(RangeAction rangeAction, State state) { + return rangeActionActivationResult.getOptimizedSetpointOnStatePreceding(rangeAction, state); + } + @Override public Map, Double> getOptimizedSetpointsOnState(State state) { return rangeActionActivationResult.getOptimizedSetpointsOnState(state); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/OptimizationResultImpl.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/OptimizationResultImpl.java index 8354e634af..55d9b9949f 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/OptimizationResultImpl.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/OptimizationResultImpl.java @@ -127,6 +127,11 @@ public Set> getRangeActions() { return rangeActionActivationResult.getRangeActions(); } + @Override + public Map, Set> getStatesPerRangeAction() { + return rangeActionActivationResult.getStatesPerRangeAction(); + } + @Override public Set> getActivatedRangeActions(State state) { return rangeActionActivationResult.getActivatedRangeActions(state); @@ -137,6 +142,11 @@ public double getOptimizedSetpoint(RangeAction rangeAction, State state) { return rangeActionActivationResult.getOptimizedSetpoint(rangeAction, state); } + @Override + public double getOptimizedSetpointOnStatePreceding(RangeAction rangeAction, State state) { + return rangeActionActivationResult.getOptimizedSetpointOnStatePreceding(rangeAction, state); + } + @Override public Map, Double> getOptimizedSetpointsOnState(State state) { return rangeActionActivationResult.getOptimizedSetpointsOnState(state); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/RangeActionActivationResultImpl.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/RangeActionActivationResultImpl.java index a511d2cd4b..b8774bbf36 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/RangeActionActivationResultImpl.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/RangeActionActivationResultImpl.java @@ -16,6 +16,7 @@ import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; import static java.lang.String.format; @@ -107,6 +108,12 @@ public Set> getRangeActions() { return elementaryResultMap.keySet(); } + @Override + public Map, Set> getStatesPerRangeAction() { + return elementaryResultMap.keySet().stream() + .collect(Collectors.toMap(Function.identity(), rangeAction -> elementaryResultMap.get(rangeAction).setPointPerState.keySet())); + } + @Override public Set> getActivatedRangeActions(State state) { computeSetpointsPerStatePerPst(); @@ -146,6 +153,14 @@ public double getOptimizedSetpoint(RangeAction rangeAction, State state) { return elementaryResultMap.get(rangeAction).refSetpoint; } + @Override + public double getOptimizedSetpointOnStatePreceding(RangeAction rangeAction, State state) { + Optional previousStateOptional = getPreviousState(state); + + return previousStateOptional.map(previousState -> getOptimizedSetpoint(rangeAction, previousState)) + .orElseGet(() -> elementaryResultMap.get(rangeAction).refSetpoint); + } + private Double getSetpointForState(Map setPointPerState, State state) { if (setPointPerState.containsKey(state)) { return setPointPerState.get(state); @@ -186,4 +201,5 @@ private Optional getPreviousState(State state) { .filter(s -> s.getInstant().comesBefore(state.getInstant())) .max(Comparator.comparingInt(s -> s.getInstant().getOrder())); } + } diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/SkippedOptimizationResultImpl.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/SkippedOptimizationResultImpl.java index 80eb13fb23..a3eab65963 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/SkippedOptimizationResultImpl.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/result/impl/SkippedOptimizationResultImpl.java @@ -160,6 +160,11 @@ public Set> getRangeActions() { return activatedRangeActions; } + @Override + public Map, Set> getStatesPerRangeAction() { + throw new OpenRaoException(SHOULD_NOT_BE_USED); + } + @Override public Set> getActivatedRangeActions(State state) { return activatedRangeActions; @@ -170,6 +175,11 @@ public double getOptimizedSetpoint(RangeAction rangeAction, State state) { throw new OpenRaoException(SHOULD_NOT_BE_USED); } + @Override + public double getOptimizedSetpointOnStatePreceding(RangeAction rangeAction, State state) { + throw new OpenRaoException(SHOULD_NOT_BE_USED); + } + @Override public Map, Double> getOptimizedSetpointsOnState(State state) { throw new OpenRaoException(SHOULD_NOT_BE_USED); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/Leaf.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/Leaf.java index dda0db8077..bdf29e5b45 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/Leaf.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/Leaf.java @@ -152,7 +152,7 @@ boolean isRoot() { void evaluate(ObjectiveFunction objectiveFunction, SensitivityComputer sensitivityComputer) { if (status.equals(Status.EVALUATED)) { TECHNICAL_LOGS.debug("Leaf has already been evaluated"); - preOptimObjectiveFunctionResult = objectiveFunction.evaluate(preOptimFlowResult); + preOptimObjectiveFunctionResult = objectiveFunction.evaluate(preOptimFlowResult, raActivationResultFromParentLeaf); return; } TECHNICAL_LOGS.debug("Evaluating {}", this); @@ -164,7 +164,7 @@ void evaluate(ObjectiveFunction objectiveFunction, SensitivityComputer sensitivi } preOptimSensitivityResult = sensitivityComputer.getSensitivityResult(); preOptimFlowResult = sensitivityComputer.getBranchResult(network); - preOptimObjectiveFunctionResult = objectiveFunction.evaluate(preOptimFlowResult); + preOptimObjectiveFunctionResult = objectiveFunction.evaluate(preOptimFlowResult, raActivationResultFromParentLeaf); status = Status.EVALUATED; } @@ -514,6 +514,17 @@ public Set> getRangeActions() { return optimizationPerimeter.getRangeActions(); } + @Override + public Map, Set> getStatesPerRangeAction() { + if (status == Status.EVALUATED) { + return raActivationResultFromParentLeaf.getStatesPerRangeAction(); + } else if (status == Status.OPTIMIZED) { + return postOptimResult.getStatesPerRangeAction(); + } else { + throw new OpenRaoException(NO_RESULTS_AVAILABLE); + } + } + @Override public Set> getActivatedRangeActions(State state) { if (status == Status.EVALUATED) { @@ -540,6 +551,17 @@ public double getOptimizedSetpoint(RangeAction rangeAction, State state) { } } + @Override + public double getOptimizedSetpointOnStatePreceding(RangeAction rangeAction, State state) { + if (status == Status.EVALUATED) { + return raActivationResultFromParentLeaf.getOptimizedSetpointOnStatePreceding(rangeAction, state); + } else if (status == Status.OPTIMIZED) { + return postOptimResult.getOptimizedSetpointOnStatePreceding(rangeAction, state); + } else { + throw new OpenRaoException(NO_RESULTS_AVAILABLE); + } + } + @Override public Map, Double> getOptimizedSetpointsOnState(State state) { if (status == Status.EVALUATED) { diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/LoopFlowViolationCostEvaluatorTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/LoopFlowViolationCostEvaluatorTest.java index d9f93bfa9a..7273ed909e 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/LoopFlowViolationCostEvaluatorTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/LoopFlowViolationCostEvaluatorTest.java @@ -191,7 +191,7 @@ void testCostWithTwoCnecs() { buildLoopFlowViolationCostEvaluator(); - assertEquals(150, evaluator.computeCostAndLimitingElements(currentLoopFlows).getLeft(), DOUBLE_TOLERANCE); + assertEquals(150, evaluator.computeCostAndLimitingElements(currentLoopFlows, null).getLeft(), DOUBLE_TOLERANCE); } @Test @@ -211,7 +211,7 @@ void testCostWithTwoCnecsWithDifferentCost() { buildLoopFlowViolationCostEvaluator(); - assertEquals(300, evaluator.computeCostAndLimitingElements(currentLoopFlows).getLeft(), DOUBLE_TOLERANCE); + assertEquals(300, evaluator.computeCostAndLimitingElements(currentLoopFlows, null).getLeft(), DOUBLE_TOLERANCE); } @Test @@ -231,7 +231,7 @@ void testCostlyElements() { buildLoopFlowViolationCostEvaluator(); - List costlyElements = evaluator.computeCostAndLimitingElements(currentLoopFlows).getRight(); + List costlyElements = evaluator.computeCostAndLimitingElements(currentLoopFlows, null).getRight(); assertEquals(2, costlyElements.size()); assertSame(cnec1, costlyElements.get(0)); assertSame(cnec2, costlyElements.get(1)); @@ -254,7 +254,7 @@ void testCostlyElementsWithNonCostlyElements() { buildLoopFlowViolationCostEvaluator(); - List costlyElements = evaluator.computeCostAndLimitingElements(currentLoopFlows).getRight(); + List costlyElements = evaluator.computeCostAndLimitingElements(currentLoopFlows, null).getRight(); assertEquals(1, costlyElements.size()); assertSame(cnec2, costlyElements.get(0)); } diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MinMarginEvaluatorTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MinMarginEvaluatorTest.java index d370cf705e..d523e659d5 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MinMarginEvaluatorTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MinMarginEvaluatorTest.java @@ -79,7 +79,7 @@ void getUnit() { @Test void getMostLimitingElements() { - List costlyElements = minMarginEvaluator.computeCostAndLimitingElements(flowResult).getRight(); + List costlyElements = minMarginEvaluator.computeCostAndLimitingElements(flowResult, null).getRight(); assertEquals(3, costlyElements.size()); assertSame(cnec3, costlyElements.get(0)); assertSame(cnec1, costlyElements.get(1)); @@ -88,7 +88,7 @@ void getMostLimitingElements() { @Test void computeCost() { - assertEquals(250., minMarginEvaluator.computeCostAndLimitingElements(flowResult).getLeft(), DOUBLE_TOLERANCE); + assertEquals(250., minMarginEvaluator.computeCostAndLimitingElements(flowResult, null).getLeft(), DOUBLE_TOLERANCE); } @Test @@ -112,8 +112,8 @@ void testWithPureMnecs() { when(marginEvaluator.getMargin(flowResult, mnec2, MEGAWATT)).thenReturn(200.); minMarginEvaluator = new MinMarginEvaluator(Set.of(mnec1, mnec2), MEGAWATT, marginEvaluator); - assertTrue(minMarginEvaluator.computeCostAndLimitingElements(flowResult).getRight().isEmpty()); - assertEquals(-2000, minMarginEvaluator.computeCostAndLimitingElements(flowResult).getLeft(), DOUBLE_TOLERANCE); + assertTrue(minMarginEvaluator.computeCostAndLimitingElements(flowResult, null).getRight().isEmpty()); + assertEquals(-2000, minMarginEvaluator.computeCostAndLimitingElements(flowResult, null).getLeft(), DOUBLE_TOLERANCE); } private void mockCnecThresholds(FlowCnec cnec, double threshold) { @@ -128,6 +128,6 @@ void testAllCnecsUnoptimized() { mockCnecThresholds(cnec2, 2000); mockCnecThresholds(cnec3, 3000); mockCnecThresholds(pureMnec, 4000); - assertEquals(-4000., minMarginEvaluator.computeCostAndLimitingElements(flowResult).getLeft(), DOUBLE_TOLERANCE); + assertEquals(-4000., minMarginEvaluator.computeCostAndLimitingElements(flowResult, null).getLeft(), DOUBLE_TOLERANCE); } } diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MnecViolationCostEvaluatorTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MnecViolationCostEvaluatorTest.java index e9e3b80bbc..b96f2500c5 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MnecViolationCostEvaluatorTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MnecViolationCostEvaluatorTest.java @@ -114,7 +114,7 @@ void getName() { void getCostlyElements() { MnecViolationCostEvaluator evaluator = createEvaluatorWithCosts(10, Unit.MEGAWATT); - List costlyElements = evaluator.computeCostAndLimitingElements(currentFlowResult).getRight(); + List costlyElements = evaluator.computeCostAndLimitingElements(currentFlowResult, null).getRight(); assertEquals(2, costlyElements.size()); assertSame(mnec2, costlyElements.get(0)); assertSame(mnec1, costlyElements.get(1)); @@ -124,7 +124,7 @@ void getCostlyElements() { void computeCostWithTooLowCost() { MnecViolationCostEvaluator evaluator = createEvaluatorWithCosts(0.5e-10, Unit.MEGAWATT); - assertEquals(0, evaluator.computeCostAndLimitingElements(currentFlowResult).getLeft(), 1e-12); + assertEquals(0, evaluator.computeCostAndLimitingElements(currentFlowResult, null).getLeft(), 1e-12); } @Test @@ -149,13 +149,13 @@ private void testCost(double initMargin, double newMargin, double expectedCostWi assertEquals( expectedCostWithEval1, - evaluator1.computeCostAndLimitingElements(currentFlowResult).getLeft(), + evaluator1.computeCostAndLimitingElements(currentFlowResult, null).getLeft(), DOUBLE_TOLERANCE ); assertEquals( expectedCostWithEval2, - evaluator2.computeCostAndLimitingElements(currentFlowResult).getLeft(), + evaluator2.computeCostAndLimitingElements(currentFlowResult, null).getLeft(), DOUBLE_TOLERANCE ); } @@ -164,7 +164,7 @@ private void testCost(double initMargin, double newMargin, double expectedCostWi void testAmperes() { MnecViolationCostEvaluator evaluator = createEvaluatorWithCosts(10, Unit.AMPERE); - List costlyElements = evaluator.computeCostAndLimitingElements(currentFlowResult).getRight(); + List costlyElements = evaluator.computeCostAndLimitingElements(currentFlowResult, null).getRight(); assertEquals(2, costlyElements.size()); assertSame(mnec2, costlyElements.get(0)); assertSame(mnec1, costlyElements.get(1)); diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunctionTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunctionTest.java index 27c9214d62..43ebfd969c 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunctionTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ObjectiveFunctionTest.java @@ -20,6 +20,8 @@ import java.util.Set; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; /** @@ -42,18 +44,18 @@ public void setUp() { cnec2 = Mockito.mock(FlowCnec.class); minMarginEvaluator = Mockito.mock(MinMarginEvaluator.class); - when(minMarginEvaluator.computeCostAndLimitingElements(flowResult)).thenReturn(Pair.of(-300., List.of(cnec1, cnec2))); - when(minMarginEvaluator.computeCostAndLimitingElements(flowResult, new HashSet<>())).thenReturn(Pair.of(-300., List.of(cnec1, cnec2))); + when(minMarginEvaluator.computeCostAndLimitingElements(eq(flowResult), any())).thenReturn(Pair.of(-300., List.of(cnec1, cnec2))); + when(minMarginEvaluator.computeCostAndLimitingElements(eq(flowResult), any(), any())).thenReturn(Pair.of(-300., List.of(cnec1, cnec2))); mnecViolationCostEvaluator = Mockito.mock(MnecViolationCostEvaluator.class); when(mnecViolationCostEvaluator.getName()).thenReturn("mnec-cost"); - when(mnecViolationCostEvaluator.computeCostAndLimitingElements(flowResult)).thenReturn(Pair.of(1000., List.of(cnec1))); - when(mnecViolationCostEvaluator.computeCostAndLimitingElements(flowResult, new HashSet<>())).thenReturn(Pair.of(1000., List.of(cnec1))); + when(mnecViolationCostEvaluator.computeCostAndLimitingElements(eq(flowResult), any())).thenReturn(Pair.of(1000., List.of(cnec1))); + when(mnecViolationCostEvaluator.computeCostAndLimitingElements(eq(flowResult), any(), any())).thenReturn(Pair.of(1000., List.of(cnec1))); loopFlowViolationCostEvaluator = Mockito.mock(LoopFlowViolationCostEvaluator.class); when(loopFlowViolationCostEvaluator.getName()).thenReturn("loop-flow-cost"); - when(loopFlowViolationCostEvaluator.computeCostAndLimitingElements(flowResult)).thenReturn(Pair.of(100., List.of(cnec2))); - when(loopFlowViolationCostEvaluator.computeCostAndLimitingElements(flowResult, new HashSet<>())).thenReturn(Pair.of(100., List.of(cnec2))); + when(loopFlowViolationCostEvaluator.computeCostAndLimitingElements(eq(flowResult), any())).thenReturn(Pair.of(100., List.of(cnec2))); + when(loopFlowViolationCostEvaluator.computeCostAndLimitingElements(eq(flowResult), any(), any())).thenReturn(Pair.of(100., List.of(cnec2))); } @Test @@ -63,16 +65,16 @@ void testWithFunctionalCostOnly() { .build(); // functional cost - assertEquals(-300., objectiveFunction.getFunctionalCostAndLimitingElements(flowResult).getLeft(), DOUBLE_TOLERANCE); - assertEquals(List.of(cnec1, cnec2), objectiveFunction.getFunctionalCostAndLimitingElements(flowResult).getRight()); + assertEquals(-300., objectiveFunction.getFunctionalCostAndLimitingElements(flowResult, null).getLeft(), DOUBLE_TOLERANCE); + assertEquals(List.of(cnec1, cnec2), objectiveFunction.getFunctionalCostAndLimitingElements(flowResult, null).getRight()); // virtual cost assertTrue(objectiveFunction.getVirtualCostNames().isEmpty()); - assertTrue(Double.isNaN(objectiveFunction.getVirtualCostAndCostlyElements(flowResult, "mnec-cost", new HashSet<>()).getLeft())); - assertTrue(objectiveFunction.getVirtualCostAndCostlyElements(flowResult, "mnec-cost", new HashSet<>()).getRight().isEmpty()); + assertTrue(Double.isNaN(objectiveFunction.getVirtualCostAndCostlyElements(flowResult, null, "mnec-cost", new HashSet<>()).getLeft())); + assertTrue(objectiveFunction.getVirtualCostAndCostlyElements(flowResult, null, "mnec-cost", new HashSet<>()).getRight().isEmpty()); // ObjectiveFunctionResult - ObjectiveFunctionResult result = objectiveFunction.evaluate(flowResult); + ObjectiveFunctionResult result = objectiveFunction.evaluate(flowResult, null); assertEquals(-300., result.getFunctionalCost(), DOUBLE_TOLERANCE); assertEquals(0., result.getVirtualCost(), DOUBLE_TOLERANCE); assertEquals(-300., result.getCost(), DOUBLE_TOLERANCE); @@ -96,23 +98,23 @@ void testWithFunctionalAndVirtualCost() { .build(); // functional cost - assertEquals(-300., objectiveFunction.getFunctionalCostAndLimitingElements(flowResult).getLeft(), DOUBLE_TOLERANCE); - assertEquals(List.of(cnec1, cnec2), objectiveFunction.getFunctionalCostAndLimitingElements(flowResult).getRight()); + assertEquals(-300., objectiveFunction.getFunctionalCostAndLimitingElements(flowResult, null).getLeft(), DOUBLE_TOLERANCE); + assertEquals(List.of(cnec1, cnec2), objectiveFunction.getFunctionalCostAndLimitingElements(flowResult, null).getRight()); // virtual cost sum assertEquals(2, objectiveFunction.getVirtualCostNames().size()); assertTrue(objectiveFunction.getVirtualCostNames().containsAll(Set.of("mnec-cost", "loop-flow-cost"))); // mnec virtual cost - assertEquals(1000., objectiveFunction.getVirtualCostAndCostlyElements(flowResult, "mnec-cost", new HashSet<>()).getLeft(), DOUBLE_TOLERANCE); - assertEquals(List.of(cnec1), objectiveFunction.getVirtualCostAndCostlyElements(flowResult, "mnec-cost", new HashSet<>()).getRight()); + assertEquals(1000., objectiveFunction.getVirtualCostAndCostlyElements(flowResult, null, "mnec-cost", new HashSet<>()).getLeft(), DOUBLE_TOLERANCE); + assertEquals(List.of(cnec1), objectiveFunction.getVirtualCostAndCostlyElements(flowResult, null, "mnec-cost", new HashSet<>()).getRight()); // loopflow virtual cost - assertEquals(100., objectiveFunction.getVirtualCostAndCostlyElements(flowResult, "loop-flow-cost", new HashSet<>()).getLeft(), DOUBLE_TOLERANCE); - assertEquals(List.of(cnec2), objectiveFunction.getVirtualCostAndCostlyElements(flowResult, "loop-flow-cost", new HashSet<>()).getRight()); + assertEquals(100., objectiveFunction.getVirtualCostAndCostlyElements(flowResult, null, "loop-flow-cost", new HashSet<>()).getLeft(), DOUBLE_TOLERANCE); + assertEquals(List.of(cnec2), objectiveFunction.getVirtualCostAndCostlyElements(flowResult, null, "loop-flow-cost", new HashSet<>()).getRight()); // ObjectiveFunctionResult - ObjectiveFunctionResult result = objectiveFunction.evaluate(flowResult); + ObjectiveFunctionResult result = objectiveFunction.evaluate(flowResult, null); assertEquals(-300., result.getFunctionalCost(), DOUBLE_TOLERANCE); assertEquals(1100., result.getVirtualCost(), DOUBLE_TOLERANCE); assertEquals(800., result.getCost(), DOUBLE_TOLERANCE); diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/SensitivityFailureOvercostEvaluatorTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/SensitivityFailureOvercostEvaluatorTest.java index ee4a213d10..94e556e608 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/SensitivityFailureOvercostEvaluatorTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/SensitivityFailureOvercostEvaluatorTest.java @@ -15,6 +15,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import java.util.HashSet; import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -58,14 +59,14 @@ void testGetUnit() { @Test void testCostWithStateInFailure() { evaluator = new SensitivityFailureOvercostEvaluator(Set.of(cnec1, cnec2), 10000); - assertEquals(10000, evaluator.computeCostAndLimitingElements(flowResult).getLeft(), DOUBLE_TOLERANCE); + assertEquals(10000, evaluator.computeCostAndLimitingElements(flowResult, null).getLeft(), DOUBLE_TOLERANCE); } @Test void testGetCostlyElements() { evaluator = new SensitivityFailureOvercostEvaluator(Set.of(cnec1, cnec2), 10000); - assertEquals(0, evaluator.computeCostAndLimitingElements(flowResult).getRight().size()); - assertEquals(0, evaluator.computeCostAndLimitingElements(flowResult, Set.of("")).getRight().size()); + assertEquals(0, evaluator.computeCostAndLimitingElements(flowResult, null).getRight().size()); + assertEquals(0, evaluator.computeCostAndLimitingElements(flowResult, null, new HashSet<>()).getRight().size()); } @Test diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizerTest.java index 3adbbab69c..35f0c1cc9d 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizerTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/IteratingLinearOptimizerTest.java @@ -152,7 +152,7 @@ private void mockFunctionalCost(Double initialFunctionalCost, Double... iteratio ObjectiveFunctionResult initialObjectiveFunctionResult = Mockito.mock(ObjectiveFunctionResult.class); when(initialObjectiveFunctionResult.getFunctionalCost()).thenReturn(initialFunctionalCost); if (iterationFunctionalCosts.length == 0) { - when(objectiveFunction.evaluate(any())).thenReturn(initialObjectiveFunctionResult); + when(objectiveFunction.evaluate(any(), any())).thenReturn(initialObjectiveFunctionResult); } else { ObjectiveFunctionResult[] objectiveFunctionResults = new ObjectiveFunctionResult[iterationFunctionalCosts.length]; for (int i = 0; i < iterationFunctionalCosts.length; i++) { @@ -160,7 +160,7 @@ private void mockFunctionalCost(Double initialFunctionalCost, Double... iteratio when(objectiveFunctionResult.getFunctionalCost()).thenReturn(iterationFunctionalCosts[i]); objectiveFunctionResults[i] = objectiveFunctionResult; } - when(objectiveFunction.evaluate(any())).thenReturn( + when(objectiveFunction.evaluate(any(), any())).thenReturn( initialObjectiveFunctionResult, objectiveFunctionResults ); diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/LinearProblemBuilderTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/LinearProblemBuilderTest.java index 4f7f7de41a..5fdad45d90 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/LinearProblemBuilderTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/LinearProblemBuilderTest.java @@ -148,4 +148,18 @@ void testBuildMaxMarginContinuousRaLimitation() { assertInstanceOf(ContinuousRangeActionGroupFiller.class, fillers.get(2)); assertInstanceOf(RaUsageLimitsFiller.class, fillers.get(3)); } + + @Test + void testBuildMinCostContinuous() { + when(rangeActionParameters.getPstModel()).thenReturn(RangeActionsOptimizationParameters.PstModel.CONTINUOUS); + when(parameters.getObjectiveFunction()).thenReturn(ObjectiveFunctionParameters.ObjectiveFunctionType.MIN_COST_MEGAWATT); + + LinearProblem linearProblem = linearProblemBuilder.buildFromInputsAndParameters(inputs, parameters); + assertNotNull(linearProblem); + List fillers = linearProblem.getFillers(); + assertEquals(3, fillers.size()); + assertTrue(fillers.get(0) instanceof CoreProblemFiller); + assertTrue(fillers.get(1) instanceof MinCostFiller); + assertTrue(fillers.get(2) instanceof ContinuousRangeActionGroupFiller); + } } diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFillerTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFillerTest.java new file mode 100644 index 0000000000..c5502c02c5 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFillerTest.java @@ -0,0 +1,199 @@ +/* + * 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.searchtreerao.linearoptimisation.algorithms.fillers; + +import com.powsybl.iidm.network.TwoSides; +import com.powsybl.openrao.commons.OpenRaoException; +import com.powsybl.openrao.commons.Unit; +import com.powsybl.openrao.data.cracapi.State; +import com.powsybl.openrao.data.cracapi.rangeaction.RangeAction; +import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters; +import com.powsybl.openrao.raoapi.parameters.RaoParameters; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.LinearProblem; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.LinearProblemBuilder; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPConstraint; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPVariable; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Jeremy Wang{@literal } + */ +class MinCostFillerTest extends AbstractFillerTest { + private static final double PST_ACTIVATION_COST = 1.5; + private LinearProblem linearProblem; + private CoreProblemFiller coreProblemFiller; + private MinCostFiller minCostFiller; + + @BeforeEach + public void setUp() throws IOException { + init(); + network.getTwoWindingsTransformer(RANGE_ACTION_ELEMENT_ID).getPhaseTapChanger().setTapPosition(TAP_INITIAL); + double initialAlpha = network.getTwoWindingsTransformer(RANGE_ACTION_ELEMENT_ID).getPhaseTapChanger().getCurrentStep().getAlpha(); + RangeActionSetpointResult initialRangeActionSetpointResult = new RangeActionSetpointResultImpl(Map.of(pstRangeAction, initialAlpha)); + + OptimizationPerimeter optimizationPerimeter = Mockito.mock(OptimizationPerimeter.class); + Mockito.when(optimizationPerimeter.getFlowCnecs()).thenReturn(Set.of(cnec1)); + + Map>> rangeActions = new HashMap<>(); + rangeActions.put(cnec1.getState(), Set.of(pstRangeAction)); + Mockito.when(optimizationPerimeter.getRangeActionsPerState()).thenReturn(rangeActions); + + RaoParameters raoParameters = new RaoParameters(); + raoParameters.getRangeActionsOptimizationParameters().setPstPenaltyCost(0.01); + raoParameters.getRangeActionsOptimizationParameters().setHvdcPenaltyCost(0.01); + raoParameters.getRangeActionsOptimizationParameters().setInjectionRaPenaltyCost(0.01); + RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(raoParameters); + + coreProblemFiller = new CoreProblemFiller( + optimizationPerimeter, + initialRangeActionSetpointResult, + rangeActionParameters, + Unit.MEGAWATT, + false, RangeActionsOptimizationParameters.PstModel.CONTINUOUS); + } + + private void createMinCostFiller() { + Map>> rangeActions = new HashMap<>(); + rangeActions.put(cnec1.getState(), Set.of(pstRangeAction)); + minCostFiller = new MinCostFiller(Set.of(cnec1), rangeActions); + } + + private void buildLinearProblem() { + linearProblem = new LinearProblemBuilder() + .withProblemFiller(coreProblemFiller) + .withProblemFiller(minCostFiller) + .withSolver(RangeActionsOptimizationParameters.Solver.SCIP) + .withInitialRangeActionActivationResult(getInitialRangeActionActivationResult()) + .build(); + linearProblem.fill(flowResult, sensitivityResult); + } + + @Test + void fillWithMinCostMarginConstraint() { + createMinCostFiller(); + buildLinearProblem(); + + OpenRaoMPVariable flowCnec1 = linearProblem.getFlowVariable(cnec1, TwoSides.ONE); + OpenRaoMPVariable absoluteVariation = linearProblem.getAbsoluteRangeActionVariationVariable(pstRangeAction, cnec1.getState()); + + // check minimum margin variable + OpenRaoMPVariable minimumMargin = linearProblem.getMinimumMarginVariable(); + assertNotNull(minimumMargin); + + // check minimum margin constraints + OpenRaoMPConstraint cnec1AboveThreshold = linearProblem.getMinimumMarginConstraint(cnec1, TwoSides.ONE, LinearProblem.MarginExtension.ABOVE_THRESHOLD); + OpenRaoMPConstraint cnec1BelowThreshold = linearProblem.getMinimumMarginConstraint(cnec1, TwoSides.ONE, LinearProblem.MarginExtension.BELOW_THRESHOLD); + assertNotNull(cnec1AboveThreshold); + assertNotNull(cnec1BelowThreshold); + assertEquals(-linearProblem.infinity(), cnec1BelowThreshold.lb(), linearProblem.infinity() * 1e-3); + assertEquals(-MIN_FLOW_1, cnec1BelowThreshold.ub(), DOUBLE_TOLERANCE); + assertEquals(-linearProblem.infinity(), cnec1AboveThreshold.lb(), linearProblem.infinity() * 1e-3); + assertEquals(MAX_FLOW_1, cnec1AboveThreshold.ub(), DOUBLE_TOLERANCE); + assertEquals(-1, cnec1BelowThreshold.getCoefficient(flowCnec1), DOUBLE_TOLERANCE); + assertEquals(1, cnec1AboveThreshold.getCoefficient(flowCnec1), DOUBLE_TOLERANCE); + assertEquals(1, cnec1BelowThreshold.getCoefficient(minimumMargin), DOUBLE_TOLERANCE); + assertEquals(1, cnec1AboveThreshold.getCoefficient(minimumMargin), DOUBLE_TOLERANCE); + + // check objective + assertEquals(0.01, linearProblem.getObjective().getCoefficient(absoluteVariation), DOUBLE_TOLERANCE); // penalty cost + // 1000 is for the arbitrary penalty coefficient + assertEquals(-1000, linearProblem.getObjective().getCoefficient(minimumMargin), DOUBLE_TOLERANCE); // penalty cost if unsecure + assertTrue(linearProblem.minimization()); + } + + @Test + void fillWithMinCostTotalCostConstraints() { + createMinCostFiller(); + buildLinearProblem(); + + OpenRaoMPVariable absoluteVariation = linearProblem.getAbsoluteRangeActionVariationVariable(pstRangeAction, cnec1.getState()); + + // check rangeAction cost variable + OpenRaoMPVariable rangeActionCostVariable = linearProblem.getRangeActionCostVariable(pstRangeAction, cnec1.getState()); + assertNotNull(rangeActionCostVariable); + // check total cost variable + OpenRaoMPVariable totalCostVariable = linearProblem.getTotalCostVariable(); + assertNotNull(totalCostVariable); + + // check rangeAction cost constraint + OpenRaoMPConstraint rangeActionCostConstraint = linearProblem.getRangeActionCostConstraint(pstRangeAction, cnec1.getState()); + assertNotNull(rangeActionCostConstraint); + assertEquals(1, rangeActionCostConstraint.getCoefficient(rangeActionCostVariable), DOUBLE_TOLERANCE); + assertEquals(-PST_ACTIVATION_COST, rangeActionCostConstraint.getCoefficient(absoluteVariation), DOUBLE_TOLERANCE); + assertEquals(0.0, rangeActionCostConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(0.0, rangeActionCostConstraint.ub(), DOUBLE_TOLERANCE); + + // check total cost constraint + OpenRaoMPConstraint totalCostConstraint = linearProblem.getTotalCostConstraint(); + assertNotNull(totalCostConstraint); + assertEquals(1, totalCostConstraint.getCoefficient(totalCostVariable), DOUBLE_TOLERANCE); + assertEquals(-1, totalCostConstraint.getCoefficient(rangeActionCostVariable), DOUBLE_TOLERANCE); + assertEquals(0.0, totalCostConstraint.lb(), DOUBLE_TOLERANCE); + assertEquals(0.0, totalCostConstraint.ub(), DOUBLE_TOLERANCE); + + // check objective + assertEquals(1, linearProblem.getObjective().getCoefficient(totalCostVariable), DOUBLE_TOLERANCE); + + // check the number of variables and constraints + // total number of variables 6 : + // - 3 due to CoreFiller + // - minimum margin variable + // - total cost variable + // - 1 range action cost variable + // total number of constraints 7 : + // - 3 due to CoreFiller + // - 2 per CNEC (min margin constraints) + // - 1 per range action (range action cost constraint) + // - total cost constraint + assertEquals(6, linearProblem.numVariables()); + assertEquals(7, linearProblem.numConstraints()); + } + + @Test + void fillWithMissingFlowVariables() { + createMinCostFiller(); + linearProblem = new LinearProblemBuilder() + .withProblemFiller(minCostFiller) + .withSolver(RangeActionsOptimizationParameters.Solver.SCIP) + .build(); + + // AbsoluteRangeActionVariables present, but no the FlowVariables + linearProblem.addAbsoluteRangeActionVariationVariable(0.0, 0.0, pstRangeAction, cnec1.getState()); + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.fill(flowResult, sensitivityResult)); + assertEquals("Variable Tieline BE FR - N - preventive_one_flow_variable has not been created yet", e.getMessage()); + } + + @Test + void fillWithMissingRangeActionVariables() { + createMinCostFiller(); + linearProblem = new LinearProblemBuilder() + .withProblemFiller(minCostFiller) + .withSolver(RangeActionsOptimizationParameters.Solver.SCIP) + .build(); + + // FlowVariables present , but not the absoluteRangeActionVariables present, + // This should work since range actions can be filtered out by the CoreProblemFiller if their number + // exceeds the max-pst-per-tso parameter + linearProblem.addFlowVariable(0.0, 0.0, cnec1, TwoSides.ONE); + linearProblem.addFlowVariable(0.0, 0.0, cnec2, TwoSides.TWO); + Exception e = assertThrows(OpenRaoException.class, () -> linearProblem.fill(flowResult, sensitivityResult)); + assertEquals("Variable PRA_PST_BE_preventive_absolutevariation_variable has not been created yet", e.getMessage()); + } +} + diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/impl/AutomatonPerimeterResultImplTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/impl/AutomatonPerimeterResultImplTest.java index b0221862e8..6fa325b072 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/impl/AutomatonPerimeterResultImplTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/result/impl/AutomatonPerimeterResultImplTest.java @@ -48,6 +48,7 @@ class AutomatonPerimeterResultImplTest { private Map, Double> rangeActionsWithSetpoint; private AutomatonPerimeterResultImpl result; private PrePerimeterResult postAutoSensitivity; + private PrePerimeterResult previousPerimeterResult; @BeforeEach public void setUp() { @@ -60,12 +61,13 @@ public void setUp() { hvdcRangeActionShifted = mock(HvdcRangeAction.class); unshiftedRangeAction = mock(RangeAction.class); postAutoSensitivity = mock(PrePerimeterResult.class); + previousPerimeterResult = mock(PrePerimeterResult.class); // Define rangeActionsWithSetpoint rangeActionsWithSetpoint = new HashMap<>(); rangeActionsWithSetpoint.put(pstRangeActionShifted, 1.0); rangeActionsWithSetpoint.put(hvdcRangeActionShifted, 2.0); rangeActionsWithSetpoint.put(unshiftedRangeAction, 3.0); - result = new AutomatonPerimeterResultImpl(postAutoSensitivity, Set.of(networkAction1), Set.of(), Set.of(pstRangeActionShifted, hvdcRangeActionShifted), rangeActionsWithSetpoint, state1); + result = new AutomatonPerimeterResultImpl(postAutoSensitivity, Set.of(networkAction1), Set.of(), Set.of(pstRangeActionShifted, hvdcRangeActionShifted), rangeActionsWithSetpoint, previousPerimeterResult, state1); } @Test diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/LeafTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/LeafTest.java index 5114dd7e45..ad06a76e8b 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/LeafTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/LeafTest.java @@ -185,7 +185,7 @@ void evaluateAnAlreadyEvaluatedLeaf() { when(prePerimeterResult.getSensitivityStatus()).thenReturn(sensitivityStatus); Leaf rootLeaf = new Leaf(optimizationPerimeter, network, prePerimeterResult, appliedRemedialActions); ObjectiveFunctionResult preOptimObjectiveFunctionResult = Mockito.mock(ObjectiveFunctionResult.class); - when(costEvaluatorMock.evaluate(prePerimeterResult)).thenReturn(preOptimObjectiveFunctionResult); + when(costEvaluatorMock.evaluate(eq(prePerimeterResult), any())).thenReturn(preOptimObjectiveFunctionResult); rootLeaf.evaluate(costEvaluatorMock, sensitivityComputer); assertEquals(Leaf.Status.EVALUATED, rootLeaf.getStatus()); } @@ -200,7 +200,7 @@ private Leaf prepareLeafForEvaluation(NetworkAction networkAction, ComputationSt when(expectedSensitivityResult.getSensitivityStatus()).thenReturn(expectedSensitivityStatus); when(sensitivityComputer.getBranchResult(network)).thenReturn(expectedFlowResult); ObjectiveFunctionResult expectedObjectiveFunctionResult = Mockito.mock(ObjectiveFunctionResult.class); - when(costEvaluatorMock.evaluate(any())).thenReturn(expectedObjectiveFunctionResult); + when(costEvaluatorMock.evaluate(any(), any())).thenReturn(expectedObjectiveFunctionResult); when(expectedObjectiveFunctionResult.getFunctionalCost()).thenReturn(expectedCost / 2); when(expectedObjectiveFunctionResult.getVirtualCost()).thenReturn(expectedCost / 2); when(expectedObjectiveFunctionResult.getVirtualCost(virtualCostName)).thenReturn(expectedCost / 2); @@ -521,7 +521,7 @@ void getCostlyElementsBeforeOptimization() { void getVirtualCostNames() { Leaf leaf = new Leaf(optimizationPerimeter, network, prePerimeterResult, appliedRemedialActions); ObjectiveFunctionResult objectiveFunctionResult = Mockito.mock(ObjectiveFunctionResult.class); - when(costEvaluatorMock.evaluate(any())).thenReturn(objectiveFunctionResult); + when(costEvaluatorMock.evaluate(any(), any())).thenReturn(objectiveFunctionResult); Set virtualCostNames = new HashSet<>(); virtualCostNames.add(virtualCostName); when(objectiveFunctionResult.getVirtualCostNames()).thenReturn(virtualCostNames); diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/SearchTreeTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/SearchTreeTest.java index a13b54ce53..33eb7ec2f6 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/SearchTreeTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/searchtree/algorithms/SearchTreeTest.java @@ -225,7 +225,7 @@ private void setLeafStatusToEvaluated(Leaf leaf) { when(sensitivityComputer.getBranchResult(network)).thenReturn(null); Mockito.doNothing().when(sensitivityComputer).compute(network); ObjectiveFunction objectiveFunction = Mockito.mock(ObjectiveFunction.class); - when(objectiveFunction.evaluate(any())).thenReturn(null); + when(objectiveFunction.evaluate(any(), any())).thenReturn(null); leaf.evaluate(objectiveFunction, sensitivityComputer); } diff --git a/ra-optimisation/search-tree-rao/src/test/resources/crac/small-crac.json b/ra-optimisation/search-tree-rao/src/test/resources/crac/small-crac.json index 3421c1d85b..4ad9217400 100644 --- a/ra-optimisation/search-tree-rao/src/test/resources/crac/small-crac.json +++ b/ra-optimisation/search-tree-rao/src/test/resources/crac/small-crac.json @@ -105,6 +105,7 @@ "rangeType": "absolute" } ], + "cost": 1.5, "networkElementId": "BBE2AA1 BBE3AA1 1" }, { diff --git a/ra-optimisation/search-tree-rao/src/test/resources/parameters/RaoParameters_MIN_COST.json b/ra-optimisation/search-tree-rao/src/test/resources/parameters/RaoParameters_MIN_COST.json new file mode 100644 index 0000000000..3c1c71caaf --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/test/resources/parameters/RaoParameters_MIN_COST.json @@ -0,0 +1,157 @@ +{ + "version" : "2.4", + "objective-function" : { + "type" : "MIN_COST_MEGAWATT", + "forbid-cost-increase" : false, + "preventive-stop-criterion" : "MIN_OBJECTIVE", + "curative-stop-criterion" : "MIN_OBJECTIVE", + "curative-min-obj-improvement" : 0.0, + "optimize-curative-if-preventive-unsecure" : false + }, + "range-actions-optimization" : { + "max-mip-iterations" : 10, + "pst-penalty-cost" : 0.01, + "pst-sensitivity-threshold" : 1.0E-6, + "pst-model" : "CONTINUOUS", + "hvdc-penalty-cost" : 0.001, + "hvdc-sensitivity-threshold" : 1.0E-6, + "injection-ra-penalty-cost" : 0.001, + "injection-ra-sensitivity-threshold" : 1.0E-6, + "ra-range-shrinking" : "DISABLED", + "linear-optimization-solver" : { + "solver" : "SCIP", + "relative-mip-gap" : 1.0E-4, + "solver-specific-parameters" : null + } + }, + "topological-actions-optimization" : { + "max-preventive-search-tree-depth" : 2147483647, + "max-auto-search-tree-depth" : 2147483647, + "max-curative-search-tree-depth" : 2147483647, + "predefined-combinations" : [ ], + "relative-minimum-impact-threshold" : 0.0, + "absolute-minimum-impact-threshold" : 0.0, + "skip-actions-far-from-most-limiting-element" : false, + "max-number-of-boundaries-for-skipping-actions" : 2 + }, + "second-preventive-rao" : { + "execution-condition" : "DISABLED", + "re-optimize-curative-range-actions" : false, + "hint-from-first-preventive-rao" : false + }, + "not-optimized-cnecs" : { + "do-not-optimize-curative-cnecs-for-tsos-without-cras" : false, + "do-not-optimize-cnec-secured-by-its-pst" : { } + }, + "load-flow-and-sensitivity-computation" : { + "load-flow-provider" : "OpenLoadFlow", + "sensitivity-provider" : "OpenLoadFlow", + "sensitivity-failure-overcost" : 10000.0, + "sensitivity-parameters" : { + "version" : "1.1", + "load-flow-parameters" : { + "version" : "1.9", + "voltageInitMode" : "UNIFORM_VALUES", + "transformerVoltageControlOn" : false, + "phaseShifterRegulationOn" : false, + "useReactiveLimits" : true, + "twtSplitShuntAdmittance" : false, + "shuntCompensatorVoltageControlOn" : false, + "readSlackBus" : true, + "writeSlackBus" : false, + "dc" : true, + "distributedSlack" : true, + "balanceType" : "PROPORTIONAL_TO_GENERATION_P_MAX", + "dcUseTransformerRatio" : true, + "countriesToBalance" : [ ], + "connectedComponentMode" : "MAIN", + "hvdcAcEmulation" : true, + "dcPowerFactor" : 1.0, + "extensions" : { + "open-load-flow-parameters" : { + "slackBusSelectionMode" : "MOST_MESHED", + "slackBusesIds" : [ ], + "slackDistributionFailureBehavior" : "LEAVE_ON_SLACK_BUS", + "voltageRemoteControl" : true, + "lowImpedanceBranchMode" : "REPLACE_BY_ZERO_IMPEDANCE_LINE", + "loadPowerFactorConstant" : false, + "plausibleActivePowerLimit" : 5000.0, + "newtonRaphsonStoppingCriteriaType" : "UNIFORM_CRITERIA", + "maxActivePowerMismatch" : 0.01, + "maxReactivePowerMismatch" : 0.01, + "maxVoltageMismatch" : 1.0E-4, + "maxAngleMismatch" : 1.0E-5, + "maxRatioMismatch" : 1.0E-5, + "maxSusceptanceMismatch" : 1.0E-4, + "slackBusPMaxMismatch" : 1.0, + "voltagePerReactivePowerControl" : false, + "generatorReactivePowerRemoteControl" : false, + "transformerReactivePowerControl" : false, + "maxNewtonRaphsonIterations" : 15, + "maxOuterLoopIterations" : 20, + "newtonRaphsonConvEpsPerEq" : 1.0E-4, + "voltageInitModeOverride" : "NONE", + "transformerVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL", + "shuntVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL", + "minPlausibleTargetVoltage" : 0.8, + "maxPlausibleTargetVoltage" : 1.2, + "minNominalVoltageTargetVoltageCheck" : 20.0, + "minRealisticVoltage" : 0.5, + "maxRealisticVoltage" : 2.0, + "lowImpedanceThreshold" : 1.0E-8, + "reactiveRangeCheckMode" : "MAX", + "networkCacheEnabled" : false, + "svcVoltageMonitoring" : true, + "stateVectorScalingMode" : "NONE", + "maxSlackBusCount" : 1, + "debugDir" : null, + "incrementalTransformerRatioTapControlOuterLoopMaxTapShift" : 3, + "secondaryVoltageControl" : false, + "reactiveLimitsMaxPqPvSwitch" : 3, + "phaseShifterControlMode" : "CONTINUOUS_WITH_DISCRETISATION", + "alwaysUpdateNetwork" : false, + "mostMeshedSlackBusSelectorMaxNominalVoltagePercentile" : 95.0, + "reportedFeatures" : [ ], + "slackBusCountryFilter" : [ ], + "actionableSwitchesIds" : [ ], + "actionableTransformersIds" : [ ], + "asymmetrical" : false, + "reactivePowerDispatchMode" : "Q_EQUAL_PROPORTION", + "outerLoopNames" : null, + "useActiveLimits" : true, + "disableVoltageControlOfGeneratorsOutsideActivePowerLimits" : false, + "lineSearchStateVectorScalingMaxIteration" : 10, + "lineSearchStateVectorScalingStepFold" : 1.3333333333333333, + "maxVoltageChangeStateVectorScalingMaxDv" : 0.1, + "maxVoltageChangeStateVectorScalingMaxDphi" : 0.17453292519943295, + "linePerUnitMode" : "IMPEDANCE", + "useLoadModel" : false, + "dcApproximationType" : "IGNORE_R", + "simulateAutomationSystems" : false, + "acSolverType" : "NEWTON_RAPHSON", + "maxNewtonKrylovIterations" : 100, + "newtonKrylovLineSearch" : false, + "referenceBusSelectionMode" : "FIRST_SLACK", + "writeReferenceTerminals" : true, + "voltageTargetPriorities" : [ "GENERATOR", "TRANSFORMER", "SHUNT" ] + } + } + }, + "flow-flow-sensitivity-value-threshold" : 0.0, + "voltage-voltage-sensitivity-value-threshold" : 0.0, + "flow-voltage-sensitivity-value-threshold" : 0.0, + "angle-flow-sensitivity-value-threshold" : 0.0, + "extensions" : { + "open-sensitivity-parameters" : { + "debugDir" : null + } + } + } + }, + "multi-threading" : { + "contingency-scenarios-in-parallel" : 1, + "preventive-leaves-in-parallel" : 1, + "auto-leaves-in-parallel" : 1, + "curative-leaves-in-parallel" : 1 + } +} \ No newline at end of file diff --git a/tests/src/test/java/com/powsybl/openrao/tests/steps/SearchTreeRaoSteps.java b/tests/src/test/java/com/powsybl/openrao/tests/steps/SearchTreeRaoSteps.java index 3ea776c47b..91fc1c0b7d 100644 --- a/tests/src/test/java/com/powsybl/openrao/tests/steps/SearchTreeRaoSteps.java +++ b/tests/src/test/java/com/powsybl/openrao/tests/steps/SearchTreeRaoSteps.java @@ -11,10 +11,7 @@ import com.powsybl.openrao.commons.OpenRaoException; import com.powsybl.openrao.commons.PhysicalParameter; import com.powsybl.openrao.commons.Unit; -import com.powsybl.openrao.data.cracapi.Crac; -import com.powsybl.openrao.data.cracapi.Instant; -import com.powsybl.openrao.data.cracapi.InstantKind; -import com.powsybl.openrao.data.cracapi.State; +import com.powsybl.openrao.data.cracapi.*; import com.powsybl.openrao.data.cracapi.cnec.Cnec; import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; import com.powsybl.iidm.network.TwoSides; @@ -452,6 +449,15 @@ public void worstRelativeMarginAndCnecInMW(double expectedMargin, String expecte assertEquals(expectedMargin, worstCnec.getValue(), flowMegawattTolerance(expectedMargin)); assertEquals(expectedCnecName, worstCnec.getKey().getId()); } + /* + RangeAction cost + */ + + @Then("the cost of remedial action {string} should be {double}") + public void costPra(String rangeActionId, Double expectedCost) { + RangeAction rangeAction = crac.getRangeAction(rangeActionId); + assertEquals(expectedCost, rangeAction.getActivationCost() * (raoResult.getOptimizedSetPointOnState(preventiveState, rangeAction) - raoResult.getPreOptimizationSetPointOnState(preventiveState, rangeAction)), TOLERANCE_RANGEACTION_SETPOINT); + } /* Flows in A diff --git a/tests/src/test/resources/com/powsybl/openrao/tests/features/extra_features/cost_objective_function.feature b/tests/src/test/resources/com/powsybl/openrao/tests/features/extra_features/cost_objective_function.feature new file mode 100644 index 0000000000..9ee8e56458 --- /dev/null +++ b/tests/src/test/resources/com/powsybl/openrao/tests/features/extra_features/cost_objective_function.feature @@ -0,0 +1,54 @@ +# Copyright (c) 2024, 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/. + +#WIP +Feature: New objective function using minimal cost + + @fast @rao @mock @ac @preventive-only + Scenario: Preventive RA with minimal cost + Given network file is "common/12NodesProdFR_3PST.uct" + Given crac file is "extra_features/crac-cost-0.json" + Given configuration file is "common/RaoParameters_minCost_megawatt_ac.json" + When I launch search_tree_rao + Then 1 remedial actions are used in preventive + And the remedial action "pst_be" is used in preventive + And the margin on cnec "BBE2AA1 FFR3AA1 1 - preventive" after PRA should be 0 A + And the tap of PstRangeAction "pst_be" should be 6 in preventive + And the cost of remedial action "pst_be" should be 234 + And the value of the objective function after PRA should be 234 +# Incorrect value because min Margin isn't exactly equal to 0, so some penalty applies + + @fast @rao @mock @ac @preventive-only + Scenario: Preventive RA with max min margin + Given network file is "common/12NodesProdFR_3PST.uct" + Given crac file is "extra_features/crac-cost-0.json" + Given configuration file is "common/RaoParameters_maxMargin_megawatt_ac.json" + When I launch search_tree_rao + Then 1 remedial actions are used in preventive + And the remedial action "pst_be" is used in preventive + And the margin on cnec "BBE2AA1 FFR3AA1 1 - preventive" after PRA should be 70 A + And the tap of PstRangeAction "pst_be" should be 16 in preventive + + @fast @rao @mock @ac @preventive-only + Scenario: Preventive RA & NetworkAction 0 with minimal cost + Given network file is "common/12NodesProdFR_3PST.uct" + Given crac file is "extra_features/crac-cost-with-network-action-0.json" + Given configuration file is "common/RaoParameters_minCost_megawatt_ac.json" + When I launch search_tree_rao + Then 0 remedial actions are used in preventive + And the margin on cnec "BBE2AA1 FFR3AA1 1 - preventive" after PRA should be 677 A + And the tap of PstRangeAction "pst_be" should be 0 in preventive + + @fast @rao @mock @ac @preventive-only + Scenario: Preventive RA & NetworkAction 0 with max min margin + Given network file is "common/12NodesProdFR_3PST.uct" + Given crac file is "extra_features/crac-cost-with-network-action-0.json" + Given configuration file is "common/RaoParameters_maxMargin_megawatt_ac.json" + When I launch search_tree_rao + Then 2 remedial actions are used in preventive + And the remedial action "pst_be" is used in preventive + And the remedial action "open-be2-fr3-1" is used in preventive + And the margin on cnec "BBE2AA1 FFR3AA1 1 - preventive" after PRA should be 1440 A + And the tap of PstRangeAction "pst_be" should be 16 in preventive diff --git a/tests/src/test/resources/files/cases/common/12NodesProdFR.uct b/tests/src/test/resources/files/cases/common/12NodesProdFR.uct new file mode 100644 index 0000000000..c5f0bac703 --- /dev/null +++ b/tests/src/test/resources/files/cases/common/12NodesProdFR.uct @@ -0,0 +1,46 @@ +##C 2007.05.01 +##N +##ZBE +BBE1AA1 BE1 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +BBE2AA1 BE2 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +BBE3AA1 BE3 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +##ZDE +DDE1AA1 DE1 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +DDE2AA1 DE2 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +DDE3AA1 DE3 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +##ZFR +FFR1AA1 FR1 0 2 400.00 -1000.0 0.00000 00000.0 0.00000 9000.00 -9000.0 9000.00 -9000.0 +FFR2AA1 FR2 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +FFR3AA1 FR3 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +##ZNL +NNL1AA1 NL1 0 2 400.00 0000.00 0.00000 1000.00 0.00000 9000.00 -9000.0 9000.00 -9000.0 +NNL2AA1 NL2 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +NNL3AA1 NL3 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +##L +BBE1AA1 BBE2AA1 1 0 0.0000 10.000 0.000000 5000 +BBE1AA1 BBE3AA1 1 0 0.0000 10.000 0.000000 5000 +FFR1AA1 FFR2AA1 1 0 0.0000 10.000 0.000000 5000 +FFR1AA1 FFR3AA1 1 0 0.0000 10.000 0.000000 5000 +FFR2AA1 FFR3AA1 1 0 0.0000 10.000 0.000000 5000 +DDE1AA1 DDE2AA1 1 0 0.0000 10.000 0.000000 5000 +DDE1AA1 DDE3AA1 1 0 0.0000 10.000 0.000000 5000 +DDE2AA1 DDE3AA1 1 0 0.0000 10.000 0.000000 5000 +NNL1AA1 NNL2AA1 1 0 0.0000 10.000 0.000000 5000 +NNL1AA1 NNL3AA1 1 0 0.0000 10.000 0.000000 5000 +NNL2AA1 NNL3AA1 1 0 0.0000 10.000 0.000000 5000 +FFR2AA1 DDE3AA1 1 0 0.0000 10.000 0.000000 5000 +DDE2AA1 NNL3AA1 1 0 0.0000 10.000 0.000000 5000 +NNL2AA1 BBE3AA1 1 0 0.0000 10.000 0.000000 410 +NNL2AA1 BBE3AA1 2 8 0.0000 10.000 0.000000 410 +NNL2AA1 BBE3AA1 3 8 0.0000 10.000 0.000000 410 +BBE2AA1 FFR3AA1 1 0 0.0000 10.000 0.000000 5000 +BBE2AA1 FFR3AA1 2 8 0.0000 10.000 0.000000 5000 +BBE2AA1 FFR3AA1 3 8 0.0000 10.000 0.000000 5000 +##T +BBE2AA1 BBE3AA1 1 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 5000 PST +BBE2AA1 BBE3AA1 2 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 5000 PST +BBE2AA1 BBE3AA1 3 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 5000 PST +##R +BBE2AA1 BBE3AA1 1 -0.68 90.00 16 0 SYMM +BBE2AA1 BBE3AA1 2 -0.68 90.00 16 0 SYMM +BBE2AA1 BBE3AA1 3 -0.68 90.00 16 0 SYMM diff --git a/tests/src/test/resources/files/cases/common/12NodesProdFR_3PST.uct b/tests/src/test/resources/files/cases/common/12NodesProdFR_3PST.uct new file mode 100644 index 0000000000..eb1b9c5cf1 --- /dev/null +++ b/tests/src/test/resources/files/cases/common/12NodesProdFR_3PST.uct @@ -0,0 +1,42 @@ +##C 2007.05.01 +##N +##ZBE +BBE1AA1 BE1 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +BBE2AA1 BE2 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +BBE3AA1 BE3 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +##ZDE +DDE1AA1 DE1 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +DDE2AA1 DE2 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +DDE3AA1 DE3 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +##ZFR +FFR1AA1 FR1 0 2 400.00 -1000.0 0.00000 00000.0 0.00000 9000.00 -9000.0 9000.00 -9000.0 +FFR2AA1 FR2 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +FFR3AA1 FR3 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +##ZNL +NNL1AA1 NL1 0 2 400.00 0000.00 0.00000 1000.00 0.00000 9000.00 -9000.0 9000.00 -9000.0 +NNL2AA1 NL2 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +NNL3AA1 NL3 0 2 400.00 0.00000 0.00000 0.00000 0.00000 9000.00 -9000.0 9000.00 -9000.0 +##L +BBE1AA1 BBE2AA1 1 0 0.0000 10.000 0.000000 5000 +BBE1AA1 BBE3AA1 1 0 0.0000 10.000 0.000000 5000 +FFR1AA1 FFR2AA1 1 0 0.0000 10.000 0.000000 5000 +FFR1AA1 FFR3AA1 1 0 0.0000 10.000 0.000000 5000 +FFR2AA1 FFR3AA1 1 0 0.0000 10.000 0.000000 5000 +DDE1AA1 DDE2AA1 1 0 0.0000 10.000 0.000000 5000 +DDE1AA1 DDE3AA1 1 0 0.0000 10.000 0.000000 5000 +DDE2AA1 DDE3AA1 1 0 0.0000 10.000 0.000000 5000 +NNL1AA1 NNL2AA1 1 0 0.0000 10.000 0.000000 5000 +NNL1AA1 NNL3AA1 1 0 0.0000 10.000 0.000000 5000 +NNL2AA1 NNL3AA1 1 0 0.0000 10.000 0.000000 5000 +FFR2AA1 DDE3AA1 1 0 0.0000 10.000 0.000000 5000 +DDE2AA1 NNL3AA1 1 0 0.0000 10.000 0.000000 5000 +NNL2AA1 BBE3AA1 1 0 0.0000 10.000 0.000000 410 +BBE2AA1 FFR3AA1 1 0 0.0000 10.000 0.000000 5000 +##T +BBE2AA1 BBE3AA1 1 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 5000 PST +BBE2AA1 BBE3AA1 2 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 5000 PST +BBE2AA1 BBE3AA1 3 0 400.0 400.0 1000. 0.0000 10.000 0.000000 0.0 5000 PST +##R +BBE2AA1 BBE3AA1 1 -0.68 90.00 16 0 SYMM +BBE2AA1 BBE3AA1 2 -0.68 90.00 16 0 SYMM +BBE2AA1 BBE3AA1 3 -0.68 90.00 16 0 SYMM diff --git a/tests/src/test/resources/files/configurations/common/RaoParameters_minCost_megawatt_ac.json b/tests/src/test/resources/files/configurations/common/RaoParameters_minCost_megawatt_ac.json new file mode 100644 index 0000000000..70856b16d2 --- /dev/null +++ b/tests/src/test/resources/files/configurations/common/RaoParameters_minCost_megawatt_ac.json @@ -0,0 +1,81 @@ +{ + "version" : "2.4", + "objective-function" : { + "type" : "MIN_COST_MEGAWATT", + "forbid-cost-increase" : false, + "curative-min-obj-improvement" : 0.0, + "preventive-stop-criterion" : "MIN_OBJECTIVE", + "curative-stop-criterion" : "MIN_OBJECTIVE" + }, + "range-actions-optimization" : { + "max-mip-iterations" : 10, + "pst-penalty-cost" : 0.01, + "pst-sensitivity-threshold" : 1.0E-6, + "pst-model" : "CONTINUOUS", + "hvdc-penalty-cost" : 0.001, + "hvdc-sensitivity-threshold" : 1.0E-6, + "injection-ra-penalty-cost" : 0.001, + "injection-ra-sensitivity-threshold" : 1.0E-6, + "linear-optimization-solver" : { + "solver" : "CBC", + "relative-mip-gap" : 1.0E-4, + "solver-specific-parameters" : null + } + }, + "topological-actions-optimization" : { + "max-preventive-search-tree-depth" : 2147483647, + "max-auto-search-tree-depth" : 2147483647, + "max-curative-search-tree-depth" : 2147483647, + "predefined-combinations" : [ ], + "relative-minimum-impact-threshold" : 0.0, + "absolute-minimum-impact-threshold" : 1.0, + "skip-actions-far-from-most-limiting-element" : false, + "max-number-of-boundaries-for-skipping-actions" : 2 + }, + "multi-threading" : { + "contingency-scenarios-in-parallel" : 1, + "preventive-leaves-in-parallel" : 1, + "curative-leaves-in-parallel" : 1 + }, + "second-preventive-rao" : { + "execution-condition" : "DISABLED", + "re-optimize-curative-range-actions" : false, + "hint-from-first-preventive-rao" : false + }, + "not-optimized-cnecs" : { + "do-not-optimize-curative-cnecs-for-tsos-without-cras" : false + }, + "load-flow-and-sensitivity-computation" : { + "load-flow-provider" : "OpenLoadFlow", + "sensitivity-provider" : "OpenLoadFlow", + "sensitivity-failure-overcost" : 10000.0, + "sensitivity-parameters" : { + "version" : "1.0", + "load-flow-parameters" : { + "version" : "1.9", + "voltageInitMode" : "UNIFORM_VALUES", + "transformerVoltageControlOn" : false, + "phaseShifterRegulationOn" : false, + "useReactiveLimits" : true, + "twtSplitShuntAdmittance" : false, + "shuntCompensatorVoltageControlOn" : false, + "readSlackBus" : true, + "writeSlackBus" : true, + "dc" : false, + "distributedSlack" : true, + "balanceType" : "PROPORTIONAL_TO_GENERATION_P", + "dcUseTransformerRatio" : true, + "countriesToBalance" : [ ], + "connectedComponentMode" : "MAIN", + "hvdcAcEmulation" : true + } + } + }, + "extensions" : { + "mnec-parameters" : { + "acceptable-margin-decrease" : 50.0, + "violation-cost" : 10.0, + "constraint-adjustment-coefficient" : 0.0 + } + } +} \ No newline at end of file diff --git a/tests/src/test/resources/files/crac/extra_features/crac-cost-0.json b/tests/src/test/resources/files/crac/extra_features/crac-cost-0.json new file mode 100644 index 0000000000..e79c534600 --- /dev/null +++ b/tests/src/test/resources/files/crac/extra_features/crac-cost-0.json @@ -0,0 +1,106 @@ +{ + "type": "CRAC", + "version": "2.1", + "info": "Generated by FARAO http://farao-community.github.io", + "id": "CRAC with max elementary actions", + "name": "CRAC with max elementary actions", + "instants": [ + { + "id": "preventive", + "kind": "PREVENTIVE" + }, + { + "id": "outage", + "kind": "OUTAGE" + }, + { + "id": "curative", + "kind": "CURATIVE" + } + ], + "networkElementsNamePerId": {}, + "contingencies": [], + "flowCnecs": [ + { + "id": "BBE2AA1 FFR3AA1 1 - preventive", + "name": "BBE2AA1 FFR3AA1 1 - preventive", + "networkElementId": "BBE2AA1 FFR3AA1 1", + "operator": "BE", + "contingencyId" : null, + "instant": "preventive", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ NaN ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "megawatt", + "min" : -500.0, + "max" : 500.0, + "side" : "left" + } ] + } + ], + "pstRangeActions": [ + { + "id": "pst_be", + "name": "pst_be", + "operator": "BE", + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "networkElementId": "BBE2AA1 BBE3AA1 1", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ], + "cost" : 100 + } + ], + "hvdcRangeActions": [], + "injectionRangeActions": [], + "networkActions": [], + "ra-usage-limits-per-instant" : [] +} \ No newline at end of file diff --git a/tests/src/test/resources/files/crac/extra_features/crac-cost-2pst.json b/tests/src/test/resources/files/crac/extra_features/crac-cost-2pst.json new file mode 100644 index 0000000000..2dd750ecb3 --- /dev/null +++ b/tests/src/test/resources/files/crac/extra_features/crac-cost-2pst.json @@ -0,0 +1,162 @@ +{ + "type": "CRAC", + "version": "2.1", + "info": "Generated by FARAO http://farao-community.github.io", + "id": "CRAC with max elementary actions", + "name": "CRAC with max elementary actions", + "instants": [ + { + "id": "preventive", + "kind": "PREVENTIVE" + }, + { + "id": "outage", + "kind": "OUTAGE" + }, + { + "id": "curative", + "kind": "CURATIVE" + } + ], + "networkElementsNamePerId": {}, + "contingencies": [], + "flowCnecs": [ + { + "id": "BBE2AA1 FFR3AA1 1 - preventive - TS0", + "name": "BBE2AA1 FFR3AA1 1 - preventive", + "networkElementId": "BBE2AA1 FFR3AA1 1", + "operator": "BE", + "contingencyId" : null, + "instant": "preventive", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ NaN ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "megawatt", + "min" : -450.0, + "max" : 450.0, + "side" : "left" + } ] + } + ], + "pstRangeActions": [ + { + "id": "pst_be_0 - TS0", + "name": "pst_be_0", + "operator": "BE", + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "networkElementId": "BBE2AA1 BBE3AA1 1", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ], + "cost" : 1.1 + }, + { + "id": "pst_be_1 - TS0", + "name": "pst_be_1", + "operator": "BE", + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "networkElementId": "BBE2AA1 BBE3AA1 2", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ], + "cost" : 7 + } + ], + "hvdcRangeActions": [], + "injectionRangeActions": [], + "networkActions": [], + "ra-usage-limits-per-instant" : [] +} \ No newline at end of file diff --git a/tests/src/test/resources/files/crac/extra_features/crac-cost-with-network-action-0.json b/tests/src/test/resources/files/crac/extra_features/crac-cost-with-network-action-0.json new file mode 100644 index 0000000000..a1035760ad --- /dev/null +++ b/tests/src/test/resources/files/crac/extra_features/crac-cost-with-network-action-0.json @@ -0,0 +1,137 @@ +{ + "type": "CRAC", + "version": "2.1", + "info": "Generated by FARAO http://farao-community.github.io", + "id": "CRAC with max elementary actions", + "name": "CRAC with max elementary actions", + "instants": [ + { + "id": "preventive", + "kind": "PREVENTIVE" + }, + { + "id": "outage", + "kind": "OUTAGE" + }, + { + "id": "curative", + "kind": "CURATIVE" + } + ], + "networkElementsNamePerId": {}, + "contingencies": [], + "flowCnecs": [ + { + "id": "BBE2AA1 FFR3AA1 1 - preventive", + "name": "BBE2AA1 FFR3AA1 1 - preventive", + "networkElementId": "BBE2AA1 FFR3AA1 1", + "operator": "BE", + "contingencyId" : null, + "instant": "preventive", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ NaN ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "megawatt", + "min" : -1000.0, + "max" : 1000.0, + "side" : "left" + } ] + }, + { + "id": "NNL2AA1 BBE3AA1 1 - preventive", + "name": "NNL2AA1 BBE3AA1 1 - preventive", + "networkElementId": "NNL2AA1 BBE3AA1 1", + "operator": "BE", + "contingencyId" : null, + "instant": "preventive", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ NaN ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "megawatt", + "min" : -1500.0, + "max" : 1500.0, + "side" : "left" + } ] + } + ], + "pstRangeActions": [ + { + "id": "pst_be", + "name": "pst_be", + "operator": "BE", + "onInstantUsageRules": [ + { + "instant": "preventive", + "usageMethod": "available" + } + ], + "networkElementId": "BBE2AA1 BBE3AA1 1", + "initialTap": 0, + "tapToAngleConversionMap": { + "-1": -0.3896097993971608, + "0": 0.0, + "-2": -0.7792105912934298, + "1": 0.3896097993971608, + "-3": -1.1687933694373345, + "2": 0.7792105912934298, + "-4": -1.5583491300758083, + "3": 1.1687933694373345, + "-5": -1.9478688732023104, + "4": 1.5583491300758083, + "-6": -2.337343603803646, + "5": 1.9478688732023104, + "-7": -2.7267643331050597, + "6": 2.337343603803646, + "-8": -3.1161220798131644, + "7": 2.7267643331050597, + "-9": -3.505407871356285, + "8": 3.1161220798131644, + "-10": -3.894612745121778, + "9": 3.505407871356285, + "-11": -4.283727749689918, + "10": 3.894612745121778, + "-12": -4.672743946063913, + "11": 4.283727749689918, + "-13": -5.061652408895631, + "12": 4.672743946063913, + "-14": -5.4504442277066305, + "13": 5.061652408895631, + "-15": -5.839110508104064, + "14": 5.4504442277066305, + "-16": -6.2276423729910535, + "15": 5.839110508104064, + "16": 6.2276423729910535 + }, + "ranges": [ + { + "min": -16, + "max": 16, + "rangeType": "absolute" + } + ], + "cost" : 1.1 + } + ], + "hvdcRangeActions": [], + "injectionRangeActions": [], + "networkActions": [{ + "id" : "open-be2-fr3-1", + "name" : "open-be2-fr3-1", + "operator" : null, + "onInstantUsageRules" : [ { + "instant" : "preventive", + "usageMethod" : "available" + } ], + "topologicalActions" : [ { + "networkElementId" : "BBE2AA1 FFR3AA1 1", + "actionType" : "open" + } ] + }], + "ra-usage-limits-per-instant" : [] +} \ No newline at end of file