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 f44d41a4a7..ef76b82775 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 @@ -10,6 +10,7 @@ import com.powsybl.openrao.commons.RandomizedString; import com.powsybl.openrao.data.cracapi.*; import com.powsybl.openrao.data.cracapi.cnec.FlowCnec; +import com.powsybl.openrao.data.cracapi.networkaction.NetworkAction; import com.powsybl.openrao.data.cracapi.rangeaction.PstRangeAction; import com.powsybl.openrao.data.cracapi.rangeaction.RangeAction; import com.powsybl.openrao.data.cracapi.rangeaction.StandardRangeAction; @@ -742,9 +743,9 @@ static void applyPreventiveResultsForAutoOrCurativeRangeActions(Network network, * For the same reason, we are going to check preventive RAs that share the same network elements as auto or curative RAs. */ static Set> getRangeActionsExcludedFromSecondPreventive(Crac crac, PerimeterResult firstPreventiveResult, Map contingencyResults) { - Set> multipleInstantRangeActions = crac.getRangeActions().stream().filter(ra -> - isRangeActionPreventive(ra, crac) - && isRangeActionAutoOrCurative(ra, crac)).collect(Collectors.toSet()); + Set> multipleInstantRangeActions = crac.getRangeActions().stream() + .filter(ra -> isRangeActionPreventive(ra, crac) && isRangeActionAutoOrCurative(ra, crac)) + .collect(Collectors.toSet()); // If first preventive diverged, we want to remove every range action that is both preventive and auto or curative. if (firstPreventiveResult instanceof SkippedOptimizationResultImpl) { @@ -753,13 +754,14 @@ static Set> getRangeActionsExcludedFromSecondPreventive(Crac crac // Removes range actions that have a range limit relative to the previous instant. Set> rangeActionsToRemove = multipleInstantRangeActions.stream() - .filter(ra -> { - if (ra instanceof PstRangeAction pstRangeAction) { - return pstRangeAction.getRanges().stream().anyMatch(tapRange -> tapRange.getRangeType().equals(RELATIVE_TO_PREVIOUS_INSTANT)); - } - return ((StandardRangeAction) ra).getRanges().stream().anyMatch(standardRange -> standardRange.getRangeType().equals(RELATIVE_TO_PREVIOUS_INSTANT)); - }) - .collect(Collectors.toSet()); + .filter(ra -> { + if (ra instanceof PstRangeAction pstRangeAction) { + return pstRangeAction.getRanges().stream().anyMatch(tapRange -> tapRange.getRangeType().equals(RELATIVE_TO_PREVIOUS_INSTANT)); + } + return ((StandardRangeAction) ra).getRanges().stream().anyMatch(standardRange -> standardRange.getRangeType().equals(RELATIVE_TO_PREVIOUS_INSTANT)); + }) + .collect(Collectors.toSet()); + rangeActionsToRemove.forEach(multipleInstantRangeActions::remove); // Removes RAs that put crac RaUsageLimits at risk. // First, we filter out state that diverged because we know no set-point was chosen for this state. @@ -769,11 +771,10 @@ static Set> getRangeActionsExcludedFromSecondPreventive(Crac crac // Then, we build a map that gives for each RA, its tap at each state it's available at. Set> rangeActionsNotPreventive = crac.getRangeActions().stream().filter(ra -> isRangeActionAutoOrCurative(ra, crac)).collect(Collectors.toSet()); State preventiveState = crac.getPreventiveState(); - rangeActionsToRemove.forEach(multipleInstantRangeActions::remove); - Map, Map>> setPointResults = buildSetPointResultsMap(crac, firstPreventiveResult, newContingencyResults, multipleInstantRangeActions, rangeActionsNotPreventive, preventiveState); + Map, Map> setPointResults = buildSetPointResultsMap(crac, firstPreventiveResult, newContingencyResults, multipleInstantRangeActions, rangeActionsNotPreventive, preventiveState); // Finally, we filter out RAs that put crac RaUsageLimits at risk. - rangeActionsToRemove.addAll(getRangeActionsToRemove(crac, preventiveState, setPointResults)); + rangeActionsToRemove.addAll(getRangeActionsToRemove(crac, preventiveState, setPointResults, newContingencyResults)); return rangeActionsToRemove; } @@ -781,68 +782,80 @@ static Set> getRangeActionsExcludedFromSecondPreventive(Crac crac * Creates a map that gives for a given RA, its tap for each state it's available at. * The only subtlety being that RAs sharing exactly the same network elements are considered to be only one RA. */ - private static Map, Map>> buildSetPointResultsMap(Crac crac, PerimeterResult firstPreventiveResult, Map contingencyResults, Set> multipleInstantRangeActions, Set> rangeActionsNotPreventive, State preventiveState) { + private static Map, Map> buildSetPointResultsMap(Crac crac, PerimeterResult firstPreventiveResult, Map contingencyResults, Set> multipleInstantRangeActions, Set> rangeActionsNotPreventive, State preventiveState) { Map, Set>> correspondanceMap = new HashMap<>(); crac.getRangeActions().stream().filter(ra -> isRangeActionPreventive(ra, crac) && !isRangeActionAutoOrCurative(ra, crac)).forEach(pra -> { Set praNetworkElements = pra.getNetworkElements(); rangeActionsNotPreventive.forEach(cra -> { if (cra.getNetworkElements().equals(praNetworkElements)) { - correspondanceMap.putIfAbsent(pra, new HashSet<>(Set.of(cra))); + correspondanceMap.putIfAbsent(pra, new HashSet<>()); correspondanceMap.get(pra).add(cra); } }); }); - Map, Map>> setPointResults = new HashMap<>(); + Map, Map> setPointResults = new HashMap<>(); correspondanceMap.forEach((pra, associatedCras) -> { - setPointResults.put(pra, new HashMap<>(Map.of(preventiveState, Set.of(firstPreventiveResult.getOptimizedSetpoint(pra, preventiveState))))); + setPointResults.put(pra, new HashMap<>(Map.of(preventiveState, firstPreventiveResult.getOptimizedSetpoint(pra, preventiveState)))); associatedCras.forEach(cra -> contingencyResults.forEach((state, result) -> { if (isRangeActionAvailableInState(cra, state, crac)) { - Map> praResults = setPointResults.get(pra); - double craSetPoint = result.getOptimizedSetpoint(cra, state); - praResults.putIfAbsent(state, new HashSet<>(Set.of(craSetPoint))); - praResults.get(state).add(craSetPoint); + setPointResults.get(pra).putIfAbsent(state, result.getOptimizedSetpoint(cra, state)); } })); }); multipleInstantRangeActions.forEach(ra -> { - setPointResults.put(ra, new HashMap<>(Map.of(preventiveState, Set.of(firstPreventiveResult.getOptimizedSetpoint(ra, preventiveState))))); + setPointResults.put(ra, new HashMap<>(Map.of(preventiveState, firstPreventiveResult.getOptimizedSetpoint(ra, preventiveState)))); contingencyResults.forEach((state, result) -> { if (isRangeActionAvailableInState(ra, state, crac)) { - setPointResults.get(ra).put(state, Set.of(result.getOptimizedSetpoint(ra, state))); + setPointResults.get(ra).put(state, result.getOptimizedSetpoint(ra, state)); } }); }); return setPointResults; } + /** + * Checks if raUsageLimits are at risk if we choose to re-optimize a range action. + * Returns True if it's at risk, False otherwise. + */ + private static boolean shouldRemoveRaDueToUsageLimits(Crac crac, State state, RangeAction rangeAction, Set activatedNetworkActions) { + String operator = rangeAction.getOperator(); + RaUsageLimits raUsageLimits = crac.getRaUsageLimits(state.getInstant()); + Set> potentiallyActivatableRas = new HashSet<>(crac.getPotentiallyAvailableRangeActions(state)); + potentiallyActivatableRas.addAll(activatedNetworkActions); + long potentiallyActivatableTsos = Integer.MAX_VALUE; + long potentiallyActivatableRasForTheTso = Integer.MAX_VALUE; + if (operator != null) { + potentiallyActivatableRasForTheTso = potentiallyActivatableRas.stream() + .filter(ra -> operator.equals(ra.getOperator())) + .count(); + potentiallyActivatableTsos = potentiallyActivatableRas.stream() + .map(RemedialAction::getOperator) + .filter(Objects::nonNull) + .distinct() + .count(); + } + int limitingValueForTheTso = Math.min(raUsageLimits.getMaxPstPerTso().getOrDefault(operator, Integer.MAX_VALUE), raUsageLimits.getMaxRaPerTso().getOrDefault(operator, Integer.MAX_VALUE)); + return raUsageLimits.getMaxRa() < potentiallyActivatableRas.size() + || limitingValueForTheTso < potentiallyActivatableRasForTheTso + || raUsageLimits.getMaxTso() < potentiallyActivatableTsos; + } + /** * Gathers every range action that should not be considered in the second preventive if those 2 criterion are met : * 1- The range action has the same tap in preventive and in a contingency scenario. * 2- For the given state, the crac has limiting RaUsageLimits. */ - private static Set> getRangeActionsToRemove(Crac crac, State preventiveState, Map, Map>> setPointResults) { + private static Set> getRangeActionsToRemove(Crac crac, State preventiveState, Map, Map> setPointResults, Map contingencyResults) { Set> rangeActionsToRemove = new HashSet<>(); setPointResults.forEach((ra, spMap) -> { - double referenceSetPoint = spMap.get(preventiveState).iterator().next(); - for (Map.Entry> entry : spMap.entrySet()) { + double referenceSetPoint = spMap.get(preventiveState); + for (Map.Entry entry : spMap.entrySet()) { State state = entry.getKey(); - if (!state.isPreventive() && entry.getValue().contains(referenceSetPoint)) { - Instant instant = state.getInstant(); - if (crac.getRaUsageLimitsPerInstant().containsKey(instant)) { - String operator = ra.getOperator(); - RaUsageLimits raUsageLimits = crac.getRaUsageLimits(instant); - Set> potentiallyAvailableRas = crac.getPotentiallyAvailableRangeActions(state); - long potentiallyAvailableRasForTheOperator = operator == null ? Integer.MAX_VALUE : potentiallyAvailableRas.stream().filter(rangeAction -> { - String otherOperator = rangeAction.getOperator(); - return otherOperator != null && otherOperator.equals(operator); - }).count(); - int limitingValueForTheTso = Math.min(raUsageLimits.getMaxPstPerTso().getOrDefault(operator, Integer.MAX_VALUE), raUsageLimits.getMaxRaPerTso().getOrDefault(operator, Integer.MAX_VALUE)); - if (raUsageLimits.getMaxRa() < potentiallyAvailableRas.size() || - limitingValueForTheTso < potentiallyAvailableRasForTheOperator) { - rangeActionsToRemove.add(ra); - break; - } - } + if (!state.isPreventive() + && entry.getValue().equals(referenceSetPoint) + && crac.getRaUsageLimitsPerInstant().containsKey(state.getInstant()) + && shouldRemoveRaDueToUsageLimits(crac, state, ra, contingencyResults.get(state).getActivatedNetworkActions())) { + rangeActionsToRemove.add(ra); } } }); diff --git a/tests/src/test/resources/features/epic20_advanced_search_tree/US20_1.feature b/tests/src/test/resources/features/epic20_advanced_search_tree/US20_1.feature index 53b73952e5..8e0faccd41 100644 --- a/tests/src/test/resources/features/epic20_advanced_search_tree/US20_1.feature +++ b/tests/src/test/resources/features/epic20_advanced_search_tree/US20_1.feature @@ -110,6 +110,22 @@ Feature: US 20.1: enable second optimization of the preventive perimeter And the tap of PstRangeAction "pst_be" should be 0 in preventive Then the worst margin is 295.6 A + @fast @rao @mock @ac @second-preventive + Scenario: US 20.1.1.8: Same case as US 20.1.1.3 with curative maxTso limits. + # We should have the same results as 20.1.1.2 + Given network file is "common/TestCase16Nodes.uct" + Given crac file is "epic20/second_preventive_ls_1_8.json" + Given configuration file is "epic20/RaoParameters_maxMargin_ampere_second_preventive.json" + When I launch search_tree_rao + # We can not re-optimize pst_fr for 2 combined reasons: + # 1- It has the same taps in preventive and in curative. + # 2- There are maxTso usage limits for curative instant. + Then 2 remedial actions are used in preventive + And the remedial action "open_fr1_fr3" is used in preventive + And the tap of PstRangeAction "pst_fr" should be -5 in preventive + And the tap of PstRangeAction "pst_be" should be 0 in preventive + Then the worst margin is 295.6 A + @fast @rao @mock @ac @second-preventive Scenario: US 20.1.2: Preventive and curative network actions 1/3 Given network file is "common/TestCase16Nodes.uct" diff --git a/tests/src/test/resources/files/crac/epic20/second_preventive_ls_1_8.json b/tests/src/test/resources/files/crac/epic20/second_preventive_ls_1_8.json new file mode 100644 index 0000000000..5b84d98a6b --- /dev/null +++ b/tests/src/test/resources/files/crac/epic20/second_preventive_ls_1_8.json @@ -0,0 +1,466 @@ +{ + "type" : "CRAC", + "version" : "2.1", + "info" : "Generated by Open RAO http://farao-community.github.io", + "id" : "second_curative_ls_1", + "name" : "second_curative_ls_1", + "instants" : [ { + "id" : "preventive", + "kind" : "PREVENTIVE" + }, { + "id" : "outage", + "kind" : "OUTAGE" + }, { + "id" : "auto", + "kind" : "AUTO" + }, { + "id" : "curative", + "kind" : "CURATIVE" + } ], + "ra-usage-limits-per-instant" : [ { + "instant": "preventive", + "max-ra" : 2 + }, { + "instant": "curative", + "max-tso" : 0 + } ], + "networkElementsNamePerId" : { }, + "contingencies" : [ { + "id" : "co1_fr2_fr3_1", + "networkElementsIds" : [ "FFR2AA1 FFR3AA1 1" ] + } ], + "flowCnecs" : [ { + "id" : "BBE1AA1 FFR5AA1 1 - co1_fr2_fr3_1 - curative", + "name" : "be1_fr5_n", + "networkElementId" : "BBE1AA1 FFR5AA1 1", + "operator" : null, + "instant" : "curative", + "contingencyId" : "co1_fr2_fr3_1", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1500.0, + "max" : 1500.0, + "side" : "right" + } ] + }, { + "id" : "BBE1AA1 FFR5AA1 1 - preventive", + "name" : "be1_fr5_n", + "networkElementId" : "BBE1AA1 FFR5AA1 1", + "operator" : null, + "instant" : "preventive", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1500.0, + "max" : 1500.0, + "side" : "right" + } ] + }, { + "id" : "BBE4AA1 FFR5AA1 1 - co1_fr2_fr3_1 - curative", + "name" : "be4_fr5_n", + "networkElementId" : "BBE4AA1 FFR5AA1 1", + "operator" : null, + "instant" : "curative", + "contingencyId" : "co1_fr2_fr3_1", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1000.0, + "max" : 1000.0, + "side" : "right" + } ] + }, { + "id" : "BBE4AA1 FFR5AA1 1 - preventive", + "name" : "be4_fr5_n", + "networkElementId" : "BBE4AA1 FFR5AA1 1", + "operator" : null, + "instant" : "preventive", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1000.0, + "max" : 1000.0, + "side" : "right" + } ] + }, { + "id" : "DDE2AA1 NNL3AA1 1 - preventive", + "name" : "de2_nl3_n", + "networkElementId" : "DDE2AA1 NNL3AA1 1", + "operator" : null, + "instant" : "preventive", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -5000.0, + "max" : 5000.0, + "side" : "right" + } ] + }, { + "id" : "FFR1AA1 FFR3AA1 1 - co1_fr2_fr3_1 - curative", + "name" : "fr1_fr3_co1", + "networkElementId" : "FFR1AA1 FFR3AA1 1", + "operator" : null, + "instant" : "curative", + "contingencyId" : "co1_fr2_fr3_1", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1500.0, + "max" : 1500.0, + "side" : "right" + } ] + }, { + "id" : "FFR1AA1 FFR4AA1 1 - co1_fr2_fr3_1 - curative", + "name" : "fr1_fr4_co1", + "networkElementId" : "FFR1AA1 FFR4AA1 1", + "operator" : null, + "instant" : "curative", + "contingencyId" : "co1_fr2_fr3_1", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1200.0, + "max" : 1200.0, + "side" : "right" + } ] + }, { + "id" : "FFR2AA1 DDE3AA1 1 - co1_fr2_fr3_1 - curative", + "name" : "fr2_de3_n", + "networkElementId" : "FFR2AA1 DDE3AA1 1", + "operator" : null, + "instant" : "curative", + "contingencyId" : "co1_fr2_fr3_1", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1500.0, + "max" : 1500.0, + "side" : "right" + } ] + }, { + "id" : "FFR2AA1 DDE3AA1 1 - preventive", + "name" : "fr2_de3_n", + "networkElementId" : "FFR2AA1 DDE3AA1 1", + "operator" : null, + "instant" : "preventive", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1500.0, + "max" : 1500.0, + "side" : "right" + } ] + }, { + "id" : "FFR3AA1 FFR5AA1 1 - co1_fr2_fr3_1 - curative", + "name" : "fr3_fr5_co1", + "networkElementId" : "FFR3AA1 FFR5AA1 1", + "operator" : null, + "instant" : "curative", + "contingencyId" : "co1_fr2_fr3_1", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1000.0, + "max" : 1000.0, + "side" : "right" + } ] + }, { + "id" : "FFR4AA1 DDE1AA1 1 - co1_fr2_fr3_1 - curative", + "name" : "fr4_de1_n", + "networkElementId" : "FFR4AA1 DDE1AA1 1", + "operator" : null, + "instant" : "curative", + "contingencyId" : "co1_fr2_fr3_1", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1500.0, + "max" : 1500.0, + "side" : "right" + } ] + }, { + "id" : "FFR4AA1 DDE1AA1 1 - preventive", + "name" : "fr4_de1_n", + "networkElementId" : "FFR4AA1 DDE1AA1 1", + "operator" : null, + "instant" : "preventive", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1500.0, + "max" : 1500.0, + "side" : "right" + } ] + }, { + "id" : "FFR4AA1 DDE4AA1 1 - co1_fr2_fr3_1 - curative", + "name" : "fr4_de4_n", + "networkElementId" : "FFR4AA1 DDE4AA1 1", + "operator" : null, + "instant" : "curative", + "contingencyId" : "co1_fr2_fr3_1", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1000.0, + "max" : 1000.0, + "side" : "right" + } ] + }, { + "id" : "FFR4AA1 DDE4AA1 1 - preventive", + "name" : "fr4_de4_n", + "networkElementId" : "FFR4AA1 DDE4AA1 1", + "operator" : null, + "instant" : "preventive", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -1000.0, + "max" : 1000.0, + "side" : "right" + } ] + }, { + "id" : "NNL2AA1 BBE3AA1 1 - preventive", + "name" : "nl2_be3_n", + "networkElementId" : "NNL2AA1 BBE3AA1 1", + "operator" : null, + "instant" : "preventive", + "optimized" : true, + "monitored" : false, + "reliabilityMargin" : 0.0, + "iMax" : [ 2000.0 ], + "nominalV" : [ 400.0 ], + "thresholds" : [ { + "unit" : "ampere", + "min" : -5000.0, + "max" : 5000.0, + "side" : "right" + } ] + } ], + "angleCnecs" : [ ], + "voltageCnecs" : [ ], + "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" + } ] + }, { + "id" : "pst_fr", + "name" : "pst_fr", + "operator" : "fr", + "onInstantUsageRules" : [ { + "instant" : "preventive", + "usageMethod" : "available" + }, { + "instant" : "curative", + "usageMethod" : "available" + } ], + "networkElementId" : "FFR2AA1 FFR4AA1 1", + "initialTap" : 5, + "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" : -10, + "max" : 10, + "rangeType" : "relativeToInitialNetwork" + } ] + } ], + "hvdcRangeActions" : [ ], + "injectionRangeActions" : [ ], + "counterTradeRangeActions" : [ ], + "networkActions" : [ { + "id" : "close_de3_de4", + "name" : "close_de3_de4", + "operator" : "de", + "onInstantUsageRules" : [ { + "instant" : "curative", + "usageMethod" : "available" + } ], + "topologicalActions" : [ { + "networkElementId" : "DDE3AA1 DDE4AA1 1", + "actionType" : "close" + } ] + }, { + "id" : "close_fr1_fr5", + "name" : "close_fr1_fr5", + "operator" : "fr", + "onInstantUsageRules" : [ { + "instant" : "curative", + "usageMethod" : "available" + } ], + "topologicalActions" : [ { + "networkElementId" : "FFR1AA1 FFR5AA1 1", + "actionType" : "close" + } ] + }, { + "id" : "open_be1_be4", + "name" : "open_be1_be4", + "operator" : "be", + "onInstantUsageRules" : [ { + "instant" : "curative", + "usageMethod" : "available" + } ], + "topologicalActions" : [ { + "networkElementId" : "BBE1AA1 BBE4AA1 1", + "actionType" : "open" + } ] + }, { + "id" : "open_fr1_fr2", + "name" : "open_fr1_fr2", + "operator" : "fr", + "onInstantUsageRules" : [ { + "instant" : "curative", + "usageMethod" : "available" + } ], + "topologicalActions" : [ { + "networkElementId" : "FFR1AA1 FFR2AA1 1", + "actionType" : "open" + } ] + }, { + "id" : "open_fr1_fr3", + "name" : "open_fr1_fr3", + "operator" : "fr", + "onInstantUsageRules" : [ { + "instant" : "preventive", + "usageMethod" : "available" + } ], + "topologicalActions" : [ { + "networkElementId" : "FFR1AA1 FFR3AA1 1", + "actionType" : "open" + } ] + } ] +} \ No newline at end of file