From d6dbf8fed09c7f17320ad157813d288b7c898207 Mon Sep 17 00:00:00 2001 From: wangjer Date: Tue, 20 Aug 2024 11:36:53 +0200 Subject: [PATCH 01/16] Cost as objective function first commit Signed-off-by: wangjer --- .../openrao/data/cracapi/RemedialAction.java | 2 + .../data/cracapi/RemedialActionAdder.java | 2 + .../data/cracimpl/AbstractRangeAction.java | 5 + .../data/cracimpl/AbstractRemedialAction.java | 14 ++ .../cracimpl/AbstractRemedialActionAdder.java | 9 +- .../CounterTradeRangeActionAdderImpl.java | 2 +- .../cracimpl/CounterTradeRangeActionImpl.java | 9 + .../cracimpl/HvdcRangeActionAdderImpl.java | 2 +- .../data/cracimpl/HvdcRangeActionImpl.java | 8 + .../InjectionRangeActionAdderImpl.java | 2 +- .../cracimpl/InjectionRangeActionImpl.java | 8 + .../cracimpl/PstRangeActionAdderImpl.java | 2 +- .../data/cracimpl/PstRangeActionImpl.java | 12 ++ .../algorithms/fillers/MinCostHardFiller.java | 167 ++++++++++++++++++ .../linearproblem/LinearProblem.java | 34 ++++ .../LinearProblemIdGenerator.java | 18 ++ .../NewObjectiveFunctionTest.java | 167 ++++++++++++++++++ ...rac-with-max-3-elementary-actions-pst.json | 4 +- ...rac-with-max-7-elementary-actions-pst.json | 4 +- 19 files changed, 462 insertions(+), 9 deletions(-) create mode 100644 ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostHardFiller.java create mode 100644 ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/NewObjectiveFunctionTest.java 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-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..e7dc01d005 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; 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/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostHardFiller.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostHardFiller.java new file mode 100644 index 0000000000..7f2117f317 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostHardFiller.java @@ -0,0 +1,167 @@ +/* + * 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.commons.Unit; +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.PstRangeAction; +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 Viktor Terrier {@literal } + * @author Baptiste Seguinot {@literal } + */ +public class MinCostHardFiller implements ProblemFiller { + protected final Set optimizedCnecs; + private final Unit unit; + private final Map> rangeActions; + + public MinCostHardFiller(Set optimizedCnecs, + Unit unit, Map> rangeActions) { + this.rangeActions = rangeActions; + this.optimizedCnecs = new TreeSet<>(Comparator.comparing(Identifiable::getId)); + this.optimizedCnecs.addAll(optimizedCnecs); + this.unit = unit; + } + + @Override + public void fill(LinearProblem linearProblem, FlowResult flowResult, SensitivityResult sensitivityResult) { + Set validFlowCnecs = FillersUtil.getFlowCnecsComputationStatusOk(optimizedCnecs, sensitivityResult); + + // build variables + buildTotalCostVariable(linearProblem, validFlowCnecs); + buildRangeActionCostVariable(linearProblem); + + // build constraints + buildSecureCnecsHardConstraints(linearProblem, validFlowCnecs); + buildRangeActionCostConstraints(linearProblem); + buildTotalCostConstraints(linearProblem); + + // complete objective + fillObjectiveWithActivationCost(linearProblem); + } + + @Override + public void updateBetweenSensiIteration(LinearProblem linearProblem, FlowResult flowResult, SensitivityResult sensitivityResult, RangeActionActivationResult rangeActionActivationResult) { + // Objective does not change, nothing to do + } + + @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, Set validFlowCnecs) { +// if (!rangeActions.isEmpty()) { + linearProblem.addTotalCostVariable(0, LinearProblem.infinity()); +// } else { + // if there is no RangeActions, the cost variable is forced to zero. + // otherwise it would be unbounded in the LP +// linearProblem.addActivationCostVariable(0.0, 0.0); +// } + } + + /** + * 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 two min/max constraints for each Cnec c. + *

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

+ * F[c] <= fmax[c] (ABOVE_THRESHOLD) + * fmin[c] <= F[c] (BELOW_THRESHOLD) + */ + private void buildSecureCnecsHardConstraints(LinearProblem linearProblem, Set validFlowCnecs) { + 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(flowVariable, -1); + } + + if (maxFlow.isPresent()) { + OpenRaoMPConstraint minimumMarginPositive = linearProblem.addMinimumMarginConstraint(-LinearProblem.infinity(), maxFlow.get(), cnec, side, LinearProblem.MarginExtension.ABOVE_THRESHOLD); + 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 buildTotalCostConstraints(LinearProblem linearProblem) { + // create constraint & add variable cost (objective function) + OpenRaoMPVariable totalCostVariable = linearProblem.getTotalCostVariable(); + OpenRaoMPConstraint totalCostConstraint = linearProblem.addActivationCostConstraint(0, 0); + totalCostConstraint.setCoefficient(totalCostVariable, 1); + 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 + */ + private void fillObjectiveWithActivationCost(LinearProblem linearProblem) { + OpenRaoMPVariable totalCostVariable = linearProblem.getTotalCostVariable(); + linearProblem.getObjective().setCoefficient(totalCostVariable, 1); + } + +} + 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 944435b549..e41b2c4455 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 @@ -111,6 +111,8 @@ public void updateBetweenMipIteration(RangeActionActivationResult rangeActionAct } public LinearProblemStatus solve() { + System.out.println(solver.getMpSolver().exportModelAsLpFormat()); + solver.setRelativeMipGap(relativeMipGap); solver.setSolverSpecificParametersAsString(solverSpecificParameters); return solver.solve(); @@ -332,6 +334,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 addActivationCostConstraint(double lb, double ub) { + return solver.makeConstraint(lb, ub, totalCostConstraintId()); + } + + public OpenRaoMPConstraint getActivationCostConstraint() { + 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/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/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/NewObjectiveFunctionTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/NewObjectiveFunctionTest.java new file mode 100644 index 0000000000..280c3c9e9f --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/NewObjectiveFunctionTest.java @@ -0,0 +1,167 @@ +package com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem; + +import com.powsybl.iidm.network.Network; +import com.powsybl.openrao.commons.Unit; +import com.powsybl.openrao.data.cracapi.Crac; +import com.powsybl.openrao.data.cracapi.State; +import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; +import com.powsybl.openrao.data.cracapi.rangeaction.PstRangeAction; +import com.powsybl.openrao.data.cracapi.rangeaction.RangeAction; +import com.powsybl.openrao.data.cracioapi.CracImporters; +import com.powsybl.openrao.raoapi.json.JsonRaoParameters; +import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters; +import com.powsybl.openrao.raoapi.parameters.RaoParameters; +import com.powsybl.openrao.searchtreerao.commons.SensitivityComputerMultiTS; +import com.powsybl.openrao.searchtreerao.commons.ToolProvider; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.PreventiveOptimizationPerimeter; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.fillers.*; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; +import com.powsybl.openrao.searchtreerao.result.impl.MultipleSensitivityResult; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.*; +import java.util.stream.Collectors; + +public class NewObjectiveFunctionTest { + + List networks; + List cracs; + RangeActionSetpointResult initialSetpoints; + List optimizationPerimeters; + List>> rangeActionsPerStatePerTimestamp; + MultipleSensitivityResult initialSensiResult; + RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/parameters/RaoParameters_DC_SCIP.json")); + + @BeforeEach + public void setUp() { + } + + private List>> computeRangeActionsPerStatePerTimestamp() { + List>> rangeActionsPerStatePerTimestamp = new ArrayList<>(); + for (Crac crac : cracs) { + Map> rangeActionsPerState = new HashMap<>(); + crac.getStates().forEach(state -> rangeActionsPerState.put(state, + crac.getPotentiallyAvailableRangeActions(state).stream() + .filter(ra -> ra instanceof PstRangeAction) + .map(ra -> (PstRangeAction) ra) + .collect(Collectors.toSet()))); + rangeActionsPerStatePerTimestamp.add(rangeActionsPerState); + } + return rangeActionsPerStatePerTimestamp; + } + + private RangeActionSetpointResult computeInitialSetpointsResults() { + Map, Double> setpoints = new HashMap<>(); + for (int i = 0; i < cracs.size(); i++) { + for (RangeAction rangeAction : cracs.get(i).getRangeActions()) { + setpoints.put(rangeAction, rangeAction.getCurrentSetpoint(networks.get(i))); + } + } + return new RangeActionSetpointResultImpl(setpoints); + } + + private List computeOptimizationPerimeters() { + List perimeters = new ArrayList<>(); + for (Crac crac : cracs) { + perimeters.add(new PreventiveOptimizationPerimeter( + crac.getPreventiveState(), + crac.getFlowCnecs(), + new HashSet<>(), + crac.getNetworkActions(), + crac.getRangeActions())); + } + return perimeters; + } + + private MultipleSensitivityResult runInitialSensi() { + List> cnecsList = new ArrayList<>(); + cracs.forEach(crac -> cnecsList.add(crac.getFlowCnecs())); + + Set> rangeActionsSet = new HashSet<>(); + cracs.forEach(crac -> rangeActionsSet.addAll(crac.getRangeActions())); + + ToolProvider toolProvider = ToolProvider.create().withNetwork(networks.get(0)).withRaoParameters(raoParameters).build(); //the attributes in the class are only used for loopflow things + + SensitivityComputerMultiTS sensitivityComputerMultiTS = SensitivityComputerMultiTS.create() + .withCnecs(cnecsList) + .withRangeActions(rangeActionsSet) + .withOutageInstant(cracs.get(0).getOutageInstant()) + .withToolProvider(toolProvider) + .build(); + sensitivityComputerMultiTS.compute(networks); + return sensitivityComputerMultiTS.getSensitivityResults(); + } + + private void importNetworksAndCracs(List cracsPaths, List networksPaths) { + cracs = new ArrayList<>(); + networks = new ArrayList<>(); + for (int i = 0; i < networksPaths.size(); i++) { + networks.add(Network.read(networksPaths.get(i), getClass().getResourceAsStream("/" + networksPaths.get(i)))); + cracs.add(CracImporters.importCrac(cracsPaths.get(i), getClass().getResourceAsStream("/" + cracsPaths.get(i)), networks.get(i))); + } + } + + @Test + public void testLinearProblem() { + importNetworksAndCracs( + List.of("multi-ts/crac/crac-case3_0.json"), + List.of("multi-ts/network/12NodesProdFR.uct") + ); + + initialSetpoints = computeInitialSetpointsResults(); + optimizationPerimeters = computeOptimizationPerimeters(); + rangeActionsPerStatePerTimestamp = computeRangeActionsPerStatePerTimestamp(); + + initialSensiResult = runInitialSensi(); + + RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(new RaoParameters()); + rangeActionParameters.setPstModel(RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); + OpenRaoMPSolver orMpSolver = new OpenRaoMPSolver("solver", RangeActionsOptimizationParameters.Solver.SCIP); + + CoreProblemFiller coreProblemFiller0 = new CoreProblemFiller( + optimizationPerimeters.get(0), + initialSetpoints, + new RangeActionActivationResultImpl(initialSetpoints), + rangeActionParameters, + Unit.MEGAWATT, + false); + + DiscretePstTapFiller discretePstTapFiller0 = new DiscretePstTapFiller( + networks.get(0), + optimizationPerimeters.get(0), + rangeActionsPerStatePerTimestamp.get(0), + initialSetpoints); + + Set allCnecs = new HashSet<>(); + allCnecs.addAll(cracs.get(0).getFlowCnecs()); + MinCostHardFiller minCostHardFiller = new MinCostHardFiller(allCnecs, Unit.MEGAWATT, rangeActionsPerStatePerTimestamp.get(0)); + + MultiTSFiller multiTSFiller = new MultiTSFiller( + optimizationPerimeters, + networks, + rangeActionParameters, + new RangeActionActivationResultImpl(initialSetpoints)); + + LinearProblem linearProblemMerge = new LinearProblemBuilder() + .withSolver(orMpSolver.getSolver()) + .withProblemFiller(coreProblemFiller0) + .withProblemFiller(minCostHardFiller) + .withProblemFiller(discretePstTapFiller0) + .withProblemFiller(multiTSFiller) + .build(); + + linearProblemMerge.fill(initialSensiResult, initialSensiResult); + linearProblemMerge.solve(); + + PstRangeAction pstRa0 = cracs.get(0).getPstRangeActions().iterator().next(); + State state0 = optimizationPerimeters.get(0).getMainOptimizationState(); + double setpointMerge0 = linearProblemMerge.getRangeActionSetpointVariable(pstRa0, state0).solutionValue(); + + System.out.println(setpointMerge0); + } + +} diff --git a/tests/src/test/resources/files/crac/epic19/small-crac-with-max-3-elementary-actions-pst.json b/tests/src/test/resources/files/crac/epic19/small-crac-with-max-3-elementary-actions-pst.json index 83af7d9c71..df9ae928f6 100644 --- a/tests/src/test/resources/files/crac/epic19/small-crac-with-max-3-elementary-actions-pst.json +++ b/tests/src/test/resources/files/crac/epic19/small-crac-with-max-3-elementary-actions-pst.json @@ -35,8 +35,8 @@ "nominalV" : [ 400.0 ], "thresholds" : [ { "unit" : "megawatt", - "min" : -500.0, - "max" : 500.0, + "min" : -400.0, + "max" : 400.0, "side" : "left" } ] } diff --git a/tests/src/test/resources/files/crac/epic19/small-crac-with-max-7-elementary-actions-pst.json b/tests/src/test/resources/files/crac/epic19/small-crac-with-max-7-elementary-actions-pst.json index 93c6f49905..a8a6fe8a03 100644 --- a/tests/src/test/resources/files/crac/epic19/small-crac-with-max-7-elementary-actions-pst.json +++ b/tests/src/test/resources/files/crac/epic19/small-crac-with-max-7-elementary-actions-pst.json @@ -35,8 +35,8 @@ "nominalV" : [ 400.0 ], "thresholds" : [ { "unit" : "megawatt", - "min" : -500.0, - "max" : 500.0, + "min" : -400.0, + "max" : 400.0, "side" : "left" } ] } From a1daafe4b7a01cf9e67c758390412963a2ac583e Mon Sep 17 00:00:00 2001 From: wangjer Date: Fri, 23 Aug 2024 15:53:22 +0200 Subject: [PATCH 02/16] Add (de)serializer for activationCost Signed-off-by: wangjer --- .../data/cracio/json/JsonSerializationConstants.java | 1 + .../PstRangeActionArrayDeserializer.java | 4 ++++ .../StandardRangeActionDeserializer.java | 4 ++++ .../json/serializers/PstRangeActionSerializer.java | 1 + .../serializers/StandardRangeActionSerializer.java | 3 +++ .../linearproblem/NewObjectiveFunctionTest.java | 12 +++++++++++- .../resources/files/crac/epic19/crac-cost-0.json | 0 7 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/src/test/resources/files/crac/epic19/crac-cost-0.json diff --git a/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/JsonSerializationConstants.java b/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/JsonSerializationConstants.java index b2a0625290..5eaec5fedb 100644 --- a/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/JsonSerializationConstants.java +++ b/data/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-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/PstRangeActionArrayDeserializer.java b/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/PstRangeActionArrayDeserializer.java index c7cd381d4d..88766c173c 100644 --- a/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/PstRangeActionArrayDeserializer.java +++ b/data/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-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/StandardRangeActionDeserializer.java b/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/StandardRangeActionDeserializer.java index 245911f93a..6c7625550a 100644 --- a/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/deserializers/StandardRangeActionDeserializer.java +++ b/data/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-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/PstRangeActionSerializer.java b/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/PstRangeActionSerializer.java index 23de2c9147..2e7edcce15 100644 --- a/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/PstRangeActionSerializer.java +++ b/data/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-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/StandardRangeActionSerializer.java b/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/StandardRangeActionSerializer.java index 8c8840a968..fd4bef7a69 100644 --- a/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/StandardRangeActionSerializer.java +++ b/data/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 { @@ -48,4 +49,6 @@ private static void serializeRanges(StandardRangeAction value, JsonGenerator } gen.writeEndArray(); } + + } diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/NewObjectiveFunctionTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/NewObjectiveFunctionTest.java index 280c3c9e9f..c36cdc0e06 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/NewObjectiveFunctionTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/NewObjectiveFunctionTest.java @@ -1,3 +1,10 @@ +/* + * 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.linearproblem; import com.powsybl.iidm.network.Network; @@ -26,6 +33,9 @@ import java.util.*; import java.util.stream.Collectors; +/** + * @author Jeremy Wang {@literal } + */ public class NewObjectiveFunctionTest { List networks; @@ -108,7 +118,7 @@ private void importNetworksAndCracs(List cracsPaths, List networ @Test public void testLinearProblem() { importNetworksAndCracs( - List.of("multi-ts/crac/crac-case3_0.json"), + List.of("multi-ts/crac/crac-cost-0.json"), List.of("multi-ts/network/12NodesProdFR.uct") ); diff --git a/tests/src/test/resources/files/crac/epic19/crac-cost-0.json b/tests/src/test/resources/files/crac/epic19/crac-cost-0.json new file mode 100644 index 0000000000..e69de29bb2 From 563ccfec7532f0f6c8dea4e36f3f52a5115a218d Mon Sep 17 00:00:00 2001 From: wangjer Date: Tue, 3 Sep 2024 17:20:46 +0200 Subject: [PATCH 03/16] Add new objective function into MIP + add tests Signed-off-by: wangjer --- .../StandardRangeActionSerializer.java | 2 - .../json/JsonRetrocompatibilityTest.java | 42 ++- .../retrocompatibility/v2/crac-v2.3.json | 12 +- .../ObjectiveFunctionParameters.java | 8 +- .../algorithms/fillers/MinCostHardFiller.java | 19 +- .../linearproblem/LinearProblem.java | 2 - .../linearproblem/LinearProblemBuilder.java | 9 + ...onTest.java => CostLinearProblemTest.java} | 28 +- .../linearproblem/CostMIPMultiTsTest.java | 252 ++++++++++++++++++ .../linearproblem/CostMIPSingleTsTest.java | 155 +++++++++++ .../resources/multi-ts/crac/crac-cost-0.json | 106 ++++++++ .../parameters/RaoParameters_MIN_COST.json | 157 +++++++++++ .../files/crac/epic19/crac-cost-2pst.json | 0 13 files changed, 744 insertions(+), 48 deletions(-) rename ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/{NewObjectiveFunctionTest.java => CostLinearProblemTest.java} (88%) create mode 100644 ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java create mode 100644 ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java create mode 100644 ra-optimisation/search-tree-rao/src/test/resources/multi-ts/crac/crac-cost-0.json create mode 100644 ra-optimisation/search-tree-rao/src/test/resources/parameters/RaoParameters_MIN_COST.json create mode 100644 tests/src/test/resources/files/crac/epic19/crac-cost-2pst.json diff --git a/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/StandardRangeActionSerializer.java b/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/StandardRangeActionSerializer.java index fd4bef7a69..2a83b8700e 100644 --- a/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/StandardRangeActionSerializer.java +++ b/data/crac-io/crac-io-json/src/main/java/com/powsybl/openrao/data/cracio/json/serializers/StandardRangeActionSerializer.java @@ -49,6 +49,4 @@ private static void serializeRanges(StandardRangeAction value, JsonGenerator } gen.writeEndArray(); } - - } diff --git a/data/crac-io/crac-io-json/src/test/java/com/powsybl/openrao/data/cracio/json/JsonRetrocompatibilityTest.java b/data/crac-io/crac-io-json/src/test/java/com/powsybl/openrao/data/cracio/json/JsonRetrocompatibilityTest.java index 7453a279b9..76b5f12679 100644 --- a/data/crac-io/crac-io-json/src/test/java/com/powsybl/openrao/data/cracio/json/JsonRetrocompatibilityTest.java +++ b/data/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,40 @@ 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() + assertNotNull(pstRangeAction4); + + // 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()); + + StandardRange injectionAbsRange = crac.getInjectionRangeAction("injectionRange1Id").getRanges().stream() .filter(tapRange -> tapRange.getRangeType().equals(RangeType.ABSOLUTE)) .findAny().orElse(null); - TapRange relTimeStepRange = crac.getPstRangeAction("pstRange4Id").getRanges().stream() + StandardRange injectionRelTimeStepRange = crac.getInjectionRangeAction("injectionRange1Id").getRanges().stream() .filter(tapRange -> tapRange.getRangeType().equals(RangeType.RELATIVE_TO_PREVIOUS_TIME_STEP)) .findAny().orElse(null); - - 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()); + assertNotNull(injectionAbsRange); + assertEquals(-100.0, injectionAbsRange.getMin()); + assertEquals(300.0, injectionAbsRange.getMax()); + assertNotNull(injectionRelTimeStepRange); + assertEquals(-400, injectionRelTimeStepRange.getMin()); + assertEquals(600, injectionRelTimeStepRange.getMax()); // check new border attribute assertEquals("border1", crac.getCnec("cnec1outageId").getBorder()); diff --git a/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.3.json b/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.3.json index 46b68ec1a4..79723256c0 100644 --- a/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.3.json +++ b/data/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", @@ -369,11 +370,12 @@ }, "initialSetpoint" : 50, "ranges" : [ { - "min" : -500.0, - "max" : 500.0 + "min" : -100.0, + "max" : 300.0 }, { - "min" : -1000.0, - "max" : 1000.0 + "min" : -400.0, + "max" : 600.0, + "rangeType" : "relativeToPreviousTimeStep" } ] } ], "counterTradeRangeActions" : [ { 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..5afb7488f1 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,9 @@ 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), + MIN_COST_MEGAWATT(Unit.MEGAWATT), + MIN_COST_AMPERE(Unit.AMPERE); private final Unit unit; @@ -55,6 +57,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/linearoptimisation/algorithms/fillers/MinCostHardFiller.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostHardFiller.java index 7f2117f317..5e1b961605 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostHardFiller.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostHardFiller.java @@ -7,11 +7,10 @@ package com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.fillers; -import com.powsybl.openrao.commons.Unit; 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.PstRangeAction; +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; @@ -29,15 +28,13 @@ */ public class MinCostHardFiller implements ProblemFiller { protected final Set optimizedCnecs; - private final Unit unit; - private final Map> rangeActions; + private final Map>> rangeActions; public MinCostHardFiller(Set optimizedCnecs, - Unit unit, Map> rangeActions) { + Map>> rangeActions) { this.rangeActions = rangeActions; this.optimizedCnecs = new TreeSet<>(Comparator.comparing(Identifiable::getId)); this.optimizedCnecs.addAll(optimizedCnecs); - this.unit = unit; } @Override @@ -45,7 +42,7 @@ public void fill(LinearProblem linearProblem, FlowResult flowResult, Sensitivity Set validFlowCnecs = FillersUtil.getFlowCnecsComputationStatusOk(optimizedCnecs, sensitivityResult); // build variables - buildTotalCostVariable(linearProblem, validFlowCnecs); + buildTotalCostVariable(linearProblem); buildRangeActionCostVariable(linearProblem); // build constraints @@ -71,14 +68,8 @@ public void updateBetweenMipIteration(LinearProblem linearProblem, RangeActionAc * Build the total cost variable TC. * TC represents the activation cost of all range actions. */ - private void buildTotalCostVariable(LinearProblem linearProblem, Set validFlowCnecs) { -// if (!rangeActions.isEmpty()) { + private void buildTotalCostVariable(LinearProblem linearProblem) { linearProblem.addTotalCostVariable(0, LinearProblem.infinity()); -// } else { - // if there is no RangeActions, the cost variable is forced to zero. - // otherwise it would be unbounded in the LP -// linearProblem.addActivationCostVariable(0.0, 0.0); -// } } /** 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 e41b2c4455..dccbbdcc11 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 @@ -111,8 +111,6 @@ public void updateBetweenMipIteration(RangeActionActivationResult rangeActionAct } public LinearProblemStatus solve() { - System.out.println(solver.getMpSolver().exportModelAsLpFormat()); - solver.setRelativeMipGap(relativeMipGap); solver.setSolverSpecificParametersAsString(solverSpecificParameters); return solver.solve(); 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 fee61c4411..1ef1b544bb 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 @@ -43,6 +43,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(buildMinCostHardFiller()); } else { this.withProblemFiller(buildMaxMinMarginFiller()); } @@ -137,6 +139,13 @@ private ProblemFiller buildMaxMinMarginFiller() { ); } + private ProblemFiller buildMinCostHardFiller() { + return new MinCostHardFiller( + inputs.getOptimizationPerimeter().getOptimizedFlowCnecs(), + inputs.getOptimizationPerimeter().getRangeActionsPerState() + ); + } + private ProblemFiller buildMnecFiller() { return new MnecFiller( inputs.getInitialFlowResult(), diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/NewObjectiveFunctionTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostLinearProblemTest.java similarity index 88% rename from ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/NewObjectiveFunctionTest.java rename to ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostLinearProblemTest.java index c36cdc0e06..346bd5de58 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/NewObjectiveFunctionTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostLinearProblemTest.java @@ -36,13 +36,14 @@ /** * @author Jeremy Wang {@literal } */ -public class NewObjectiveFunctionTest { +public class CostLinearProblemTest { List networks; List cracs; RangeActionSetpointResult initialSetpoints; List optimizationPerimeters; - List>> rangeActionsPerStatePerTimestamp; + List>> pstRangeActionsPerStatePerTimestamp; + List>>> rangeActionsPerStatePerTimestamp; MultipleSensitivityResult initialSensiResult; RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/parameters/RaoParameters_DC_SCIP.json")); @@ -50,18 +51,22 @@ public class NewObjectiveFunctionTest { public void setUp() { } - private List>> computeRangeActionsPerStatePerTimestamp() { - List>> rangeActionsPerStatePerTimestamp = new ArrayList<>(); + private void computeRangeActionsPerStatePerTimestamp() { + pstRangeActionsPerStatePerTimestamp = new ArrayList<>(); + rangeActionsPerStatePerTimestamp = new ArrayList<>(); for (Crac crac : cracs) { - Map> rangeActionsPerState = new HashMap<>(); + Map>> rangeActionsPerState = new HashMap<>(); crac.getStates().forEach(state -> rangeActionsPerState.put(state, + new HashSet<>(crac.getPotentiallyAvailableRangeActions(state)))); + rangeActionsPerStatePerTimestamp.add(rangeActionsPerState); + Map> pstRangeActionsPerState = new HashMap<>(); + crac.getStates().forEach(state -> pstRangeActionsPerState.put(state, crac.getPotentiallyAvailableRangeActions(state).stream() .filter(ra -> ra instanceof PstRangeAction) .map(ra -> (PstRangeAction) ra) .collect(Collectors.toSet()))); - rangeActionsPerStatePerTimestamp.add(rangeActionsPerState); + pstRangeActionsPerStatePerTimestamp.add(pstRangeActionsPerState); } - return rangeActionsPerStatePerTimestamp; } private RangeActionSetpointResult computeInitialSetpointsResults() { @@ -124,7 +129,7 @@ public void testLinearProblem() { initialSetpoints = computeInitialSetpointsResults(); optimizationPerimeters = computeOptimizationPerimeters(); - rangeActionsPerStatePerTimestamp = computeRangeActionsPerStatePerTimestamp(); + computeRangeActionsPerStatePerTimestamp(); initialSensiResult = runInitialSensi(); @@ -143,12 +148,11 @@ public void testLinearProblem() { DiscretePstTapFiller discretePstTapFiller0 = new DiscretePstTapFiller( networks.get(0), optimizationPerimeters.get(0), - rangeActionsPerStatePerTimestamp.get(0), + pstRangeActionsPerStatePerTimestamp.get(0), initialSetpoints); - Set allCnecs = new HashSet<>(); - allCnecs.addAll(cracs.get(0).getFlowCnecs()); - MinCostHardFiller minCostHardFiller = new MinCostHardFiller(allCnecs, Unit.MEGAWATT, rangeActionsPerStatePerTimestamp.get(0)); + Set allCnecs = new HashSet<>(cracs.get(0).getFlowCnecs()); + MinCostHardFiller minCostHardFiller = new MinCostHardFiller(allCnecs, rangeActionsPerStatePerTimestamp.get(0)); MultiTSFiller multiTSFiller = new MultiTSFiller( optimizationPerimeters, diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java new file mode 100644 index 0000000000..5d31e51c3d --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java @@ -0,0 +1,252 @@ +/* + * 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.linearproblem; + +import com.powsybl.iidm.network.Network; +import com.powsybl.openrao.data.cracapi.Crac; +import com.powsybl.openrao.data.cracapi.Instant; +import com.powsybl.openrao.data.cracapi.State; +import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; +import com.powsybl.openrao.data.cracapi.rangeaction.PstRangeAction; +import com.powsybl.openrao.data.cracapi.rangeaction.RangeAction; +import com.powsybl.openrao.data.cracioapi.CracImporters; +import com.powsybl.openrao.raoapi.json.JsonRaoParameters; +import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters; +import com.powsybl.openrao.raoapi.parameters.RaoParameters; +import com.powsybl.openrao.raoapi.parameters.extensions.LoopFlowParametersExtension; +import com.powsybl.openrao.raoapi.parameters.extensions.MnecParametersExtension; +import com.powsybl.openrao.raoapi.parameters.extensions.RelativeMarginsParametersExtension; +import com.powsybl.openrao.searchtreerao.commons.SensitivityComputerMultiTS; +import com.powsybl.openrao.searchtreerao.commons.ToolProvider; +import com.powsybl.openrao.searchtreerao.commons.objectivefunctionevaluator.ObjectiveFunction; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.PreventiveOptimizationPerimeter; +import com.powsybl.openrao.searchtreerao.commons.parameters.RangeActionLimitationParameters; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.IteratingLinearOptimizer; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.IteratingLinearOptimizerMultiTS; +import com.powsybl.openrao.searchtreerao.linearoptimisation.inputs.IteratingLinearOptimizerInput; +import com.powsybl.openrao.searchtreerao.linearoptimisation.inputs.IteratingLinearOptimizerMultiTSInput; +import com.powsybl.openrao.searchtreerao.linearoptimisation.parameters.IteratingLinearOptimizerParameters; +import com.powsybl.openrao.searchtreerao.result.api.LinearOptimizationResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; +import com.powsybl.openrao.searchtreerao.result.impl.MultipleSensitivityResult; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; +import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl; +import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.*; + +/** + * @author Jeremy Wang {@literal } + */ +public class CostMIPMultiTsTest { + List networks; + List cracs; + RangeActionSetpointResult initialSetpoints; + List optimizationPerimeters; + MultipleSensitivityResult initialSensiResult; + RangeActionsOptimizationParameters.PstModel pstModel = RangeActionsOptimizationParameters.PstModel.CONTINUOUS; + RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/parameters/RaoParameters_MIN_COST.json")); + + @BeforeEach + public void setUp() { + raoParameters.getRangeActionsOptimizationParameters().setPstModel(pstModel); + } + + private void importNetworksAndCracs(List cracsPaths, List networksPaths) { + cracs = new ArrayList<>(); + networks = new ArrayList<>(); + for (int i = 0; i < networksPaths.size(); i++) { + networks.add(Network.read(networksPaths.get(i), getClass().getResourceAsStream("/" + networksPaths.get(i)))); + cracs.add(CracImporters.importCrac(cracsPaths.get(i), getClass().getResourceAsStream("/" + cracsPaths.get(i)), networks.get(i))); + } + } + + private RangeActionSetpointResult computeInitialSetpointsResults() { + Map, Double> setpoints = new HashMap<>(); + for (int i = 0; i < cracs.size(); i++) { + for (RangeAction rangeAction : cracs.get(i).getRangeActions()) { + setpoints.put(rangeAction, rangeAction.getCurrentSetpoint(networks.get(i))); + } + } + return new RangeActionSetpointResultImpl(setpoints); + } + + private List computeOptimizationPerimeters() { + List perimeters = new ArrayList<>(); + for (Crac crac : cracs) { + perimeters.add(new PreventiveOptimizationPerimeter( + crac.getPreventiveState(), + crac.getFlowCnecs(), + new HashSet<>(), + crac.getNetworkActions(), + crac.getRangeActions())); + } + return perimeters; + } + + private MultipleSensitivityResult runInitialSensi() { + List> cnecsList = new ArrayList<>(); + cracs.forEach(crac -> cnecsList.add(crac.getFlowCnecs())); + + Set> rangeActionsSet = new HashSet<>(); + cracs.forEach(crac -> rangeActionsSet.addAll(crac.getRangeActions())); + + ToolProvider toolProvider = ToolProvider.create().withNetwork(networks.get(0)).withRaoParameters(raoParameters).build(); //the attributes in the class are only used for loopflow things + + SensitivityComputerMultiTS sensitivityComputerMultiTS = SensitivityComputerMultiTS.create() + .withCnecs(cnecsList) + .withRangeActions(rangeActionsSet) + .withOutageInstant(cracs.get(0).getOutageInstant()) + .withToolProvider(toolProvider) + .build(); + sensitivityComputerMultiTS.compute(networks); + return sensitivityComputerMultiTS.getSensitivityResults(); + } + + //This test highlights a problem about optimizing multiple time steps at once: + //The RAO does not try to optimize a TS if a worse TS exists + //Here pst2 from TS1 could have a setpoint of 6.22, but it keeps it to 0.0 (initial setpoint) because TS0 is worse + @Test + public void testTwoTimestepsThreePst() { + List cracsPaths = List.of( + "multi-ts/crac/crac-3pst-ts0.json", + "multi-ts/crac/crac-3pst-ts1.json" + ); + List networksPaths = Collections.nCopies(2, "multi-ts/network/12NodesProdFR_3PST.uct"); + + importNetworksAndCracs(cracsPaths, networksPaths); + initialSetpoints = computeInitialSetpointsResults(); + optimizationPerimeters = computeOptimizationPerimeters(); + initialSensiResult = runInitialSensi(); + + LinearOptimizationResult result = runIteratingLinearOptimization(); + System.out.println(result.getStatus()); + + PstRangeAction pstRa0Ts0 = cracs.get(0).getPstRangeAction("pst_be_0 - TS0"); + PstRangeAction pstRa1Ts0 = cracs.get(0).getPstRangeAction("pst_be_1 - TS0"); + PstRangeAction pstRa1Ts1 = cracs.get(1).getPstRangeAction("pst_be_1 - TS1"); + PstRangeAction pstRa2Ts1 = cracs.get(1).getPstRangeAction("pst_be_2 - TS1"); + + State state0 = optimizationPerimeters.get(0).getMainOptimizationState(); + State state1 = optimizationPerimeters.get(1).getMainOptimizationState(); + double pstOptimizedSetPoint0Ts0 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa0Ts0, state0); + double pstOptimizedSetPoint1Ts0 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa1Ts0, state0); + double pstOptimizedSetPoint1Ts1 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa1Ts1, state1); + double pstOptimizedSetPoint2Ts1 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa2Ts1, state1); + + System.out.println("---- TS0 ----"); + System.out.println(pstOptimizedSetPoint0Ts0); + System.out.println(pstOptimizedSetPoint1Ts0); + System.out.println("---- TS1 ----"); + System.out.println(pstOptimizedSetPoint1Ts1); + System.out.println(pstOptimizedSetPoint2Ts1); + } + + public LinearOptimizationResult runIteratingLinearOptimization() { + + Instant outageInstant = Mockito.mock(Instant.class); + + Set allCnecs = new HashSet<>(); + cracs.forEach(crac -> allCnecs.addAll(crac.getFlowCnecs())); + + ObjectiveFunction objectiveFunction = ObjectiveFunction.create().build( + allCnecs, + Collections.emptySet(), + initialSensiResult, + initialSensiResult, + initialSetpoints, + null, + Collections.emptySet(), + raoParameters); + + ToolProvider toolProvider = ToolProvider.create().withNetwork(networks.get(0)).withRaoParameters(raoParameters).build(); //the attributes in the class are only used for loopflow things + + IteratingLinearOptimizerMultiTSInput input = IteratingLinearOptimizerMultiTSInput.create() + .withNetworks(networks) + .withOptimizationPerimeters(optimizationPerimeters) + .withInitialFlowResult(initialSensiResult) + .withPrePerimeterFlowResult(initialSensiResult) + .withPrePerimeterSetpoints(initialSetpoints) + .withPreOptimizationFlowResult(initialSensiResult) + .withPreOptimizationSensitivityResult(initialSensiResult) + .withPreOptimizationAppliedRemedialActions(new AppliedRemedialActions()) + .withRaActivationFromParentLeaf(new RangeActionActivationResultImpl(initialSetpoints)) + .withObjectiveFunction(objectiveFunction) + .withToolProvider(toolProvider) + .withOutageInstant(cracs.get(0).getOutageInstant()) + .build(); + + IteratingLinearOptimizerParameters parameters = IteratingLinearOptimizerParameters.create() + .withObjectiveFunction(raoParameters.getObjectiveFunctionParameters().getType()) + .withRangeActionParameters(raoParameters.getRangeActionsOptimizationParameters()) + .withMnecParameters(raoParameters.getExtension(MnecParametersExtension.class)) + .withMaxMinRelativeMarginParameters(raoParameters.getExtension(RelativeMarginsParametersExtension.class)) + .withLoopFlowParameters(raoParameters.getExtension(LoopFlowParametersExtension.class)) + .withUnoptimizedCnecParameters(null) + .withRaLimitationParameters(new RangeActionLimitationParameters()) + .withSolverParameters(raoParameters.getRangeActionsOptimizationParameters().getLinearOptimizationSolver()) + .withMaxNumberOfIterations(raoParameters.getRangeActionsOptimizationParameters().getMaxMipIterations()) + .withRaRangeShrinking(!raoParameters.getRangeActionsOptimizationParameters().getRaRangeShrinking().equals(RangeActionsOptimizationParameters.RaRangeShrinking.DISABLED)) + .build(); + + return IteratingLinearOptimizerMultiTS.optimize(input, parameters, outageInstant); + + } + + public LinearOptimizationResult testProblemAlone(int timeStepIndex) { + Instant outageInstant = Mockito.mock(Instant.class); + + Set allCnecs = new HashSet<>(cracs.get(timeStepIndex).getFlowCnecs()); + + ObjectiveFunction objectiveFunction = ObjectiveFunction.create().build( + allCnecs, + Collections.emptySet(), + initialSensiResult, + initialSensiResult, + initialSetpoints, + null, + Collections.emptySet(), + raoParameters); + + ToolProvider toolProvider = ToolProvider.create().withNetwork(networks.get(0)).withRaoParameters(raoParameters).build(); //the attributes in the class are only used for loopflow things + + IteratingLinearOptimizerInput input0 = IteratingLinearOptimizerInput.create() + .withNetwork(networks.get(timeStepIndex)) + .withOptimizationPerimeter(optimizationPerimeters.get(timeStepIndex)) + .withInitialFlowResult(initialSensiResult) + .withPrePerimeterFlowResult(initialSensiResult) + .withPrePerimeterSetpoints(initialSetpoints) + .withPreOptimizationFlowResult(initialSensiResult) + .withPreOptimizationSensitivityResult(initialSensiResult) + .withPreOptimizationAppliedRemedialActions(new AppliedRemedialActions()) + .withRaActivationFromParentLeaf(new RangeActionActivationResultImpl(initialSetpoints)) + .withObjectiveFunction(objectiveFunction) + .withToolProvider(toolProvider) + .withOutageInstant(cracs.get(timeStepIndex).getOutageInstant()) + .build(); + + IteratingLinearOptimizerParameters parameters = IteratingLinearOptimizerParameters.create() + .withObjectiveFunction(raoParameters.getObjectiveFunctionParameters().getType()) + .withRangeActionParameters(raoParameters.getRangeActionsOptimizationParameters()) + .withMnecParameters(raoParameters.getExtension(MnecParametersExtension.class)) + .withMaxMinRelativeMarginParameters(raoParameters.getExtension(RelativeMarginsParametersExtension.class)) + .withLoopFlowParameters(raoParameters.getExtension(LoopFlowParametersExtension.class)) + .withUnoptimizedCnecParameters(null) + .withRaLimitationParameters(new RangeActionLimitationParameters()) + .withSolverParameters(raoParameters.getRangeActionsOptimizationParameters().getLinearOptimizationSolver()) + .withMaxNumberOfIterations(raoParameters.getRangeActionsOptimizationParameters().getMaxMipIterations()) + .withRaRangeShrinking(!raoParameters.getRangeActionsOptimizationParameters().getRaRangeShrinking().equals(RangeActionsOptimizationParameters.RaRangeShrinking.DISABLED)) + .build(); + + return IteratingLinearOptimizer.optimize(input0, parameters, outageInstant); + } +} diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java new file mode 100644 index 0000000000..6a2adf4db3 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java @@ -0,0 +1,155 @@ +/* + * 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.linearproblem; + +import com.powsybl.iidm.network.Network; +import com.powsybl.openrao.data.cracapi.Crac; +import com.powsybl.openrao.data.cracapi.State; +import com.powsybl.openrao.data.cracapi.rangeaction.PstRangeAction; +import com.powsybl.openrao.data.cracapi.rangeaction.RangeAction; +import com.powsybl.openrao.data.cracioapi.CracImporters; +import com.powsybl.openrao.raoapi.json.JsonRaoParameters; +import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters; +import com.powsybl.openrao.raoapi.parameters.RaoParameters; +import com.powsybl.openrao.raoapi.parameters.extensions.LoopFlowParametersExtension; +import com.powsybl.openrao.raoapi.parameters.extensions.MnecParametersExtension; +import com.powsybl.openrao.raoapi.parameters.extensions.RelativeMarginsParametersExtension; +import com.powsybl.openrao.searchtreerao.commons.SensitivityComputerMultiTS; +import com.powsybl.openrao.searchtreerao.commons.ToolProvider; +import com.powsybl.openrao.searchtreerao.commons.objectivefunctionevaluator.ObjectiveFunction; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; +import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.PreventiveOptimizationPerimeter; +import com.powsybl.openrao.searchtreerao.commons.parameters.RangeActionLimitationParameters; +import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.IteratingLinearOptimizer; +import com.powsybl.openrao.searchtreerao.linearoptimisation.inputs.IteratingLinearOptimizerInput; +import com.powsybl.openrao.searchtreerao.linearoptimisation.parameters.IteratingLinearOptimizerParameters; +import com.powsybl.openrao.searchtreerao.result.api.LinearOptimizationResult; +import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; +import com.powsybl.openrao.searchtreerao.result.impl.*; +import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.*; + +/** + * @author Jeremy Wang {@literal } + */ +public class CostMIPSingleTsTest { + Network network; + Crac crac; + RangeActionSetpointResult initialSetpoints; + OptimizationPerimeter optimizationPerimeter; + MultipleSensitivityResult initialSensiResult; + RangeActionsOptimizationParameters.PstModel pstModel = RangeActionsOptimizationParameters.PstModel.CONTINUOUS; + RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/parameters/RaoParameters_MIN_COST.json")); + + @BeforeEach + public void setUp() { + raoParameters.getRangeActionsOptimizationParameters().setPstModel(pstModel); + } + + private RangeActionSetpointResult computeInitialSetpointsResults() { + Map, Double> setpoints = new HashMap<>(); + for (RangeAction rangeAction : crac.getRangeActions()) { + setpoints.put(rangeAction, rangeAction.getCurrentSetpoint(network)); + } + return new RangeActionSetpointResultImpl(setpoints); + } + + private OptimizationPerimeter computeOptimizationPerimeter() { + return new PreventiveOptimizationPerimeter( + crac.getPreventiveState(), + crac.getFlowCnecs(), + new HashSet<>(), + crac.getNetworkActions(), + crac.getRangeActions() + ); + } + + private MultipleSensitivityResult runInitialSensi() { + ToolProvider toolProvider = ToolProvider.create().withNetwork(network).withRaoParameters(raoParameters).build(); + + SensitivityComputerMultiTS sensitivityComputer = SensitivityComputerMultiTS.create() + .withCnecs(List.of(crac.getFlowCnecs())) + .withRangeActions(crac.getRangeActions()) + .withOutageInstant(crac.getOutageInstant()) + .withToolProvider(toolProvider) + .build(); + sensitivityComputer.compute(List.of(network)); + return sensitivityComputer.getSensitivityResults(); + } + + @Test + public void testTwoPst() { + network = Network.read("multi-ts/network/12NodesProdFR_3PST.uct", getClass().getResourceAsStream("/multi-ts/network/12NodesProdFR_3PST.uct")); + crac = CracImporters.importCrac("multi-ts/crac/crac-cost-2pst.json", + getClass().getResourceAsStream("/multi-ts/crac/crac-cost-2pst.json"), + network); + initialSetpoints = computeInitialSetpointsResults(); + optimizationPerimeter = computeOptimizationPerimeter(); + initialSensiResult = runInitialSensi(); + + LinearOptimizationResult result = runIteratingLinearOptimization(); + System.out.println(result.getStatus()); + + PstRangeAction pstRa0Ts0 = crac.getPstRangeAction("pst_be_0 - TS0"); + PstRangeAction pstRa1Ts0 = crac.getPstRangeAction("pst_be_1 - TS0"); + State state0 = optimizationPerimeter.getMainOptimizationState(); + double pstOptimizedSetPoint0Ts0 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa0Ts0, state0); + double pstOptimizedSetPoint1Ts0 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa1Ts0, state0); + System.out.println("---- PST 0 ----"); + System.out.println(pstOptimizedSetPoint0Ts0); + System.out.println("---- PST 1 ----"); + System.out.println(pstOptimizedSetPoint1Ts0); + } + + public LinearOptimizationResult runIteratingLinearOptimization() { + ObjectiveFunction objectiveFunction = ObjectiveFunction.create().build( + crac.getFlowCnecs(), + Collections.emptySet(), + initialSensiResult, + initialSensiResult, + initialSetpoints, + null, + Collections.emptySet(), + raoParameters); + + ToolProvider toolProvider = ToolProvider.create().withNetwork(network).withRaoParameters(raoParameters).build(); + + IteratingLinearOptimizerInput input = IteratingLinearOptimizerInput.create() + .withNetwork(network) + .withOptimizationPerimeter(optimizationPerimeter) + .withInitialFlowResult(initialSensiResult) + .withPrePerimeterFlowResult(initialSensiResult) + .withPrePerimeterSetpoints(initialSetpoints) + .withPreOptimizationFlowResult(initialSensiResult) + .withPreOptimizationSensitivityResult(initialSensiResult) + .withPreOptimizationAppliedRemedialActions(new AppliedRemedialActions()) + .withRaActivationFromParentLeaf(new RangeActionActivationResultImpl(initialSetpoints)) + .withObjectiveFunction(objectiveFunction) + .withToolProvider(toolProvider) + .withOutageInstant(crac.getOutageInstant()) + .build(); + + IteratingLinearOptimizerParameters parameters = IteratingLinearOptimizerParameters.create() + .withObjectiveFunction(raoParameters.getObjectiveFunctionParameters().getType()) + .withRangeActionParameters(raoParameters.getRangeActionsOptimizationParameters()) + .withMnecParameters(raoParameters.getExtension(MnecParametersExtension.class)) + .withMaxMinRelativeMarginParameters(raoParameters.getExtension(RelativeMarginsParametersExtension.class)) + .withLoopFlowParameters(raoParameters.getExtension(LoopFlowParametersExtension.class)) + .withUnoptimizedCnecParameters(null) + .withRaLimitationParameters(new RangeActionLimitationParameters()) + .withSolverParameters(raoParameters.getRangeActionsOptimizationParameters().getLinearOptimizationSolver()) + .withMaxNumberOfIterations(raoParameters.getRangeActionsOptimizationParameters().getMaxMipIterations()) + .withRaRangeShrinking(!raoParameters.getRangeActionsOptimizationParameters().getRaRangeShrinking().equals(RangeActionsOptimizationParameters.RaRangeShrinking.DISABLED)) + .build(); + + return IteratingLinearOptimizer.optimize(input, parameters, crac.getOutageInstant()); + } +} diff --git a/ra-optimisation/search-tree-rao/src/test/resources/multi-ts/crac/crac-cost-0.json b/ra-optimisation/search-tree-rao/src/test/resources/multi-ts/crac/crac-cost-0.json new file mode 100644 index 0000000000..70ea10408e --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/test/resources/multi-ts/crac/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 - 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 - TS0", + "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": [], + "ra-usage-limits-per-instant" : [] +} \ No newline at end of file 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/resources/files/crac/epic19/crac-cost-2pst.json b/tests/src/test/resources/files/crac/epic19/crac-cost-2pst.json new file mode 100644 index 0000000000..e69de29bb2 From 83a4c4eadc2fe2408d0d4d4228bc069a07b00b7d Mon Sep 17 00:00:00 2001 From: wangjer Date: Tue, 10 Sep 2024 16:15:34 +0200 Subject: [PATCH 04/16] Make the constraint soft with arbitrary penalty Signed-off-by: wangjer --- .../data/cracimpl/AbstractRemedialAction.java | 2 +- .../ObjectiveFunctionParameters.java | 1 + ...CostHardFiller.java => MinCostFiller.java} | 37 +++++++++++++++++-- .../linearproblem/LinearProblemBuilder.java | 6 +-- .../linearproblem/CostLinearProblemTest.java | 4 +- .../linearproblem/CostMIPMultiTsTest.java | 1 + 6 files changed, 42 insertions(+), 9 deletions(-) rename ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/{MinCostHardFiller.java => MinCostFiller.java} (81%) 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 e7dc01d005..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,7 +32,7 @@ public abstract class AbstractRemedialAction> extend private boolean computedUsageMethods = false; private Map usageMethodPerState; private Map usageMethodPerInstant; - private double activationCost; + private double activationCost = 0; protected AbstractRemedialAction(String id, String name, String operator, Set usageRules, Integer speed) { super(id, name); 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 5afb7488f1..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 @@ -41,6 +41,7 @@ public enum ObjectiveFunctionType { MAX_MIN_MARGIN_IN_AMPERE(Unit.AMPERE), MAX_MIN_RELATIVE_MARGIN_IN_MEGAWATT(Unit.MEGAWATT), 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); diff --git a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostHardFiller.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFiller.java similarity index 81% rename from ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostHardFiller.java rename to ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFiller.java index 5e1b961605..4cbe246bc1 100644 --- a/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostHardFiller.java +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFiller.java @@ -11,6 +11,7 @@ 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.commons.RaoUtil; 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; @@ -26,12 +27,13 @@ * @author Viktor Terrier {@literal } * @author Baptiste Seguinot {@literal } */ -public class MinCostHardFiller implements ProblemFiller { +public class MinCostFiller implements ProblemFiller { protected final Set optimizedCnecs; private final Map>> rangeActions; + private final double marginPenaltyCoefficient = 1000; - public MinCostHardFiller(Set optimizedCnecs, - Map>> rangeActions) { + public MinCostFiller(Set optimizedCnecs, + Map>> rangeActions) { this.rangeActions = rangeActions; this.optimizedCnecs = new TreeSet<>(Comparator.comparing(Identifiable::getId)); this.optimizedCnecs.addAll(optimizedCnecs); @@ -44,6 +46,7 @@ public void fill(LinearProblem linearProblem, FlowResult flowResult, Sensitivity // build variables buildTotalCostVariable(linearProblem); buildRangeActionCostVariable(linearProblem); + buildMinimumMarginVariable(linearProblem, validFlowCnecs); // build constraints buildSecureCnecsHardConstraints(linearProblem, validFlowCnecs); @@ -83,6 +86,22 @@ private void buildRangeActionCostVariable(LinearProblem linearProblem) { })); } + /** + * Build the minimum margin variable MM. + * MM represents the smallest margin of all Cnecs. + * It is given in MEGAWATT. + */ + private void buildMinimumMarginVariable(LinearProblem linearProblem, Set validFlowCnecs) { + if (!validFlowCnecs.isEmpty()) { + // INFERIOR TO 0??? + 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. *

@@ -92,6 +111,8 @@ private void buildRangeActionCostVariable(LinearProblem linearProblem) { * fmin[c] <= F[c] (BELOW_THRESHOLD) */ private void buildSecureCnecsHardConstraints(LinearProblem linearProblem, Set validFlowCnecs) { + OpenRaoMPVariable minimumMarginVariable = linearProblem.getMinimumMarginVariable(); + validFlowCnecs.forEach(cnec -> cnec.getMonitoredSides().forEach(side -> { OpenRaoMPVariable flowVariable = linearProblem.getFlowVariable(cnec, side); @@ -99,14 +120,17 @@ private void buildSecureCnecsHardConstraints(LinearProblem linearProblem, Set maxFlow; minFlow = cnec.getLowerBound(side, MEGAWATT); maxFlow = cnec.getUpperBound(side, MEGAWATT); + // double unitConversionCoefficient = RaoUtil.getFlowUnitMultiplier(cnec, side, unit, 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); } })); @@ -122,6 +146,9 @@ private void buildTotalCostConstraints(LinearProblem linearProblem) { OpenRaoMPVariable totalCostVariable = linearProblem.getTotalCostVariable(); OpenRaoMPConstraint totalCostConstraint = linearProblem.addActivationCostConstraint(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); @@ -148,10 +175,14 @@ private void buildRangeActionCostConstraints(LinearProblem linearProblem) { /** * Add in the objective function of the linear problem the total cost TC + * Add min margin as penalty if unsecure */ private void fillObjectiveWithActivationCost(LinearProblem linearProblem) { OpenRaoMPVariable totalCostVariable = linearProblem.getTotalCostVariable(); linearProblem.getObjective().setCoefficient(totalCostVariable, 1); + OpenRaoMPVariable minimumMarginVariable = linearProblem.getMinimumMarginVariable(); + linearProblem.getObjective().setCoefficient(minimumMarginVariable, -marginPenaltyCoefficient); + } } 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 1ef1b544bb..b675a47634 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 @@ -44,7 +44,7 @@ public LinearProblem buildFromInputsAndParameters(IteratingLinearOptimizerInput if (parameters.getObjectiveFunction().relativePositiveMargins()) { this.withProblemFiller(buildMaxMinRelativeMarginFiller()); } else if (parameters.getObjectiveFunction().isMinCost()) { - this.withProblemFiller(buildMinCostHardFiller()); + this.withProblemFiller(buildMinCostFiller()); } else { this.withProblemFiller(buildMaxMinMarginFiller()); } @@ -139,8 +139,8 @@ private ProblemFiller buildMaxMinMarginFiller() { ); } - private ProblemFiller buildMinCostHardFiller() { - return new MinCostHardFiller( + private ProblemFiller buildMinCostFiller() { + return new MinCostFiller( inputs.getOptimizationPerimeter().getOptimizedFlowCnecs(), inputs.getOptimizationPerimeter().getRangeActionsPerState() ); diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostLinearProblemTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostLinearProblemTest.java index 346bd5de58..102597f3d1 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostLinearProblemTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostLinearProblemTest.java @@ -152,7 +152,7 @@ public void testLinearProblem() { initialSetpoints); Set allCnecs = new HashSet<>(cracs.get(0).getFlowCnecs()); - MinCostHardFiller minCostHardFiller = new MinCostHardFiller(allCnecs, rangeActionsPerStatePerTimestamp.get(0)); + MinCostFiller minCostFiller = new MinCostFiller(allCnecs, rangeActionsPerStatePerTimestamp.get(0)); MultiTSFiller multiTSFiller = new MultiTSFiller( optimizationPerimeters, @@ -163,7 +163,7 @@ public void testLinearProblem() { LinearProblem linearProblemMerge = new LinearProblemBuilder() .withSolver(orMpSolver.getSolver()) .withProblemFiller(coreProblemFiller0) - .withProblemFiller(minCostHardFiller) + .withProblemFiller(minCostFiller) .withProblemFiller(discretePstTapFiller0) .withProblemFiller(multiTSFiller) .build(); diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java index 5d31e51c3d..42158e6118 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java @@ -48,6 +48,7 @@ * @author Jeremy Wang {@literal } */ public class CostMIPMultiTsTest { + // File not updated yet List networks; List cracs; RangeActionSetpointResult initialSetpoints; From 66b9163f57e1f31e3468a5e9567a50b9ec4d5f2e Mon Sep 17 00:00:00 2001 From: wangjer Date: Wed, 11 Sep 2024 16:54:19 +0200 Subject: [PATCH 05/16] Format code + add comments Signed-off-by: wangjer --- .../algorithms/fillers/MinCostFiller.java | 16 +++++++------- .../linearproblem/CostMIPSingleTsTest.java | 21 ++++++++++++++++++- 2 files changed, 29 insertions(+), 8 deletions(-) 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 index 4cbe246bc1..4f7eeeb08f 100644 --- 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 @@ -11,7 +11,6 @@ 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.commons.RaoUtil; 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; @@ -24,8 +23,7 @@ import static com.powsybl.openrao.commons.Unit.MEGAWATT; /** - * @author Viktor Terrier {@literal } - * @author Baptiste Seguinot {@literal } + * @author Jeremy Wang {@literal } */ public class MinCostFiller implements ProblemFiller { protected final Set optimizedCnecs; @@ -90,10 +88,11 @@ private void buildRangeActionCostVariable(LinearProblem linearProblem) { * 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()) { - // INFERIOR TO 0??? + // 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. @@ -104,11 +103,13 @@ private void buildMinimumMarginVariable(LinearProblem linearProblem, Set * For each Cnec c, the constraints are: *

- * F[c] <= fmax[c] (ABOVE_THRESHOLD) - * fmin[c] <= F[c] (BELOW_THRESHOLD) + * MM <= fmax[c] - F[c] (ABOVE_THRESHOLD) + * MM <= F[c] - fmin[c] (BELOW_THRESHOLD) */ private void buildSecureCnecsHardConstraints(LinearProblem linearProblem, Set validFlowCnecs) { OpenRaoMPVariable minimumMarginVariable = linearProblem.getMinimumMarginVariable(); @@ -175,12 +176,13 @@ private void buildRangeActionCostConstraints(LinearProblem linearProblem) { /** * Add in the objective function of the linear problem the total cost TC - * Add min margin as penalty if unsecure + * Add min margin as penalty if unsecure. */ private void fillObjectiveWithActivationCost(LinearProblem linearProblem) { OpenRaoMPVariable totalCostVariable = linearProblem.getTotalCostVariable(); linearProblem.getObjective().setCoefficient(totalCostVariable, 1); OpenRaoMPVariable minimumMarginVariable = linearProblem.getMinimumMarginVariable(); + // marginPenaltyCoefficient is arbitrary for now linearProblem.getObjective().setCoefficient(minimumMarginVariable, -marginPenaltyCoefficient); } diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java index 6a2adf4db3..3708a729da 100644 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java @@ -46,7 +46,7 @@ public class CostMIPSingleTsTest { RangeActionSetpointResult initialSetpoints; OptimizationPerimeter optimizationPerimeter; MultipleSensitivityResult initialSensiResult; - RangeActionsOptimizationParameters.PstModel pstModel = RangeActionsOptimizationParameters.PstModel.CONTINUOUS; + RangeActionsOptimizationParameters.PstModel pstModel = RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS; RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/parameters/RaoParameters_MIN_COST.json")); @BeforeEach @@ -85,6 +85,25 @@ private MultipleSensitivityResult runInitialSensi() { return sensitivityComputer.getSensitivityResults(); } + @Test + public void testSimpleCase() { + network = Network.read("multi-ts/network/12NodesProdFR.uct", getClass().getResourceAsStream("/multi-ts/network/12NodesProdFR.uct")); + crac = CracImporters.importCrac("multi-ts/crac/crac-cost-0.json", + getClass().getResourceAsStream("/multi-ts/crac/crac-cost-0.json"), + network); + initialSetpoints = computeInitialSetpointsResults(); + optimizationPerimeter = computeOptimizationPerimeter(); + initialSensiResult = runInitialSensi(); + + LinearOptimizationResult result = runIteratingLinearOptimization(); + System.out.println(result.getStatus()); + + PstRangeAction pstRa0Ts0 = crac.getPstRangeAction("pst_be - TS0"); + State state0 = optimizationPerimeter.getMainOptimizationState(); + double pstOptimizedSetPoint0Ts0 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa0Ts0, state0); + System.out.println(pstOptimizedSetPoint0Ts0); + } + @Test public void testTwoPst() { network = Network.read("multi-ts/network/12NodesProdFR_3PST.uct", getClass().getResourceAsStream("/multi-ts/network/12NodesProdFR_3PST.uct")); From 33d68b308f554db904448891471e50aae512a8d7 Mon Sep 17 00:00:00 2001 From: wangjer Date: Thu, 12 Sep 2024 15:08:57 +0200 Subject: [PATCH 06/16] Remove multiTS related content + fix cherry-pick issues Signed-off-by: wangjer --- .../json/JsonRetrocompatibilityTest.java | 13 - .../retrocompatibility/v2/crac-v2.3.json | 9 +- .../retrocompatibility/v2/crac-v2.4.json | 3 +- .../retrocompatibility/v2/crac-v2.5.json | 3 +- .../data/cracapi/NetworkActionUtils.java | 6 + .../algorithms/fillers/MinCostFiller.java | 10 +- .../linearproblem/CostLinearProblemTest.java | 181 ------------- .../linearproblem/CostMIPMultiTsTest.java | 253 ------------------ .../linearproblem/CostMIPSingleTsTest.java | 174 ------------ .../resources/multi-ts/crac/crac-cost-0.json | 106 -------- .../files/crac/epic19/crac-cost-0.json | 0 .../files/crac/epic19/crac-cost-2pst.json | 0 ...rac-with-max-3-elementary-actions-pst.json | 4 +- ...rac-with-max-7-elementary-actions-pst.json | 4 +- 14 files changed, 23 insertions(+), 743 deletions(-) delete mode 100644 ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostLinearProblemTest.java delete mode 100644 ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java delete mode 100644 ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java delete mode 100644 ra-optimisation/search-tree-rao/src/test/resources/multi-ts/crac/crac-cost-0.json delete mode 100644 tests/src/test/resources/files/crac/epic19/crac-cost-0.json delete mode 100644 tests/src/test/resources/files/crac/epic19/crac-cost-2pst.json diff --git a/data/crac-io/crac-io-json/src/test/java/com/powsybl/openrao/data/cracio/json/JsonRetrocompatibilityTest.java b/data/crac-io/crac-io-json/src/test/java/com/powsybl/openrao/data/cracio/json/JsonRetrocompatibilityTest.java index 76b5f12679..c5c1e9bed4 100644 --- a/data/crac-io/crac-io-json/src/test/java/com/powsybl/openrao/data/cracio/json/JsonRetrocompatibilityTest.java +++ b/data/crac-io/crac-io-json/src/test/java/com/powsybl/openrao/data/cracio/json/JsonRetrocompatibilityTest.java @@ -769,19 +769,6 @@ private void testContentOfV2Point3Crac(Crac crac) { assertEquals(Unit.TAP, pstRelTimeStepRange.getUnit()); assertEquals(3.2, pstRangeAction4.getActivationCost()); - StandardRange injectionAbsRange = crac.getInjectionRangeAction("injectionRange1Id").getRanges().stream() - .filter(tapRange -> tapRange.getRangeType().equals(RangeType.ABSOLUTE)) - .findAny().orElse(null); - StandardRange injectionRelTimeStepRange = crac.getInjectionRangeAction("injectionRange1Id").getRanges().stream() - .filter(tapRange -> tapRange.getRangeType().equals(RangeType.RELATIVE_TO_PREVIOUS_TIME_STEP)) - .findAny().orElse(null); - assertNotNull(injectionAbsRange); - assertEquals(-100.0, injectionAbsRange.getMin()); - assertEquals(300.0, injectionAbsRange.getMax()); - assertNotNull(injectionRelTimeStepRange); - assertEquals(-400, injectionRelTimeStepRange.getMin()); - assertEquals(600, injectionRelTimeStepRange.getMax()); - // check new border attribute assertEquals("border1", crac.getCnec("cnec1outageId").getBorder()); assertEquals("border1", crac.getCnec("cnec1prevId").getBorder()); diff --git a/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.3.json b/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.3.json index 79723256c0..737a113e87 100644 --- a/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.3.json +++ b/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.3.json @@ -370,12 +370,11 @@ }, "initialSetpoint" : 50, "ranges" : [ { - "min" : -100.0, - "max" : 300.0 + "min" : -500.0, + "max" : 500.0 }, { - "min" : -400.0, - "max" : 600.0, - "rangeType" : "relativeToPreviousTimeStep" + "min" : -1000.0, + "max" : 1000.0 } ] } ], "counterTradeRangeActions" : [ { diff --git a/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.4.json b/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.4.json index b0052a082b..53cfbc5540 100644 --- a/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.4.json +++ b/data/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-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.5.json b/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.5.json index 2f1fc42923..939f9b386b 100644 --- a/data/crac-io/crac-io-json/src/test/resources/retrocompatibility/v2/crac-v2.5.json +++ b/data/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/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/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 index 4f7eeeb08f..17ad9a7b3e 100644 --- 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 @@ -70,7 +70,7 @@ public void updateBetweenMipIteration(LinearProblem linearProblem, RangeActionAc * TC represents the activation cost of all range actions. */ private void buildTotalCostVariable(LinearProblem linearProblem) { - linearProblem.addTotalCostVariable(0, LinearProblem.infinity()); + linearProblem.addTotalCostVariable(0, linearProblem.infinity()); } /** @@ -80,7 +80,7 @@ private void buildTotalCostVariable(LinearProblem linearProblem) { private void buildRangeActionCostVariable(LinearProblem linearProblem) { rangeActions.forEach((state, rangeActionSet) -> rangeActionSet.forEach(rangeAction -> { - linearProblem.addRangeActionCostVariable(0, LinearProblem.infinity(), rangeAction, state); + linearProblem.addRangeActionCostVariable(0, linearProblem.infinity(), rangeAction, state); })); } @@ -93,7 +93,7 @@ private void buildRangeActionCostVariable(LinearProblem linearProblem) { 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); + 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 @@ -124,13 +124,13 @@ private void buildSecureCnecsHardConstraints(LinearProblem linearProblem, Set} - */ -public class CostLinearProblemTest { - - List networks; - List cracs; - RangeActionSetpointResult initialSetpoints; - List optimizationPerimeters; - List>> pstRangeActionsPerStatePerTimestamp; - List>>> rangeActionsPerStatePerTimestamp; - MultipleSensitivityResult initialSensiResult; - RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/parameters/RaoParameters_DC_SCIP.json")); - - @BeforeEach - public void setUp() { - } - - private void computeRangeActionsPerStatePerTimestamp() { - pstRangeActionsPerStatePerTimestamp = new ArrayList<>(); - rangeActionsPerStatePerTimestamp = new ArrayList<>(); - for (Crac crac : cracs) { - Map>> rangeActionsPerState = new HashMap<>(); - crac.getStates().forEach(state -> rangeActionsPerState.put(state, - new HashSet<>(crac.getPotentiallyAvailableRangeActions(state)))); - rangeActionsPerStatePerTimestamp.add(rangeActionsPerState); - Map> pstRangeActionsPerState = new HashMap<>(); - crac.getStates().forEach(state -> pstRangeActionsPerState.put(state, - crac.getPotentiallyAvailableRangeActions(state).stream() - .filter(ra -> ra instanceof PstRangeAction) - .map(ra -> (PstRangeAction) ra) - .collect(Collectors.toSet()))); - pstRangeActionsPerStatePerTimestamp.add(pstRangeActionsPerState); - } - } - - private RangeActionSetpointResult computeInitialSetpointsResults() { - Map, Double> setpoints = new HashMap<>(); - for (int i = 0; i < cracs.size(); i++) { - for (RangeAction rangeAction : cracs.get(i).getRangeActions()) { - setpoints.put(rangeAction, rangeAction.getCurrentSetpoint(networks.get(i))); - } - } - return new RangeActionSetpointResultImpl(setpoints); - } - - private List computeOptimizationPerimeters() { - List perimeters = new ArrayList<>(); - for (Crac crac : cracs) { - perimeters.add(new PreventiveOptimizationPerimeter( - crac.getPreventiveState(), - crac.getFlowCnecs(), - new HashSet<>(), - crac.getNetworkActions(), - crac.getRangeActions())); - } - return perimeters; - } - - private MultipleSensitivityResult runInitialSensi() { - List> cnecsList = new ArrayList<>(); - cracs.forEach(crac -> cnecsList.add(crac.getFlowCnecs())); - - Set> rangeActionsSet = new HashSet<>(); - cracs.forEach(crac -> rangeActionsSet.addAll(crac.getRangeActions())); - - ToolProvider toolProvider = ToolProvider.create().withNetwork(networks.get(0)).withRaoParameters(raoParameters).build(); //the attributes in the class are only used for loopflow things - - SensitivityComputerMultiTS sensitivityComputerMultiTS = SensitivityComputerMultiTS.create() - .withCnecs(cnecsList) - .withRangeActions(rangeActionsSet) - .withOutageInstant(cracs.get(0).getOutageInstant()) - .withToolProvider(toolProvider) - .build(); - sensitivityComputerMultiTS.compute(networks); - return sensitivityComputerMultiTS.getSensitivityResults(); - } - - private void importNetworksAndCracs(List cracsPaths, List networksPaths) { - cracs = new ArrayList<>(); - networks = new ArrayList<>(); - for (int i = 0; i < networksPaths.size(); i++) { - networks.add(Network.read(networksPaths.get(i), getClass().getResourceAsStream("/" + networksPaths.get(i)))); - cracs.add(CracImporters.importCrac(cracsPaths.get(i), getClass().getResourceAsStream("/" + cracsPaths.get(i)), networks.get(i))); - } - } - - @Test - public void testLinearProblem() { - importNetworksAndCracs( - List.of("multi-ts/crac/crac-cost-0.json"), - List.of("multi-ts/network/12NodesProdFR.uct") - ); - - initialSetpoints = computeInitialSetpointsResults(); - optimizationPerimeters = computeOptimizationPerimeters(); - computeRangeActionsPerStatePerTimestamp(); - - initialSensiResult = runInitialSensi(); - - RangeActionsOptimizationParameters rangeActionParameters = RangeActionsOptimizationParameters.buildFromRaoParameters(new RaoParameters()); - rangeActionParameters.setPstModel(RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS); - OpenRaoMPSolver orMpSolver = new OpenRaoMPSolver("solver", RangeActionsOptimizationParameters.Solver.SCIP); - - CoreProblemFiller coreProblemFiller0 = new CoreProblemFiller( - optimizationPerimeters.get(0), - initialSetpoints, - new RangeActionActivationResultImpl(initialSetpoints), - rangeActionParameters, - Unit.MEGAWATT, - false); - - DiscretePstTapFiller discretePstTapFiller0 = new DiscretePstTapFiller( - networks.get(0), - optimizationPerimeters.get(0), - pstRangeActionsPerStatePerTimestamp.get(0), - initialSetpoints); - - Set allCnecs = new HashSet<>(cracs.get(0).getFlowCnecs()); - MinCostFiller minCostFiller = new MinCostFiller(allCnecs, rangeActionsPerStatePerTimestamp.get(0)); - - MultiTSFiller multiTSFiller = new MultiTSFiller( - optimizationPerimeters, - networks, - rangeActionParameters, - new RangeActionActivationResultImpl(initialSetpoints)); - - LinearProblem linearProblemMerge = new LinearProblemBuilder() - .withSolver(orMpSolver.getSolver()) - .withProblemFiller(coreProblemFiller0) - .withProblemFiller(minCostFiller) - .withProblemFiller(discretePstTapFiller0) - .withProblemFiller(multiTSFiller) - .build(); - - linearProblemMerge.fill(initialSensiResult, initialSensiResult); - linearProblemMerge.solve(); - - PstRangeAction pstRa0 = cracs.get(0).getPstRangeActions().iterator().next(); - State state0 = optimizationPerimeters.get(0).getMainOptimizationState(); - double setpointMerge0 = linearProblemMerge.getRangeActionSetpointVariable(pstRa0, state0).solutionValue(); - - System.out.println(setpointMerge0); - } - -} diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java deleted file mode 100644 index 42158e6118..0000000000 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPMultiTsTest.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * 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.linearproblem; - -import com.powsybl.iidm.network.Network; -import com.powsybl.openrao.data.cracapi.Crac; -import com.powsybl.openrao.data.cracapi.Instant; -import com.powsybl.openrao.data.cracapi.State; -import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; -import com.powsybl.openrao.data.cracapi.rangeaction.PstRangeAction; -import com.powsybl.openrao.data.cracapi.rangeaction.RangeAction; -import com.powsybl.openrao.data.cracioapi.CracImporters; -import com.powsybl.openrao.raoapi.json.JsonRaoParameters; -import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters; -import com.powsybl.openrao.raoapi.parameters.RaoParameters; -import com.powsybl.openrao.raoapi.parameters.extensions.LoopFlowParametersExtension; -import com.powsybl.openrao.raoapi.parameters.extensions.MnecParametersExtension; -import com.powsybl.openrao.raoapi.parameters.extensions.RelativeMarginsParametersExtension; -import com.powsybl.openrao.searchtreerao.commons.SensitivityComputerMultiTS; -import com.powsybl.openrao.searchtreerao.commons.ToolProvider; -import com.powsybl.openrao.searchtreerao.commons.objectivefunctionevaluator.ObjectiveFunction; -import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; -import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.PreventiveOptimizationPerimeter; -import com.powsybl.openrao.searchtreerao.commons.parameters.RangeActionLimitationParameters; -import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.IteratingLinearOptimizer; -import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.IteratingLinearOptimizerMultiTS; -import com.powsybl.openrao.searchtreerao.linearoptimisation.inputs.IteratingLinearOptimizerInput; -import com.powsybl.openrao.searchtreerao.linearoptimisation.inputs.IteratingLinearOptimizerMultiTSInput; -import com.powsybl.openrao.searchtreerao.linearoptimisation.parameters.IteratingLinearOptimizerParameters; -import com.powsybl.openrao.searchtreerao.result.api.LinearOptimizationResult; -import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; -import com.powsybl.openrao.searchtreerao.result.impl.MultipleSensitivityResult; -import com.powsybl.openrao.searchtreerao.result.impl.RangeActionActivationResultImpl; -import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl; -import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import java.util.*; - -/** - * @author Jeremy Wang {@literal } - */ -public class CostMIPMultiTsTest { - // File not updated yet - List networks; - List cracs; - RangeActionSetpointResult initialSetpoints; - List optimizationPerimeters; - MultipleSensitivityResult initialSensiResult; - RangeActionsOptimizationParameters.PstModel pstModel = RangeActionsOptimizationParameters.PstModel.CONTINUOUS; - RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/parameters/RaoParameters_MIN_COST.json")); - - @BeforeEach - public void setUp() { - raoParameters.getRangeActionsOptimizationParameters().setPstModel(pstModel); - } - - private void importNetworksAndCracs(List cracsPaths, List networksPaths) { - cracs = new ArrayList<>(); - networks = new ArrayList<>(); - for (int i = 0; i < networksPaths.size(); i++) { - networks.add(Network.read(networksPaths.get(i), getClass().getResourceAsStream("/" + networksPaths.get(i)))); - cracs.add(CracImporters.importCrac(cracsPaths.get(i), getClass().getResourceAsStream("/" + cracsPaths.get(i)), networks.get(i))); - } - } - - private RangeActionSetpointResult computeInitialSetpointsResults() { - Map, Double> setpoints = new HashMap<>(); - for (int i = 0; i < cracs.size(); i++) { - for (RangeAction rangeAction : cracs.get(i).getRangeActions()) { - setpoints.put(rangeAction, rangeAction.getCurrentSetpoint(networks.get(i))); - } - } - return new RangeActionSetpointResultImpl(setpoints); - } - - private List computeOptimizationPerimeters() { - List perimeters = new ArrayList<>(); - for (Crac crac : cracs) { - perimeters.add(new PreventiveOptimizationPerimeter( - crac.getPreventiveState(), - crac.getFlowCnecs(), - new HashSet<>(), - crac.getNetworkActions(), - crac.getRangeActions())); - } - return perimeters; - } - - private MultipleSensitivityResult runInitialSensi() { - List> cnecsList = new ArrayList<>(); - cracs.forEach(crac -> cnecsList.add(crac.getFlowCnecs())); - - Set> rangeActionsSet = new HashSet<>(); - cracs.forEach(crac -> rangeActionsSet.addAll(crac.getRangeActions())); - - ToolProvider toolProvider = ToolProvider.create().withNetwork(networks.get(0)).withRaoParameters(raoParameters).build(); //the attributes in the class are only used for loopflow things - - SensitivityComputerMultiTS sensitivityComputerMultiTS = SensitivityComputerMultiTS.create() - .withCnecs(cnecsList) - .withRangeActions(rangeActionsSet) - .withOutageInstant(cracs.get(0).getOutageInstant()) - .withToolProvider(toolProvider) - .build(); - sensitivityComputerMultiTS.compute(networks); - return sensitivityComputerMultiTS.getSensitivityResults(); - } - - //This test highlights a problem about optimizing multiple time steps at once: - //The RAO does not try to optimize a TS if a worse TS exists - //Here pst2 from TS1 could have a setpoint of 6.22, but it keeps it to 0.0 (initial setpoint) because TS0 is worse - @Test - public void testTwoTimestepsThreePst() { - List cracsPaths = List.of( - "multi-ts/crac/crac-3pst-ts0.json", - "multi-ts/crac/crac-3pst-ts1.json" - ); - List networksPaths = Collections.nCopies(2, "multi-ts/network/12NodesProdFR_3PST.uct"); - - importNetworksAndCracs(cracsPaths, networksPaths); - initialSetpoints = computeInitialSetpointsResults(); - optimizationPerimeters = computeOptimizationPerimeters(); - initialSensiResult = runInitialSensi(); - - LinearOptimizationResult result = runIteratingLinearOptimization(); - System.out.println(result.getStatus()); - - PstRangeAction pstRa0Ts0 = cracs.get(0).getPstRangeAction("pst_be_0 - TS0"); - PstRangeAction pstRa1Ts0 = cracs.get(0).getPstRangeAction("pst_be_1 - TS0"); - PstRangeAction pstRa1Ts1 = cracs.get(1).getPstRangeAction("pst_be_1 - TS1"); - PstRangeAction pstRa2Ts1 = cracs.get(1).getPstRangeAction("pst_be_2 - TS1"); - - State state0 = optimizationPerimeters.get(0).getMainOptimizationState(); - State state1 = optimizationPerimeters.get(1).getMainOptimizationState(); - double pstOptimizedSetPoint0Ts0 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa0Ts0, state0); - double pstOptimizedSetPoint1Ts0 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa1Ts0, state0); - double pstOptimizedSetPoint1Ts1 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa1Ts1, state1); - double pstOptimizedSetPoint2Ts1 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa2Ts1, state1); - - System.out.println("---- TS0 ----"); - System.out.println(pstOptimizedSetPoint0Ts0); - System.out.println(pstOptimizedSetPoint1Ts0); - System.out.println("---- TS1 ----"); - System.out.println(pstOptimizedSetPoint1Ts1); - System.out.println(pstOptimizedSetPoint2Ts1); - } - - public LinearOptimizationResult runIteratingLinearOptimization() { - - Instant outageInstant = Mockito.mock(Instant.class); - - Set allCnecs = new HashSet<>(); - cracs.forEach(crac -> allCnecs.addAll(crac.getFlowCnecs())); - - ObjectiveFunction objectiveFunction = ObjectiveFunction.create().build( - allCnecs, - Collections.emptySet(), - initialSensiResult, - initialSensiResult, - initialSetpoints, - null, - Collections.emptySet(), - raoParameters); - - ToolProvider toolProvider = ToolProvider.create().withNetwork(networks.get(0)).withRaoParameters(raoParameters).build(); //the attributes in the class are only used for loopflow things - - IteratingLinearOptimizerMultiTSInput input = IteratingLinearOptimizerMultiTSInput.create() - .withNetworks(networks) - .withOptimizationPerimeters(optimizationPerimeters) - .withInitialFlowResult(initialSensiResult) - .withPrePerimeterFlowResult(initialSensiResult) - .withPrePerimeterSetpoints(initialSetpoints) - .withPreOptimizationFlowResult(initialSensiResult) - .withPreOptimizationSensitivityResult(initialSensiResult) - .withPreOptimizationAppliedRemedialActions(new AppliedRemedialActions()) - .withRaActivationFromParentLeaf(new RangeActionActivationResultImpl(initialSetpoints)) - .withObjectiveFunction(objectiveFunction) - .withToolProvider(toolProvider) - .withOutageInstant(cracs.get(0).getOutageInstant()) - .build(); - - IteratingLinearOptimizerParameters parameters = IteratingLinearOptimizerParameters.create() - .withObjectiveFunction(raoParameters.getObjectiveFunctionParameters().getType()) - .withRangeActionParameters(raoParameters.getRangeActionsOptimizationParameters()) - .withMnecParameters(raoParameters.getExtension(MnecParametersExtension.class)) - .withMaxMinRelativeMarginParameters(raoParameters.getExtension(RelativeMarginsParametersExtension.class)) - .withLoopFlowParameters(raoParameters.getExtension(LoopFlowParametersExtension.class)) - .withUnoptimizedCnecParameters(null) - .withRaLimitationParameters(new RangeActionLimitationParameters()) - .withSolverParameters(raoParameters.getRangeActionsOptimizationParameters().getLinearOptimizationSolver()) - .withMaxNumberOfIterations(raoParameters.getRangeActionsOptimizationParameters().getMaxMipIterations()) - .withRaRangeShrinking(!raoParameters.getRangeActionsOptimizationParameters().getRaRangeShrinking().equals(RangeActionsOptimizationParameters.RaRangeShrinking.DISABLED)) - .build(); - - return IteratingLinearOptimizerMultiTS.optimize(input, parameters, outageInstant); - - } - - public LinearOptimizationResult testProblemAlone(int timeStepIndex) { - Instant outageInstant = Mockito.mock(Instant.class); - - Set allCnecs = new HashSet<>(cracs.get(timeStepIndex).getFlowCnecs()); - - ObjectiveFunction objectiveFunction = ObjectiveFunction.create().build( - allCnecs, - Collections.emptySet(), - initialSensiResult, - initialSensiResult, - initialSetpoints, - null, - Collections.emptySet(), - raoParameters); - - ToolProvider toolProvider = ToolProvider.create().withNetwork(networks.get(0)).withRaoParameters(raoParameters).build(); //the attributes in the class are only used for loopflow things - - IteratingLinearOptimizerInput input0 = IteratingLinearOptimizerInput.create() - .withNetwork(networks.get(timeStepIndex)) - .withOptimizationPerimeter(optimizationPerimeters.get(timeStepIndex)) - .withInitialFlowResult(initialSensiResult) - .withPrePerimeterFlowResult(initialSensiResult) - .withPrePerimeterSetpoints(initialSetpoints) - .withPreOptimizationFlowResult(initialSensiResult) - .withPreOptimizationSensitivityResult(initialSensiResult) - .withPreOptimizationAppliedRemedialActions(new AppliedRemedialActions()) - .withRaActivationFromParentLeaf(new RangeActionActivationResultImpl(initialSetpoints)) - .withObjectiveFunction(objectiveFunction) - .withToolProvider(toolProvider) - .withOutageInstant(cracs.get(timeStepIndex).getOutageInstant()) - .build(); - - IteratingLinearOptimizerParameters parameters = IteratingLinearOptimizerParameters.create() - .withObjectiveFunction(raoParameters.getObjectiveFunctionParameters().getType()) - .withRangeActionParameters(raoParameters.getRangeActionsOptimizationParameters()) - .withMnecParameters(raoParameters.getExtension(MnecParametersExtension.class)) - .withMaxMinRelativeMarginParameters(raoParameters.getExtension(RelativeMarginsParametersExtension.class)) - .withLoopFlowParameters(raoParameters.getExtension(LoopFlowParametersExtension.class)) - .withUnoptimizedCnecParameters(null) - .withRaLimitationParameters(new RangeActionLimitationParameters()) - .withSolverParameters(raoParameters.getRangeActionsOptimizationParameters().getLinearOptimizationSolver()) - .withMaxNumberOfIterations(raoParameters.getRangeActionsOptimizationParameters().getMaxMipIterations()) - .withRaRangeShrinking(!raoParameters.getRangeActionsOptimizationParameters().getRaRangeShrinking().equals(RangeActionsOptimizationParameters.RaRangeShrinking.DISABLED)) - .build(); - - return IteratingLinearOptimizer.optimize(input0, parameters, outageInstant); - } -} diff --git a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java deleted file mode 100644 index 3708a729da..0000000000 --- a/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/linearproblem/CostMIPSingleTsTest.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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.linearproblem; - -import com.powsybl.iidm.network.Network; -import com.powsybl.openrao.data.cracapi.Crac; -import com.powsybl.openrao.data.cracapi.State; -import com.powsybl.openrao.data.cracapi.rangeaction.PstRangeAction; -import com.powsybl.openrao.data.cracapi.rangeaction.RangeAction; -import com.powsybl.openrao.data.cracioapi.CracImporters; -import com.powsybl.openrao.raoapi.json.JsonRaoParameters; -import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters; -import com.powsybl.openrao.raoapi.parameters.RaoParameters; -import com.powsybl.openrao.raoapi.parameters.extensions.LoopFlowParametersExtension; -import com.powsybl.openrao.raoapi.parameters.extensions.MnecParametersExtension; -import com.powsybl.openrao.raoapi.parameters.extensions.RelativeMarginsParametersExtension; -import com.powsybl.openrao.searchtreerao.commons.SensitivityComputerMultiTS; -import com.powsybl.openrao.searchtreerao.commons.ToolProvider; -import com.powsybl.openrao.searchtreerao.commons.objectivefunctionevaluator.ObjectiveFunction; -import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.OptimizationPerimeter; -import com.powsybl.openrao.searchtreerao.commons.optimizationperimeters.PreventiveOptimizationPerimeter; -import com.powsybl.openrao.searchtreerao.commons.parameters.RangeActionLimitationParameters; -import com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.IteratingLinearOptimizer; -import com.powsybl.openrao.searchtreerao.linearoptimisation.inputs.IteratingLinearOptimizerInput; -import com.powsybl.openrao.searchtreerao.linearoptimisation.parameters.IteratingLinearOptimizerParameters; -import com.powsybl.openrao.searchtreerao.result.api.LinearOptimizationResult; -import com.powsybl.openrao.searchtreerao.result.api.RangeActionSetpointResult; -import com.powsybl.openrao.searchtreerao.result.impl.*; -import com.powsybl.openrao.sensitivityanalysis.AppliedRemedialActions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.*; - -/** - * @author Jeremy Wang {@literal } - */ -public class CostMIPSingleTsTest { - Network network; - Crac crac; - RangeActionSetpointResult initialSetpoints; - OptimizationPerimeter optimizationPerimeter; - MultipleSensitivityResult initialSensiResult; - RangeActionsOptimizationParameters.PstModel pstModel = RangeActionsOptimizationParameters.PstModel.APPROXIMATED_INTEGERS; - RaoParameters raoParameters = JsonRaoParameters.read(getClass().getResourceAsStream("/parameters/RaoParameters_MIN_COST.json")); - - @BeforeEach - public void setUp() { - raoParameters.getRangeActionsOptimizationParameters().setPstModel(pstModel); - } - - private RangeActionSetpointResult computeInitialSetpointsResults() { - Map, Double> setpoints = new HashMap<>(); - for (RangeAction rangeAction : crac.getRangeActions()) { - setpoints.put(rangeAction, rangeAction.getCurrentSetpoint(network)); - } - return new RangeActionSetpointResultImpl(setpoints); - } - - private OptimizationPerimeter computeOptimizationPerimeter() { - return new PreventiveOptimizationPerimeter( - crac.getPreventiveState(), - crac.getFlowCnecs(), - new HashSet<>(), - crac.getNetworkActions(), - crac.getRangeActions() - ); - } - - private MultipleSensitivityResult runInitialSensi() { - ToolProvider toolProvider = ToolProvider.create().withNetwork(network).withRaoParameters(raoParameters).build(); - - SensitivityComputerMultiTS sensitivityComputer = SensitivityComputerMultiTS.create() - .withCnecs(List.of(crac.getFlowCnecs())) - .withRangeActions(crac.getRangeActions()) - .withOutageInstant(crac.getOutageInstant()) - .withToolProvider(toolProvider) - .build(); - sensitivityComputer.compute(List.of(network)); - return sensitivityComputer.getSensitivityResults(); - } - - @Test - public void testSimpleCase() { - network = Network.read("multi-ts/network/12NodesProdFR.uct", getClass().getResourceAsStream("/multi-ts/network/12NodesProdFR.uct")); - crac = CracImporters.importCrac("multi-ts/crac/crac-cost-0.json", - getClass().getResourceAsStream("/multi-ts/crac/crac-cost-0.json"), - network); - initialSetpoints = computeInitialSetpointsResults(); - optimizationPerimeter = computeOptimizationPerimeter(); - initialSensiResult = runInitialSensi(); - - LinearOptimizationResult result = runIteratingLinearOptimization(); - System.out.println(result.getStatus()); - - PstRangeAction pstRa0Ts0 = crac.getPstRangeAction("pst_be - TS0"); - State state0 = optimizationPerimeter.getMainOptimizationState(); - double pstOptimizedSetPoint0Ts0 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa0Ts0, state0); - System.out.println(pstOptimizedSetPoint0Ts0); - } - - @Test - public void testTwoPst() { - network = Network.read("multi-ts/network/12NodesProdFR_3PST.uct", getClass().getResourceAsStream("/multi-ts/network/12NodesProdFR_3PST.uct")); - crac = CracImporters.importCrac("multi-ts/crac/crac-cost-2pst.json", - getClass().getResourceAsStream("/multi-ts/crac/crac-cost-2pst.json"), - network); - initialSetpoints = computeInitialSetpointsResults(); - optimizationPerimeter = computeOptimizationPerimeter(); - initialSensiResult = runInitialSensi(); - - LinearOptimizationResult result = runIteratingLinearOptimization(); - System.out.println(result.getStatus()); - - PstRangeAction pstRa0Ts0 = crac.getPstRangeAction("pst_be_0 - TS0"); - PstRangeAction pstRa1Ts0 = crac.getPstRangeAction("pst_be_1 - TS0"); - State state0 = optimizationPerimeter.getMainOptimizationState(); - double pstOptimizedSetPoint0Ts0 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa0Ts0, state0); - double pstOptimizedSetPoint1Ts0 = result.getRangeActionActivationResult().getOptimizedSetpoint(pstRa1Ts0, state0); - System.out.println("---- PST 0 ----"); - System.out.println(pstOptimizedSetPoint0Ts0); - System.out.println("---- PST 1 ----"); - System.out.println(pstOptimizedSetPoint1Ts0); - } - - public LinearOptimizationResult runIteratingLinearOptimization() { - ObjectiveFunction objectiveFunction = ObjectiveFunction.create().build( - crac.getFlowCnecs(), - Collections.emptySet(), - initialSensiResult, - initialSensiResult, - initialSetpoints, - null, - Collections.emptySet(), - raoParameters); - - ToolProvider toolProvider = ToolProvider.create().withNetwork(network).withRaoParameters(raoParameters).build(); - - IteratingLinearOptimizerInput input = IteratingLinearOptimizerInput.create() - .withNetwork(network) - .withOptimizationPerimeter(optimizationPerimeter) - .withInitialFlowResult(initialSensiResult) - .withPrePerimeterFlowResult(initialSensiResult) - .withPrePerimeterSetpoints(initialSetpoints) - .withPreOptimizationFlowResult(initialSensiResult) - .withPreOptimizationSensitivityResult(initialSensiResult) - .withPreOptimizationAppliedRemedialActions(new AppliedRemedialActions()) - .withRaActivationFromParentLeaf(new RangeActionActivationResultImpl(initialSetpoints)) - .withObjectiveFunction(objectiveFunction) - .withToolProvider(toolProvider) - .withOutageInstant(crac.getOutageInstant()) - .build(); - - IteratingLinearOptimizerParameters parameters = IteratingLinearOptimizerParameters.create() - .withObjectiveFunction(raoParameters.getObjectiveFunctionParameters().getType()) - .withRangeActionParameters(raoParameters.getRangeActionsOptimizationParameters()) - .withMnecParameters(raoParameters.getExtension(MnecParametersExtension.class)) - .withMaxMinRelativeMarginParameters(raoParameters.getExtension(RelativeMarginsParametersExtension.class)) - .withLoopFlowParameters(raoParameters.getExtension(LoopFlowParametersExtension.class)) - .withUnoptimizedCnecParameters(null) - .withRaLimitationParameters(new RangeActionLimitationParameters()) - .withSolverParameters(raoParameters.getRangeActionsOptimizationParameters().getLinearOptimizationSolver()) - .withMaxNumberOfIterations(raoParameters.getRangeActionsOptimizationParameters().getMaxMipIterations()) - .withRaRangeShrinking(!raoParameters.getRangeActionsOptimizationParameters().getRaRangeShrinking().equals(RangeActionsOptimizationParameters.RaRangeShrinking.DISABLED)) - .build(); - - return IteratingLinearOptimizer.optimize(input, parameters, crac.getOutageInstant()); - } -} diff --git a/ra-optimisation/search-tree-rao/src/test/resources/multi-ts/crac/crac-cost-0.json b/ra-optimisation/search-tree-rao/src/test/resources/multi-ts/crac/crac-cost-0.json deleted file mode 100644 index 70ea10408e..0000000000 --- a/ra-optimisation/search-tree-rao/src/test/resources/multi-ts/crac/crac-cost-0.json +++ /dev/null @@ -1,106 +0,0 @@ -{ - "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 - TS0", - "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": [], - "ra-usage-limits-per-instant" : [] -} \ No newline at end of file diff --git a/tests/src/test/resources/files/crac/epic19/crac-cost-0.json b/tests/src/test/resources/files/crac/epic19/crac-cost-0.json deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/src/test/resources/files/crac/epic19/crac-cost-2pst.json b/tests/src/test/resources/files/crac/epic19/crac-cost-2pst.json deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/src/test/resources/files/crac/epic19/small-crac-with-max-3-elementary-actions-pst.json b/tests/src/test/resources/files/crac/epic19/small-crac-with-max-3-elementary-actions-pst.json index df9ae928f6..83af7d9c71 100644 --- a/tests/src/test/resources/files/crac/epic19/small-crac-with-max-3-elementary-actions-pst.json +++ b/tests/src/test/resources/files/crac/epic19/small-crac-with-max-3-elementary-actions-pst.json @@ -35,8 +35,8 @@ "nominalV" : [ 400.0 ], "thresholds" : [ { "unit" : "megawatt", - "min" : -400.0, - "max" : 400.0, + "min" : -500.0, + "max" : 500.0, "side" : "left" } ] } diff --git a/tests/src/test/resources/files/crac/epic19/small-crac-with-max-7-elementary-actions-pst.json b/tests/src/test/resources/files/crac/epic19/small-crac-with-max-7-elementary-actions-pst.json index a8a6fe8a03..93c6f49905 100644 --- a/tests/src/test/resources/files/crac/epic19/small-crac-with-max-7-elementary-actions-pst.json +++ b/tests/src/test/resources/files/crac/epic19/small-crac-with-max-7-elementary-actions-pst.json @@ -35,8 +35,8 @@ "nominalV" : [ 400.0 ], "thresholds" : [ { "unit" : "megawatt", - "min" : -400.0, - "max" : 400.0, + "min" : -500.0, + "max" : 500.0, "side" : "left" } ] } From 71e12d925ba3a27f5af712f7cd7e0455ef59ba25 Mon Sep 17 00:00:00 2001 From: wangjer Date: Wed, 18 Sep 2024 16:11:31 +0200 Subject: [PATCH 07/16] Add tests MinCostFiller Signed-off-by: wangjer --- .../algorithms/fillers/MinCostFiller.java | 6 +- .../linearproblem/LinearProblem.java | 4 +- .../algorithms/fillers/MinCostFillerTest.java | 194 ++++++++++++++++++ .../src/test/resources/crac/small-crac.json | 1 + 4 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFillerTest.java 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 index 17ad9a7b3e..1735e1af08 100644 --- 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 @@ -49,7 +49,7 @@ public void fill(LinearProblem linearProblem, FlowResult flowResult, Sensitivity // build constraints buildSecureCnecsHardConstraints(linearProblem, validFlowCnecs); buildRangeActionCostConstraints(linearProblem); - buildTotalCostConstraints(linearProblem); + buildTotalCostConstraint(linearProblem); // complete objective fillObjectiveWithActivationCost(linearProblem); @@ -142,10 +142,10 @@ private void buildSecureCnecsHardConstraints(LinearProblem linearProblem, Set rangeAction, return solver.getVariable(rangeActionCostVariableId(rangeAction, state)); } - public OpenRaoMPConstraint addActivationCostConstraint(double lb, double ub) { + public OpenRaoMPConstraint addTotalCostConstraint(double lb, double ub) { return solver.makeConstraint(lb, ub, totalCostConstraintId()); } - public OpenRaoMPConstraint getActivationCostConstraint() { + public OpenRaoMPConstraint getTotalCostConstraint() { return solver.getConstraint(totalCostConstraintId()); } 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..20d57aedfb --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/test/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFillerTest.java @@ -0,0 +1,194 @@ +/* + * 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.RangeActionActivationResultImpl; +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 MaxMinMarginFiller maxMinMarginFiller; + 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, + new RangeActionActivationResultImpl(initialRangeActionSetpointResult), + rangeActionParameters, + Unit.MEGAWATT, + false, RangeActionsOptimizationParameters.PstModel.CONTINUOUS); + } + + private void createMaxMinMarginFiller(Unit unit) { + maxMinMarginFiller = new MaxMinMarginFiller(Set.of(cnec1), unit); + } + + 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) + .build(); + linearProblem.fill(flowResult, sensitivityResult); + } + + @Test + void fillWithMinCostInMegawatt() { + 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 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(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 + assertTrue(linearProblem.minimization()); + + // 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/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" }, { From 989c983ee70ed3dbf0e5b1fa374a6579f69bb6f9 Mon Sep 17 00:00:00 2001 From: wangjer Date: Wed, 18 Sep 2024 16:45:19 +0200 Subject: [PATCH 08/16] Fix sonar issues Signed-off-by: wangjer --- .../algorithms/fillers/MinCostFiller.java | 11 +++----- .../algorithms/fillers/MinCostFillerTest.java | 26 ++++++++++++------- 2 files changed, 20 insertions(+), 17 deletions(-) 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 index 1735e1af08..674707d3ec 100644 --- 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 @@ -26,9 +26,9 @@ * @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; - private final double marginPenaltyCoefficient = 1000; public MinCostFiller(Set optimizedCnecs, Map>> rangeActions) { @@ -79,9 +79,7 @@ private void buildTotalCostVariable(LinearProblem linearProblem) { */ private void buildRangeActionCostVariable(LinearProblem linearProblem) { rangeActions.forEach((state, rangeActionSet) -> - rangeActionSet.forEach(rangeAction -> { - linearProblem.addRangeActionCostVariable(0, linearProblem.infinity(), rangeAction, state); - })); + rangeActionSet.forEach(rangeAction -> linearProblem.addRangeActionCostVariable(0, linearProblem.infinity(), rangeAction, state))); } /** @@ -121,7 +119,6 @@ private void buildSecureCnecsHardConstraints(LinearProblem linearProblem, Set maxFlow; minFlow = cnec.getLowerBound(side, MEGAWATT); maxFlow = cnec.getUpperBound(side, MEGAWATT); - // double unitConversionCoefficient = RaoUtil.getFlowUnitMultiplier(cnec, side, unit, MEGAWATT); if (minFlow.isPresent()) { OpenRaoMPConstraint minimumMarginNegative = linearProblem.addMinimumMarginConstraint(-linearProblem.infinity(), -minFlow.get(), cnec, side, LinearProblem.MarginExtension.BELOW_THRESHOLD); @@ -182,8 +179,8 @@ private void fillObjectiveWithActivationCost(LinearProblem linearProblem) { OpenRaoMPVariable totalCostVariable = linearProblem.getTotalCostVariable(); linearProblem.getObjective().setCoefficient(totalCostVariable, 1); OpenRaoMPVariable minimumMarginVariable = linearProblem.getMinimumMarginVariable(); - // marginPenaltyCoefficient is arbitrary for now - linearProblem.getObjective().setCoefficient(minimumMarginVariable, -marginPenaltyCoefficient); + // MARGIN_PENALTY_COEFFICIENT value is arbitrary for now + linearProblem.getObjective().setCoefficient(minimumMarginVariable, -MARGIN_PENALTY_COEFFICIENT); } 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 index 20d57aedfb..8d1cd0c18a 100644 --- 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 @@ -39,7 +39,6 @@ class MinCostFillerTest extends AbstractFillerTest { private static final double PST_ACTIVATION_COST = 1.5; private LinearProblem linearProblem; private CoreProblemFiller coreProblemFiller; - private MaxMinMarginFiller maxMinMarginFiller; private MinCostFiller minCostFiller; @BeforeEach @@ -71,10 +70,6 @@ public void setUp() throws IOException { false, RangeActionsOptimizationParameters.PstModel.CONTINUOUS); } - private void createMaxMinMarginFiller(Unit unit) { - maxMinMarginFiller = new MaxMinMarginFiller(Set.of(cnec1), unit); - } - private void createMinCostFiller() { Map>> rangeActions = new HashMap<>(); rangeActions.put(cnec1.getState(), Set.of(pstRangeAction)); @@ -91,7 +86,7 @@ private void buildLinearProblem() { } @Test - void fillWithMinCostInMegawatt() { + void fillWithMinCostMarginConstraint() { createMinCostFiller(); buildLinearProblem(); @@ -116,6 +111,20 @@ void fillWithMinCostInMegawatt() { 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); @@ -140,10 +149,7 @@ void fillWithMinCostInMegawatt() { assertEquals(0.0, totalCostConstraint.ub(), 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 - assertTrue(linearProblem.minimization()); + assertEquals(1, linearProblem.getObjective().getCoefficient(totalCostVariable), DOUBLE_TOLERANCE); // check the number of variables and constraints // total number of variables 6 : From b70d486cc9245cf381c54ad8855f7a71fc2cdaff Mon Sep 17 00:00:00 2001 From: wangjer Date: Mon, 23 Sep 2024 09:32:30 +0200 Subject: [PATCH 09/16] Add test build linear problem with min cost Signed-off-by: wangjer --- .../algorithms/LinearProblemBuilderTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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); + } } From b1b2e3042f3dc47ff457cd5f9b2c7a5581dd6b07 Mon Sep 17 00:00:00 2001 From: wangjer Date: Fri, 11 Oct 2024 16:52:38 +0200 Subject: [PATCH 10/16] MinCost for network actions Signed-off-by: wangjer --- .../castor/algorithm/AutomatonSimulator.java | 7 +- .../algorithm/CastorFullOptimization.java | 7 +- .../PrePerimeterSensitivityAnalysis.java | 8 +- .../searchtreerao/commons/RaoLogger.java | 3 +- .../ActivationCostEvaluator.java | 97 +++++++++++++++++++ .../CostEvaluator.java | 7 +- .../LoopFlowViolationCostEvaluator.java | 3 +- .../MinMarginEvaluator.java | 3 +- .../MnecViolationCostEvaluator.java | 3 +- .../ObjectiveFunction.java | 33 ++++--- .../ObjectiveFunctionResultImpl.java | 10 +- .../SensitivityFailureOvercostEvaluator.java | 3 +- .../algorithms/IteratingLinearOptimizer.java | 2 +- .../algorithms/fillers/MinCostFiller.java | 1 + .../api/RangeActionActivationResult.java | 4 + .../impl/AutomatonPerimeterResultImpl.java | 17 +++- .../impl/CurativeWithSecondPraoResult.java | 24 ++++- ...IteratingLinearOptimizationResultImpl.java | 10 ++ .../result/impl/OptimizationResultImpl.java | 10 ++ .../impl/RangeActionActivationResultImpl.java | 16 +++ .../impl/SkippedOptimizationResultImpl.java | 10 ++ .../searchtree/algorithms/Leaf.java | 26 ++++- .../LoopFlowViolationCostEvaluatorTest.java | 8 +- .../MinMarginEvaluatorTest.java | 10 +- .../MnecViolationCostEvaluatorTest.java | 10 +- .../ObjectiveFunctionTest.java | 38 ++++---- ...nsitivityFailureOvercostEvaluatorTest.java | 7 +- .../IteratingLinearOptimizerTest.java | 4 +- .../AutomatonPerimeterResultImplTest.java | 4 +- .../searchtree/algorithms/LeafTest.java | 6 +- .../searchtree/algorithms/SearchTreeTest.java | 2 +- 31 files changed, 315 insertions(+), 78 deletions(-) create mode 100644 ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ActivationCostEvaluator.java 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/CastorFullOptimization.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/castor/algorithm/CastorFullOptimization.java index 38f5e0eed2..8b40db937c 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 @@ -99,6 +99,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); @@ -143,6 +144,7 @@ public CompletableFuture run() { } RaoLogger.logSensitivityAnalysisResults("Systematic sensitivity analysis after preventive remedial actions: ", prePerimeterSensitivityAnalysis.getObjectiveFunction(), + new RangeActionActivationResultImpl(RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(raoInput.getNetwork(), raoInput.getCrac().getRangeActions())), preCurativeSensitivityAnalysisOutput, raoParameters, NUMBER_LOGGED_ELEMENTS_DURING_RAO); @@ -422,7 +424,9 @@ private OptimizationResult optimizeCurativePerimeter(Perimeter curativePerimeter Set loopFlowCnecs = AbstractOptimizationPerimeter.getLoopFlowCnecs(flowCnecs, raoParameters, network); ObjectiveFunction objectiveFunction = ObjectiveFunction.create().build(flowCnecs, loopFlowCnecs, initialSensitivityOutput, prePerimeterSensitivityOutput, stateTree.getOperatorsNotSharingCras(), raoParameters); - ObjectiveFunctionResult objectiveFunctionResult = objectiveFunction.evaluate(prePerimeterSensitivityOutput); + RangeActionActivationResult rangeActionActivationResult = new RangeActionActivationResultImpl(prePerimeterSensitivityOutput); + ObjectiveFunctionResult objectiveFunctionResult = objectiveFunction.evaluate(prePerimeterSensitivityOutput, rangeActionActivationResult); + boolean stopCriterionReached = isStopCriterionChecked(objectiveFunctionResult, curativeTreeParameters); if (stopCriterionReached) { NetworkActionsResult networkActionsResult = new NetworkActionsResultImpl(Collections.emptySet()); @@ -680,6 +684,7 @@ private SecondPreventiveRaoResult runSecondPreventiveRao(RaoInput raoInput, } RaoLogger.logSensitivityAnalysisResults("Systematic sensitivity analysis after curative remedial actions before second preventive optimization: ", prePerimeterSensitivityAnalysis.getObjectiveFunction(), + new RangeActionActivationResultImpl(RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(raoInput.getNetwork(), crac.getRangeActions())), sensiWithPostContingencyRemedialActions, parameters, 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 66494120ca..1eb1de2d67 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 @@ -43,6 +43,7 @@ private RaoLogger() { public static void logSensitivityAnalysisResults(String prefix, ObjectiveFunction objectiveFunction, + RangeActionActivationResult rangeActionActivationResult, PrePerimeterResult sensitivityAnalysisResult, RaoParameters raoParameters, int numberOfLoggedLimitingElements) { @@ -51,7 +52,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: {})", formatDouble(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..422e6da433 --- /dev/null +++ b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/ActivationCostEvaluator.java @@ -0,0 +1,97 @@ +/* + * 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 final double unsecurePenalty = 10000; + + 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 += unsecurePenalty; + } + 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..f339af0118 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<>())); } @@ -96,6 +96,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 +114,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 +149,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 index 674707d3ec..6554678e4a 100644 --- 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 @@ -174,6 +174,7 @@ private void buildRangeActionCostConstraints(LinearProblem linearProblem) { /** * 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(); 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 6c3d8adcb6..3510758c4c 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 @@ -151,7 +151,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); @@ -163,7 +163,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; } @@ -512,6 +512,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) { @@ -538,6 +549,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/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 e345eaa8dc..84e1dc064f 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 a8faae5811..a6d4cec6b5 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); } From 1b9acc836b934b80da5e998d656d92c81c1627bf Mon Sep 17 00:00:00 2001 From: wangjer Date: Thu, 17 Oct 2024 16:14:21 +0200 Subject: [PATCH 11/16] Min cost documentation Signed-off-by: wangjer --- docs/castor/linear-problem.md | 1 + docs/castor/linear-problem/min-cost-filler.md | 86 +++++++++++++++++++ docs/parameters.md | 4 + .../algorithms/fillers/MinCostFiller.java | 4 +- 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 docs/castor/linear-problem/min-cost-filler.md 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..0288a814d5 --- /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 arbitrary 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/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 index 6554678e4a..94024c1e30 100644 --- 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 @@ -47,7 +47,7 @@ public void fill(LinearProblem linearProblem, FlowResult flowResult, Sensitivity buildMinimumMarginVariable(linearProblem, validFlowCnecs); // build constraints - buildSecureCnecsHardConstraints(linearProblem, validFlowCnecs); + buildSecureCnecsConstraints(linearProblem, validFlowCnecs); buildRangeActionCostConstraints(linearProblem); buildTotalCostConstraint(linearProblem); @@ -109,7 +109,7 @@ private void buildMinimumMarginVariable(LinearProblem linearProblem, Set validFlowCnecs) { + private void buildSecureCnecsConstraints(LinearProblem linearProblem, Set validFlowCnecs) { OpenRaoMPVariable minimumMarginVariable = linearProblem.getMinimumMarginVariable(); validFlowCnecs.forEach(cnec -> cnec.getMonitoredSides().forEach(side -> { From 2f13d9f419908d715b63dfe0de1650f8c30366d5 Mon Sep 17 00:00:00 2001 From: wangjer Date: Wed, 23 Oct 2024 11:27:07 +0200 Subject: [PATCH 12/16] bug fix + simple cucumber test Signed-off-by: wangjer --- docs/castor/linear-problem/min-cost-filler.md | 2 +- .../ActivationCostEvaluator.java | 4 +- .../cost_objective_function.feature | 29 ++++ .../files/cases/common/12NodesProdFR.uct | 46 +++++ .../files/cases/common/12NodesProdFR_3PST.uct | 46 +++++ .../RaoParameters_minCost_megawatt_ac.json | 81 +++++++++ .../crac/extra_features/crac-cost-0.json | 106 ++++++++++++ .../crac/extra_features/crac-cost-2pst.json | 162 ++++++++++++++++++ 8 files changed, 473 insertions(+), 3 deletions(-) create mode 100644 tests/src/test/resources/com/powsybl/openrao/tests/features/extra_features/cost_objective_function.feature create mode 100644 tests/src/test/resources/files/cases/common/12NodesProdFR.uct create mode 100644 tests/src/test/resources/files/cases/common/12NodesProdFR_3PST.uct create mode 100644 tests/src/test/resources/files/configurations/common/RaoParameters_minCost_megawatt_ac.json create mode 100644 tests/src/test/resources/files/crac/extra_features/crac-cost-0.json create mode 100644 tests/src/test/resources/files/crac/extra_features/crac-cost-2pst.json diff --git a/docs/castor/linear-problem/min-cost-filler.md b/docs/castor/linear-problem/min-cost-filler.md index 0288a814d5..07fc512bd6 100644 --- a/docs/castor/linear-problem/min-cost-filler.md +++ b/docs/castor/linear-problem/min-cost-filler.md @@ -83,4 +83,4 @@ $$ \end{equation} $$ -The penalty coefficient was arbitrary 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 +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/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 index 422e6da433..dd4953f031 100644 --- 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 @@ -24,7 +24,7 @@ public class ActivationCostEvaluator implements CostEvaluator { private final Set flowCnecs; private final Unit unit; private final MarginEvaluator marginEvaluator; - private final double unsecurePenalty = 10000; + private static final double MARGIN_PENALTY_COEFFICIENT = 1000; public ActivationCostEvaluator(Set flowCnecs, Unit unit, MarginEvaluator marginEvaluator) { this.flowCnecs = flowCnecs; @@ -77,7 +77,7 @@ public Pair> computeCostAndLimitingElements(FlowResult fl double margin = marginEvaluator.getMargin(flowResult, limitingElement, unit); if (margin < 0) { - activationCost += unsecurePenalty; + activationCost -= MARGIN_PENALTY_COEFFICIENT * margin; } return Pair.of(activationCost, costlyElements); } 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..b52c3a36b9 --- /dev/null +++ b/tests/src/test/resources/com/powsybl/openrao/tests/features/extra_features/cost_objective_function.feature @@ -0,0 +1,29 @@ +# 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 - TS0" is used in preventive + And the margin on cnec "BBE2AA1 FFR3AA1 1 - preventive - TS0" after PRA should be 0 A + And the tap of PstRangeAction "pst_be - TS0" should be 6 in preventive + + @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 - TS0" is used in preventive + And the margin on cnec "BBE2AA1 FFR3AA1 1 - preventive - TS0" after PRA should be 70 A + And the tap of PstRangeAction "pst_be - TS0" 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..c5f0bac703 --- /dev/null +++ b/tests/src/test/resources/files/cases/common/12NodesProdFR_3PST.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/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..8c4931d6a9 --- /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 - 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" : -500.0, + "max" : 500.0, + "side" : "left" + } ] + } + ], + "pstRangeActions": [ + { + "id": "pst_be - TS0", + "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": [], + "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 From 2f9d05a4ccabaa9d149d09a1bd5e9d6d5ea093e7 Mon Sep 17 00:00:00 2001 From: wangjer Date: Wed, 23 Oct 2024 16:58:17 +0200 Subject: [PATCH 13/16] Add cucumber test with network action Signed-off-by: wangjer --- .../ActivationCostEvaluator.java | 10 +- .../cost_objective_function.feature | 34 ++++- .../files/cases/common/12NodesProdFR_3PST.uct | 4 - .../crac/extra_features/crac-cost-0.json | 4 +- .../crac-cost-with-network-action-0.json | 137 ++++++++++++++++++ 5 files changed, 171 insertions(+), 18 deletions(-) create mode 100644 tests/src/test/resources/files/crac/extra_features/crac-cost-with-network-action-0.json 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 index dd4953f031..3c95736e5d 100644 --- 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 @@ -85,12 +85,10 @@ public Pair> computeCostAndLimitingElements(FlowResult fl 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); - }); - }); + 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/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 index b52c3a36b9..29dc5aa2b9 100644 --- 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 @@ -13,9 +13,9 @@ Feature: New objective function using minimal cost 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 - TS0" is used in preventive - And the margin on cnec "BBE2AA1 FFR3AA1 1 - preventive - TS0" after PRA should be 0 A - And the tap of PstRangeAction "pst_be - TS0" should be 6 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 @fast @rao @mock @ac @preventive-only Scenario: Preventive RA with max min margin @@ -24,6 +24,28 @@ Feature: New objective function using minimal cost 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 - TS0" is used in preventive - And the margin on cnec "BBE2AA1 FFR3AA1 1 - preventive - TS0" after PRA should be 70 A - And the tap of PstRangeAction "pst_be - TS0" should be 16 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_3PST.uct b/tests/src/test/resources/files/cases/common/12NodesProdFR_3PST.uct index c5f0bac703..eb1b9c5cf1 100644 --- a/tests/src/test/resources/files/cases/common/12NodesProdFR_3PST.uct +++ b/tests/src/test/resources/files/cases/common/12NodesProdFR_3PST.uct @@ -31,11 +31,7 @@ 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 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 index 8c4931d6a9..f8da19e2c7 100644 --- 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 @@ -22,7 +22,7 @@ "contingencies": [], "flowCnecs": [ { - "id": "BBE2AA1 FFR3AA1 1 - preventive - TS0", + "id": "BBE2AA1 FFR3AA1 1 - preventive", "name": "BBE2AA1 FFR3AA1 1 - preventive", "networkElementId": "BBE2AA1 FFR3AA1 1", "operator": "BE", @@ -43,7 +43,7 @@ ], "pstRangeActions": [ { - "id": "pst_be - TS0", + "id": "pst_be", "name": "pst_be", "operator": "BE", "onInstantUsageRules": [ 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 From 8c43b3d227773b9c407ee1d49e4d4637abcc86c5 Mon Sep 17 00:00:00 2001 From: wangjer Date: Thu, 24 Oct 2024 11:36:04 +0200 Subject: [PATCH 14/16] Bug fixes after merge Signed-off-by: wangjer --- .../algorithm/CastorContingencyScenarios.java | 14 ++++++-------- .../castor/algorithm/CastorFullOptimization.java | 2 +- .../castor/algorithm/CastorSecondPreventive.java | 1 + .../algorithms/fillers/MinCostFiller.java | 7 +------ .../algorithms/fillers/MinCostFillerTest.java | 3 +-- 5 files changed, 10 insertions(+), 17 deletions(-) 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 3bc7315f35..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 @@ -131,7 +131,7 @@ public CompletableFuture run() { } RaoLogger.logSensitivityAnalysisResults("Systematic sensitivity analysis after preventive remedial actions: ", prePerimeterSensitivityAnalysis.getObjectiveFunction(), - new RangeActionActivationResultImpl(RangeActionSetpointResultImpl.buildWithSetpointsFromNetwork(raoInput.getNetwork(), raoInput.getCrac().getRangeActions())), + 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/linearoptimisation/algorithms/fillers/MinCostFiller.java b/ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/linearoptimisation/algorithms/fillers/MinCostFiller.java index 94024c1e30..82d2ee8196 100644 --- 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 @@ -38,7 +38,7 @@ public MinCostFiller(Set optimizedCnecs, } @Override - public void fill(LinearProblem linearProblem, FlowResult flowResult, SensitivityResult sensitivityResult) { + public void fill(LinearProblem linearProblem, FlowResult flowResult, SensitivityResult sensitivityResult, RangeActionActivationResult rangeActionActivationResult) { Set validFlowCnecs = FillersUtil.getFlowCnecsComputationStatusOk(optimizedCnecs, sensitivityResult); // build variables @@ -55,11 +55,6 @@ public void fill(LinearProblem linearProblem, FlowResult flowResult, Sensitivity fillObjectiveWithActivationCost(linearProblem); } - @Override - public void updateBetweenSensiIteration(LinearProblem linearProblem, FlowResult flowResult, SensitivityResult sensitivityResult, RangeActionActivationResult rangeActionActivationResult) { - // Objective does not change, nothing to do - } - @Override public void updateBetweenMipIteration(LinearProblem linearProblem, RangeActionActivationResult rangeActionActivationResult) { // Objective does not change, nothing to do 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 index 8d1cd0c18a..c5502c02c5 100644 --- 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 @@ -19,7 +19,6 @@ 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.RangeActionActivationResultImpl; import com.powsybl.openrao.searchtreerao.result.impl.RangeActionSetpointResultImpl; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -64,7 +63,6 @@ public void setUp() throws IOException { coreProblemFiller = new CoreProblemFiller( optimizationPerimeter, initialRangeActionSetpointResult, - new RangeActionActivationResultImpl(initialRangeActionSetpointResult), rangeActionParameters, Unit.MEGAWATT, false, RangeActionsOptimizationParameters.PstModel.CONTINUOUS); @@ -81,6 +79,7 @@ private void buildLinearProblem() { .withProblemFiller(coreProblemFiller) .withProblemFiller(minCostFiller) .withSolver(RangeActionsOptimizationParameters.Solver.SCIP) + .withInitialRangeActionActivationResult(getInitialRangeActionActivationResult()) .build(); linearProblem.fill(flowResult, sensitivityResult); } From 2ca135e3b73b5d5282c6aa75cc3bb7c43b9a55e6 Mon Sep 17 00:00:00 2001 From: wangjer Date: Fri, 25 Oct 2024 10:44:26 +0200 Subject: [PATCH 15/16] Add simple cucumber step Signed-off-by: wangjer --- .../openrao/tests/steps/SearchTreeRaoSteps.java | 14 ++++++++++---- .../extra_features/cost_objective_function.feature | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) 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 index 29dc5aa2b9..0cbd8ad11d 100644 --- 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 @@ -16,6 +16,7 @@ Feature: New objective function using minimal cost 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 2.6 @fast @rao @mock @ac @preventive-only Scenario: Preventive RA with max min margin From 5a41f922fda31f14a6d5a8463bf15c1030e638be Mon Sep 17 00:00:00 2001 From: wangjer Date: Fri, 25 Oct 2024 15:35:53 +0200 Subject: [PATCH 16/16] Bug fix for first evaluation of objective function Signed-off-by: wangjer --- .../objectivefunctionevaluator/ObjectiveFunction.java | 7 +++++-- .../extra_features/cost_objective_function.feature | 4 +++- .../resources/files/crac/extra_features/crac-cost-0.json | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) 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 f339af0118..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 @@ -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) { 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 index 0cbd8ad11d..9ee8e56458 100644 --- 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 @@ -16,7 +16,9 @@ Feature: New objective function using minimal cost 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 2.6 + 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 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 index f8da19e2c7..e79c534600 100644 --- 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 @@ -96,7 +96,7 @@ "rangeType": "absolute" } ], - "cost" : 1.1 + "cost" : 100 } ], "hvdcRangeActions": [],