From 162fac8c0ba98dc6c5502f3360f999a05832ba2d Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 4 Aug 2023 11:33:14 +0200 Subject: [PATCH 01/18] Implementation of ProportionalScalable on loads and on generators Signed-off-by: Nicolas Rol --- .../scalable/ProportionalScalable.java | 92 ++++++++++++++++++- .../scalable/VariationParameters.java | 33 +++++++ 2 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java index a485fc25ad7..b385901f2fb 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java @@ -6,12 +6,12 @@ */ package com.powsybl.iidm.modification.scalable; +import com.powsybl.iidm.network.Generator; +import com.powsybl.iidm.network.Load; import com.powsybl.iidm.network.Network; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; /** @@ -61,6 +61,11 @@ void setIterationPercentage(double iterationPercentage) { private final List scalablePercentageList; + private ProportionalScalable(){ + // Initialisation if the list + this.scalablePercentageList = new ArrayList<>(); + } + ProportionalScalable(List percentages, List scalables) { checkPercentages(percentages, scalables); this.scalablePercentageList = new ArrayList<>(); @@ -69,8 +74,85 @@ void setIterationPercentage(double iterationPercentage) { } } + public ProportionalScalable onLoads(VariationParameters variationParameters, Collection loads) { + // Initialisation of the ProportionalScalable + ProportionalScalable proportionalScalable = new ProportionalScalable(); + + // The variation mode chosen changes how the percentages are computed + switch (variationParameters.getVariationMode()) { + case PROPORTIONAL_TO_P0 -> { + // Proportional to the P0 of the loads + AtomicReference sumP0 = new AtomicReference<>(0D); + loads.forEach(load -> + sumP0.set(sumP0.get() + load.getP0()) + ); + loads.forEach(load -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (load.getP0() * 100.0 / sumP0.get())))); + } + case REGULAR_DISTRIBUTION -> + // Each load get the same + loads.forEach(load -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (100.0 / loads.size())))); + default -> + throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", variationParameters.getVariationMode())); + } + return proportionalScalable; + } + + public ProportionalScalable onGenerators(VariationParameters variationParameters, Collection generators) { + // Initialisation of the ProportionalScalable + ProportionalScalable proportionalScalable = new ProportionalScalable(); + + // The variation mode chosen changes how the percentages are computed + switch (variationParameters.getVariationMode()) { + case PROPORTIONAL_TO_TARGETP -> { + // Proportional to the target power of each generator + AtomicReference sumP0 = new AtomicReference<>(0D); + generators.forEach(generator -> + sumP0.set(sumP0.get() + generator.getTargetP()) + ); + generators.forEach(generator -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getTargetP() * 100.0 / sumP0.get())))); + } + case PROPORTIONAL_TO_PMAX -> { + // Proportional to the maximal power of each generator + AtomicReference sumP0 = new AtomicReference<>(0D); + generators.forEach(generator -> + sumP0.set(sumP0.get() + generator.getMaxP()) + ); + generators.forEach(generator -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getMaxP() * 100.0 / sumP0.get())))); + } + case PROPORTIONAL_TO_DIFF_PMAX_TARGETP -> { + // Proportional to the available power (Pmax - targetP) of each generator + AtomicReference sumP0 = new AtomicReference<>(0D); + generators.forEach(generator -> + sumP0.set(sumP0.get() + (generator.getMaxP() - generator.getTargetP())) + ); + generators.forEach(generator -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getMaxP() - generator.getTargetP()) * 100.0 / sumP0.get())))); + } + case PROPORTIONAL_TO_DIFF_TARGETP_PMIN -> { + // Proportional to the used power (targetP - Pmin) of each generator + AtomicReference sumP0 = new AtomicReference<>(0D); + generators.forEach(generator -> + sumP0.set(sumP0.get() + (generator.getTargetP() - generator.getMinP())) + ); + generators.forEach(generator -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getTargetP() - generator.getMinP()) * 100.0 / sumP0.get())))); + } + case REGULAR_DISTRIBUTION -> + // Each load get the same + generators.forEach(generator -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size())))); + default -> + throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", variationParameters.getVariationMode())); + } + return proportionalScalable; + } + Collection getScalables() { - return scalablePercentageList.stream().map(ScalablePercentage::getScalable).collect(Collectors.toList()); + return scalablePercentageList.stream().map(ScalablePercentage::getScalable).toList(); } private static void checkPercentages(List percentages, List scalables) { diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java new file mode 100644 index 00000000000..8e27206e7fa --- /dev/null +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023. , All partners of the iTesla project (http://www.itesla-project.eu/consortium) + * 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.iidm.modification.scalable; + +public class VariationParameters { + + public enum VariationMode { + PROPORTIONAL_TO_TARGETP, + PROPORTIONAL_TO_PMAX, + PROPORTIONAL_TO_DIFF_PMAX_TARGETP, + PROPORTIONAL_TO_DIFF_TARGETP_PMIN, + PROPORTIONAL_TO_P0, + REGULAR_DISTRIBUTION + } + + private VariationMode variationMode; + + + public VariationParameters(VariationMode variationMode) { + this.variationMode = variationMode; + } + + public VariationMode getVariationMode() { + return variationMode; + } + + public void setVariationMode(VariationMode variationMode) { + this.variationMode = variationMode; + } +} From 24888834df4368122a4eda033a15b8a0d99986ef Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 7 Aug 2023 10:28:12 +0200 Subject: [PATCH 02/18] Implementation of ProportionalScalable on loads and on generators Signed-off-by: Nicolas Rol --- .../scalable/ProportionalScalable.java | 110 +++++++++++++----- .../iidm/modification/scalable/Scalable.java | 26 +++++ .../scalable/VariationParameters.java | 46 ++++++-- 3 files changed, 145 insertions(+), 37 deletions(-) diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java index b385901f2fb..7c85cd6cd52 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java @@ -6,13 +6,14 @@ */ package com.powsybl.iidm.modification.scalable; +import com.powsybl.commons.reporter.Reporter; +import com.powsybl.commons.reporter.TypedValue; import com.powsybl.iidm.network.Generator; import com.powsybl.iidm.network.Load; import com.powsybl.iidm.network.Network; import java.util.*; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; /** * Scalable that divides scale proportionally between multiple scalable. @@ -74,81 +75,133 @@ private ProportionalScalable(){ } } - public ProportionalScalable onLoads(VariationParameters variationParameters, Collection loads) { + public double scaleOnLoads(Network network, + Reporter subReporter, + VariationParameters variationParameters, + Collection loads) { // Initialisation of the ProportionalScalable ProportionalScalable proportionalScalable = new ProportionalScalable(); + // Global current value + AtomicReference sumP0 = new AtomicReference<>(0D); + // The variation mode chosen changes how the percentages are computed - switch (variationParameters.getVariationMode()) { + switch (variationParameters.getDistributionMode()) { case PROPORTIONAL_TO_P0 -> { // Proportional to the P0 of the loads - AtomicReference sumP0 = new AtomicReference<>(0D); loads.forEach(load -> sumP0.set(sumP0.get() + load.getP0()) ); loads.forEach(load -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (load.getP0() * 100.0 / sumP0.get())))); + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (load.getP0() * 100.0 / sumP0.get()))) + ); } case REGULAR_DISTRIBUTION -> // Each load get the same - loads.forEach(load -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (100.0 / loads.size())))); + loads.forEach(load -> { + sumP0.set(sumP0.get() + load.getP0()); + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (100.0 / loads.size()))); + }); + default -> + throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", variationParameters.getDistributionMode())); + } + + // Variation asked globally + double variationAsked = Scalable.getVariationAsked(variationParameters, sumP0); + + // Do the repartition + double variationDone; + switch (variationParameters.getReactiveVariationMode()) { + case CONSTANT_Q -> + variationDone = proportionalScalable.scale(network, variationAsked, new ScalingParameters().setScalingConvention(Scalable.ScalingConvention.LOAD)); + case TAN_PHI_FIXED -> + variationDone = proportionalScalable.scale(network, variationAsked, new ScalingParameters().setScalingConvention(Scalable.ScalingConvention.LOAD).setConstantPowerFactor(true)); default -> - throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", variationParameters.getVariationMode())); + throw new IllegalArgumentException(String.format("Reactive Variation mode %s not recognised", variationParameters.getReactiveVariationMode())); } - return proportionalScalable; + + // Report + Scalable.createReport(subReporter, + "scalingApplied", + String.format("Successfully scaled on loads using mode %s with a variation value asked of %s. Variation done is %s", + variationParameters.getDistributionMode(), variationAsked, variationDone), + TypedValue.INFO_SEVERITY); + return variationDone; } - public ProportionalScalable onGenerators(VariationParameters variationParameters, Collection generators) { + public double scaleOnGenerators(Network network, + Reporter subReporter, + VariationParameters variationParameters, + Collection generators) { // Initialisation of the ProportionalScalable ProportionalScalable proportionalScalable = new ProportionalScalable(); + // Global current power + AtomicReference sumP = new AtomicReference<>(0D); + // The variation mode chosen changes how the percentages are computed - switch (variationParameters.getVariationMode()) { + switch (variationParameters.getDistributionMode()) { case PROPORTIONAL_TO_TARGETP -> { // Proportional to the target power of each generator - AtomicReference sumP0 = new AtomicReference<>(0D); generators.forEach(generator -> - sumP0.set(sumP0.get() + generator.getTargetP()) + sumP.set(sumP.get() + generator.getTargetP()) ); generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getTargetP() * 100.0 / sumP0.get())))); + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getTargetP() * 100.0 / sumP.get())))); } case PROPORTIONAL_TO_PMAX -> { // Proportional to the maximal power of each generator - AtomicReference sumP0 = new AtomicReference<>(0D); generators.forEach(generator -> - sumP0.set(sumP0.get() + generator.getMaxP()) + sumP.set(sumP.get() + generator.getMaxP()) ); generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getMaxP() * 100.0 / sumP0.get())))); + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getMaxP() * 100.0 / sumP.get())))); } case PROPORTIONAL_TO_DIFF_PMAX_TARGETP -> { // Proportional to the available power (Pmax - targetP) of each generator - AtomicReference sumP0 = new AtomicReference<>(0D); generators.forEach(generator -> - sumP0.set(sumP0.get() + (generator.getMaxP() - generator.getTargetP())) + sumP.set(sumP.get() + (generator.getMaxP() - generator.getTargetP())) ); generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getMaxP() - generator.getTargetP()) * 100.0 / sumP0.get())))); + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getMaxP() - generator.getTargetP()) * 100.0 / sumP.get())))); } case PROPORTIONAL_TO_DIFF_TARGETP_PMIN -> { // Proportional to the used power (targetP - Pmin) of each generator - AtomicReference sumP0 = new AtomicReference<>(0D); generators.forEach(generator -> - sumP0.set(sumP0.get() + (generator.getTargetP() - generator.getMinP())) + sumP.set(sumP.get() + (generator.getTargetP() - generator.getMinP())) ); generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getTargetP() - generator.getMinP()) * 100.0 / sumP0.get())))); + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getTargetP() - generator.getMinP()) * 100.0 / sumP.get())))); } case REGULAR_DISTRIBUTION -> // Each load get the same - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size())))); + generators.forEach(generator -> { + sumP.set(sumP.get() + (generator.getTargetP() - generator.getMinP())); + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))); + }); default -> - throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", variationParameters.getVariationMode())); + throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", variationParameters.getDistributionMode())); } - return proportionalScalable; + + // Variation asked globally + double variationAsked = Scalable.getVariationAsked(variationParameters, sumP); + + // Do the repartition + double variationDone = proportionalScalable.scale( + network, + variationAsked, + new ScalingParameters() + .setScalingConvention(ScalingConvention.GENERATOR) + .setIterative(true)); + + // Report + Scalable.createReport(subReporter, + "scalingApplied", + String.format("Successfully scaled on generators using mode %s with a variation value asked of %s. Variation done is %s", + variationParameters.getDistributionMode(), variationAsked, variationDone), + TypedValue.INFO_SEVERITY); + + return variationDone; } Collection getScalables() { @@ -210,8 +263,7 @@ private double scaleIteration(Network n, double asked, ScalingParameters paramet Scalable s = scalablePercentage.getScalable(); double iterationPercentage = scalablePercentage.getIterationPercentage(); double askedOnScalable = iterationPercentage / 100 * asked; - double doneOnScalable = 0; - doneOnScalable = s.scale(n, askedOnScalable, parameters); + double doneOnScalable = s.scale(n, askedOnScalable, parameters); if (Math.abs(doneOnScalable - askedOnScalable) > EPSILON) { scalablePercentage.setIterationPercentage(0); } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java index b803f2107f2..f7c8aba6e29 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java @@ -6,14 +6,20 @@ */ package com.powsybl.iidm.modification.scalable; +import com.powsybl.commons.reporter.Report; +import com.powsybl.commons.reporter.Reporter; +import com.powsybl.commons.reporter.TypedValue; import com.powsybl.iidm.network.Injection; import com.powsybl.iidm.network.Network; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; +import static com.powsybl.iidm.modification.scalable.VariationParameters.VariationType.DELTA_P; + /** * @author Geoffroy Jamgotchian * @author Ameni Walha @@ -229,4 +235,24 @@ static StackScalable stack(String... ids) { static UpDownScalable upDown(Scalable upScalable, Scalable downScalable) { return new UpDownScalable(upScalable, downScalable); } + + /** + * Returns the value that has to be added to the network, depending on the type of variation chosen in the parameters + * @param variationParameters Variation parameters including a variation type (DELTA_P or TARGET_P) and a variation value + * @param sum current global value + * @return the variation value if the type is DELTA_P, else the difference between the variation value and the current global value sum + */ + static double getVariationAsked(VariationParameters variationParameters, AtomicReference sum) { + return variationParameters.getVariationType() == DELTA_P + ? variationParameters.getVariationValue() + : variationParameters.getVariationValue() - sum.get(); + } + + public static void createReport(Reporter reporter, String reporterKey, String message, TypedValue errorSeverity) { + reporter.report(Report.builder() + .withKey(reporterKey) + .withDefaultMessage(message) + .withSeverity(errorSeverity) + .build()); + } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java index 8e27206e7fa..267c37cbb25 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java @@ -7,7 +7,7 @@ public class VariationParameters { - public enum VariationMode { + public enum DistributionMode { PROPORTIONAL_TO_TARGETP, PROPORTIONAL_TO_PMAX, PROPORTIONAL_TO_DIFF_PMAX_TARGETP, @@ -16,18 +16,48 @@ public enum VariationMode { REGULAR_DISTRIBUTION } - private VariationMode variationMode; + public enum VariationType { + DELTA_P, + TARGET_P + } + + public enum ReactiveVariationMode { + CONSTANT_Q, + TAN_PHI_FIXED + } + private final DistributionMode distributionMode; + private final VariationType variationType; + private final Double variationValue; + private final ReactiveVariationMode reactiveVariationMode; + + public VariationParameters(DistributionMode distributionMode, VariationType variationType, Double variationValue, ReactiveVariationMode reactiveVariationMode) { + this.distributionMode = distributionMode; + this.variationType = variationType; + this.variationValue = variationValue; + this.reactiveVariationMode = reactiveVariationMode; + } + + public VariationParameters(DistributionMode distributionMode, VariationType variationType, Double variationValue) { + this.distributionMode = distributionMode; + this.variationType = variationType; + this.variationValue = variationValue; + this.reactiveVariationMode = null; + } + + public DistributionMode getDistributionMode() { + return distributionMode; + } - public VariationParameters(VariationMode variationMode) { - this.variationMode = variationMode; + public VariationType getVariationType() { + return variationType; } - public VariationMode getVariationMode() { - return variationMode; + public Double getVariationValue() { + return variationValue; } - public void setVariationMode(VariationMode variationMode) { - this.variationMode = variationMode; + public ReactiveVariationMode getReactiveVariationMode() { + return reactiveVariationMode; } } From d37ac44e94122561c13de69402280591f635dc61 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 7 Aug 2023 12:45:09 +0200 Subject: [PATCH 03/18] Merge VariationParameters into existing ScalingParameters + make scaleOnX methods static Signed-off-by: Nicolas Rol --- .../scalable/ProportionalScalable.java | 67 ++++++++++++------- .../iidm/modification/scalable/Scalable.java | 12 ++-- .../scalable/ScalingParameters.java | 44 ++++++++++++ .../scalable/VariationParameters.java | 63 ----------------- 4 files changed, 92 insertions(+), 94 deletions(-) delete mode 100644 iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java index 7c85cd6cd52..85177732bfb 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java @@ -6,6 +6,7 @@ */ package com.powsybl.iidm.modification.scalable; +import com.powsybl.commons.PowsyblException; import com.powsybl.commons.reporter.Reporter; import com.powsybl.commons.reporter.TypedValue; import com.powsybl.iidm.network.Generator; @@ -62,7 +63,7 @@ void setIterationPercentage(double iterationPercentage) { private final List scalablePercentageList; - private ProportionalScalable(){ + private ProportionalScalable() { // Initialisation if the list this.scalablePercentageList = new ArrayList<>(); } @@ -75,10 +76,23 @@ private ProportionalScalable(){ } } - public double scaleOnLoads(Network network, + /** + * Computes and applies a scaling variation of power on a list of loads, using variation parameters defined by the user + * @param network The network on which the scaling variation is applied + * @param subReporter The reporter + * @param scalingParameters The parameters for the scaling + * @param loads The loads on which the scaling will be done + * @return the value of the power that was finally allocated on the loads + */ + public static double scaleOnLoads(Network network, Reporter subReporter, - VariationParameters variationParameters, + ScalingParameters scalingParameters, Collection loads) { + // Check that scalingParameters is coherent with the type of elements given + if (scalingParameters.getScalingConvention() != ScalingConvention.LOAD) { + throw new PowsyblException(String.format("Scaling convention in the parameters cannot be %s for generators", scalingParameters.getScalingConvention())); + } + // Initialisation of the ProportionalScalable ProportionalScalable proportionalScalable = new ProportionalScalable(); @@ -86,7 +100,7 @@ public double scaleOnLoads(Network network, AtomicReference sumP0 = new AtomicReference<>(0D); // The variation mode chosen changes how the percentages are computed - switch (variationParameters.getDistributionMode()) { + switch (scalingParameters.getDistributionMode()) { case PROPORTIONAL_TO_P0 -> { // Proportional to the P0 of the loads loads.forEach(load -> @@ -103,36 +117,41 @@ public double scaleOnLoads(Network network, proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (100.0 / loads.size()))); }); default -> - throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", variationParameters.getDistributionMode())); + throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", scalingParameters.getDistributionMode())); } // Variation asked globally - double variationAsked = Scalable.getVariationAsked(variationParameters, sumP0); + double variationAsked = Scalable.getVariationAsked(scalingParameters, sumP0); // Do the repartition - double variationDone; - switch (variationParameters.getReactiveVariationMode()) { - case CONSTANT_Q -> - variationDone = proportionalScalable.scale(network, variationAsked, new ScalingParameters().setScalingConvention(Scalable.ScalingConvention.LOAD)); - case TAN_PHI_FIXED -> - variationDone = proportionalScalable.scale(network, variationAsked, new ScalingParameters().setScalingConvention(Scalable.ScalingConvention.LOAD).setConstantPowerFactor(true)); - default -> - throw new IllegalArgumentException(String.format("Reactive Variation mode %s not recognised", variationParameters.getReactiveVariationMode())); - } + double variationDone = proportionalScalable.scale(network, variationAsked, scalingParameters); // Report Scalable.createReport(subReporter, "scalingApplied", String.format("Successfully scaled on loads using mode %s with a variation value asked of %s. Variation done is %s", - variationParameters.getDistributionMode(), variationAsked, variationDone), + scalingParameters.getDistributionMode(), variationAsked, variationDone), TypedValue.INFO_SEVERITY); return variationDone; } - public double scaleOnGenerators(Network network, + /** + * Computes and applies a scaling variation of power on a list of generators, using variation parameters defined by the user + * @param network The network on which the scaling variation is applied + * @param subReporter The reporter + * @param scalingParameters The parameters for the scaling + * @param generators The generators on which the scaling will be done + * @return the value of the power that was finally allocated on the generators + */ + public static double scaleOnGenerators(Network network, Reporter subReporter, - VariationParameters variationParameters, + ScalingParameters scalingParameters, Collection generators) { + // Check that scalingParameters is coherent with the type of elements given + if (scalingParameters.getScalingConvention() != ScalingConvention.GENERATOR) { + throw new PowsyblException(String.format("Scaling convention in the parameters cannot be %s for generators", scalingParameters.getScalingConvention())); + } + // Initialisation of the ProportionalScalable ProportionalScalable proportionalScalable = new ProportionalScalable(); @@ -140,7 +159,7 @@ public double scaleOnGenerators(Network network, AtomicReference sumP = new AtomicReference<>(0D); // The variation mode chosen changes how the percentages are computed - switch (variationParameters.getDistributionMode()) { + switch (scalingParameters.getDistributionMode()) { case PROPORTIONAL_TO_TARGETP -> { // Proportional to the target power of each generator generators.forEach(generator -> @@ -180,25 +199,23 @@ public double scaleOnGenerators(Network network, proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))); }); default -> - throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", variationParameters.getDistributionMode())); + throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", scalingParameters.getDistributionMode())); } // Variation asked globally - double variationAsked = Scalable.getVariationAsked(variationParameters, sumP); + double variationAsked = Scalable.getVariationAsked(scalingParameters, sumP); // Do the repartition double variationDone = proportionalScalable.scale( network, variationAsked, - new ScalingParameters() - .setScalingConvention(ScalingConvention.GENERATOR) - .setIterative(true)); + scalingParameters); // Report Scalable.createReport(subReporter, "scalingApplied", String.format("Successfully scaled on generators using mode %s with a variation value asked of %s. Variation done is %s", - variationParameters.getDistributionMode(), variationAsked, variationDone), + scalingParameters.getDistributionMode(), variationAsked, variationDone), TypedValue.INFO_SEVERITY); return variationDone; diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java index f7c8aba6e29..5a920a07e99 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java @@ -18,7 +18,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import static com.powsybl.iidm.modification.scalable.VariationParameters.VariationType.DELTA_P; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.DELTA_P; /** * @author Geoffroy Jamgotchian @@ -238,14 +238,14 @@ static UpDownScalable upDown(Scalable upScalable, Scalable downScalable) { /** * Returns the value that has to be added to the network, depending on the type of variation chosen in the parameters - * @param variationParameters Variation parameters including a variation type (DELTA_P or TARGET_P) and a variation value + * @param scalingParameters Scaling parameters including a variation type (DELTA_P or TARGET_P) and a variation value * @param sum current global value * @return the variation value if the type is DELTA_P, else the difference between the variation value and the current global value sum */ - static double getVariationAsked(VariationParameters variationParameters, AtomicReference sum) { - return variationParameters.getVariationType() == DELTA_P - ? variationParameters.getVariationValue() - : variationParameters.getVariationValue() - sum.get(); + static double getVariationAsked(ScalingParameters scalingParameters, AtomicReference sum) { + return scalingParameters.getVariationType() == DELTA_P + ? scalingParameters.getVariationValue() + : scalingParameters.getVariationValue() - sum.get(); } public static void createReport(Reporter reporter, String reporterKey, String message, TypedValue errorSeverity) { diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java index b7e4cf3ffda..6f4d56f9d45 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java @@ -18,6 +18,24 @@ public class ScalingParameters { public static final String VERSION = "1.0"; + public enum DistributionMode { + PROPORTIONAL_TO_TARGETP, + PROPORTIONAL_TO_PMAX, + PROPORTIONAL_TO_DIFF_PMAX_TARGETP, + PROPORTIONAL_TO_DIFF_TARGETP_PMIN, + PROPORTIONAL_TO_P0, + REGULAR_DISTRIBUTION + } + + public enum VariationType { + DELTA_P, + TARGET_P + } + + private DistributionMode distributionMode = null; + private VariationType variationType = null; + private double variationValue = 0.0; + public static final Scalable.ScalingConvention DEFAULT_SCALING_CONVENTION = Scalable.ScalingConvention.GENERATOR; public static final boolean DEFAULT_CONSTANT_POWER_FACTOR = false; public static final boolean DEFAULT_RECONNECT = false; @@ -46,6 +64,20 @@ public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean r this.allowsGeneratorOutOfActivePowerLimits = allowsGeneratorOutOfActivePowerLimits; } + public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, + boolean iterative, boolean allowsGeneratorOutOfActivePowerLimits, + DistributionMode distributionMode, VariationType variationType, + double variationValue) { + this.scalingConvention = scalingConvention; + this.reconnect = reconnect; + this.constantPowerFactor = constantPowerFactor; + this.iterative = iterative; + this.allowsGeneratorOutOfActivePowerLimits = allowsGeneratorOutOfActivePowerLimits; + this.distributionMode = distributionMode; + this.variationType = variationType; + this.variationValue = variationValue; + } + /** * @return the scaling convention for the scaling, {@link Scalable.ScalingConvention} GENERATOR by default. */ @@ -109,6 +141,18 @@ public ScalingParameters setAllowsGeneratorOutOfActivePowerLimits(boolean allows return this; } + public DistributionMode getDistributionMode() { + return distributionMode; + } + + public VariationType getVariationType() { + return variationType; + } + + public Double getVariationValue() { + return variationValue; + } + public static ScalingParameters load() { return load(PlatformConfig.defaultConfig()); } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java deleted file mode 100644 index 267c37cbb25..00000000000 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/VariationParameters.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2023. , All partners of the iTesla project (http://www.itesla-project.eu/consortium) - * 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.iidm.modification.scalable; - -public class VariationParameters { - - public enum DistributionMode { - PROPORTIONAL_TO_TARGETP, - PROPORTIONAL_TO_PMAX, - PROPORTIONAL_TO_DIFF_PMAX_TARGETP, - PROPORTIONAL_TO_DIFF_TARGETP_PMIN, - PROPORTIONAL_TO_P0, - REGULAR_DISTRIBUTION - } - - public enum VariationType { - DELTA_P, - TARGET_P - } - - public enum ReactiveVariationMode { - CONSTANT_Q, - TAN_PHI_FIXED - } - - private final DistributionMode distributionMode; - private final VariationType variationType; - private final Double variationValue; - private final ReactiveVariationMode reactiveVariationMode; - - public VariationParameters(DistributionMode distributionMode, VariationType variationType, Double variationValue, ReactiveVariationMode reactiveVariationMode) { - this.distributionMode = distributionMode; - this.variationType = variationType; - this.variationValue = variationValue; - this.reactiveVariationMode = reactiveVariationMode; - } - - public VariationParameters(DistributionMode distributionMode, VariationType variationType, Double variationValue) { - this.distributionMode = distributionMode; - this.variationType = variationType; - this.variationValue = variationValue; - this.reactiveVariationMode = null; - } - - public DistributionMode getDistributionMode() { - return distributionMode; - } - - public VariationType getVariationType() { - return variationType; - } - - public Double getVariationValue() { - return variationValue; - } - - public ReactiveVariationMode getReactiveVariationMode() { - return reactiveVariationMode; - } -} From aae0a7d21f97ecdb724b6955eac12725cb437f78 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 7 Aug 2023 17:31:51 +0200 Subject: [PATCH 04/18] Added Exceptions management and Tests Signed-off-by: Nicolas Rol --- .../scalable/ProportionalScalable.java | 88 ++-- .../scalable/ScalingParameters.java | 26 +- .../scalable/ProportionalScalableTest.java | 416 ++++++++++++++++++ .../modification/scalable/ScalableTest.java | 30 +- .../scalable/ScalingParametersTest.java | 26 +- 5 files changed, 545 insertions(+), 41 deletions(-) create mode 100644 iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java index 85177732bfb..67beda9677f 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java @@ -90,7 +90,7 @@ public static double scaleOnLoads(Network network, Collection loads) { // Check that scalingParameters is coherent with the type of elements given if (scalingParameters.getScalingConvention() != ScalingConvention.LOAD) { - throw new PowsyblException(String.format("Scaling convention in the parameters cannot be %s for generators", scalingParameters.getScalingConvention())); + throw new PowsyblException(String.format("Scaling convention in the parameters cannot be %s for loads", scalingParameters.getScalingConvention())); } // Initialisation of the ProportionalScalable @@ -106,9 +106,17 @@ public static double scaleOnLoads(Network network, loads.forEach(load -> sumP0.set(sumP0.get() + load.getP0()) ); - loads.forEach(load -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (load.getP0() * 100.0 / sumP0.get()))) - ); + if (sumP0.get() > 0.0) { + loads.forEach(load -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (load.getP0() * 100.0 / sumP0.get()))) + ); + } else { + // If no power is currently configured, a regular distribution is used + loads.forEach(load -> { + sumP0.set(sumP0.get() + load.getP0()); + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (100.0 / loads.size()))); + }); + } } case REGULAR_DISTRIBUTION -> // Each load get the same @@ -156,54 +164,84 @@ public static double scaleOnGenerators(Network network, ProportionalScalable proportionalScalable = new ProportionalScalable(); // Global current power - AtomicReference sumP = new AtomicReference<>(0D); + AtomicReference sumTargetP = new AtomicReference<>(0D); // The variation mode chosen changes how the percentages are computed switch (scalingParameters.getDistributionMode()) { case PROPORTIONAL_TO_TARGETP -> { // Proportional to the target power of each generator generators.forEach(generator -> - sumP.set(sumP.get() + generator.getTargetP()) + sumTargetP.set(sumTargetP.get() + generator.getTargetP()) ); - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getTargetP() * 100.0 / sumP.get())))); + if (sumTargetP.get() > 0.0) { + generators.forEach(generator -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getTargetP() * 100.0 / sumTargetP.get())))); + } else { + // If no power is currently configured, a regular distribution is used + generators.forEach(generator -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) + ); + } } case PROPORTIONAL_TO_PMAX -> { // Proportional to the maximal power of each generator + // Global max power + AtomicReference sumPMax = new AtomicReference<>(0D); + generators.forEach(generator -> { + sumTargetP.set(sumTargetP.get() + generator.getTargetP()); + sumPMax.set(sumPMax.get() + generator.getMaxP()); + }); generators.forEach(generator -> - sumP.set(sumP.get() + generator.getMaxP()) - ); - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getMaxP() * 100.0 / sumP.get())))); + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getMaxP() * 100.0 / sumPMax.get())))); } case PROPORTIONAL_TO_DIFF_PMAX_TARGETP -> { // Proportional to the available power (Pmax - targetP) of each generator - generators.forEach(generator -> - sumP.set(sumP.get() + (generator.getMaxP() - generator.getTargetP())) - ); - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getMaxP() - generator.getTargetP()) * 100.0 / sumP.get())))); + // Global available power + AtomicReference sumAvailableP = new AtomicReference<>(0D); + generators.forEach(generator -> { + sumTargetP.set(sumTargetP.get() + generator.getTargetP()); + sumAvailableP.set(sumAvailableP.get() + (generator.getMaxP() - generator.getTargetP())); + }); + if (sumAvailableP.get() > 0.0) { + generators.forEach(generator -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getMaxP() - generator.getTargetP()) * 100.0 / sumAvailableP.get())))); + } else { + // If no power is currently available, a regular distribution is used + generators.forEach(generator -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) + ); + } } case PROPORTIONAL_TO_DIFF_TARGETP_PMIN -> { // Proportional to the used power (targetP - Pmin) of each generator - generators.forEach(generator -> - sumP.set(sumP.get() + (generator.getTargetP() - generator.getMinP())) - ); - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getTargetP() - generator.getMinP()) * 100.0 / sumP.get())))); + // Global used power + AtomicReference sumUsedP = new AtomicReference<>(0D); + generators.forEach(generator -> { + sumTargetP.set(sumTargetP.get() + generator.getTargetP()); + sumUsedP.set(sumUsedP.get() + (generator.getTargetP() - generator.getMinP())); + }); + if (sumUsedP.get() > 0.0) { + generators.forEach(generator -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getTargetP() - generator.getMinP()) * 100.0 / sumUsedP.get())))); + } else { + // If no power is currently used, a regular distribution is used + generators.forEach(generator -> + proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) + ); + } } case REGULAR_DISTRIBUTION -> // Each load get the same generators.forEach(generator -> { - sumP.set(sumP.get() + (generator.getTargetP() - generator.getMinP())); + sumTargetP.set(sumTargetP.get() + generator.getTargetP()); proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))); }); default -> - throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", scalingParameters.getDistributionMode())); + throw new IllegalArgumentException(String.format("Variation mode cannot be %s for GeneratorScalables", scalingParameters.getDistributionMode())); } // Variation asked globally - double variationAsked = Scalable.getVariationAsked(scalingParameters, sumP); + double variationAsked = Scalable.getVariationAsked(scalingParameters, sumTargetP); // Do the repartition double variationDone = proportionalScalable.scale( diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java index 6f4d56f9d45..508d8ff11ba 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java @@ -32,10 +32,6 @@ public enum VariationType { TARGET_P } - private DistributionMode distributionMode = null; - private VariationType variationType = null; - private double variationValue = 0.0; - public static final Scalable.ScalingConvention DEFAULT_SCALING_CONVENTION = Scalable.ScalingConvention.GENERATOR; public static final boolean DEFAULT_CONSTANT_POWER_FACTOR = false; public static final boolean DEFAULT_RECONNECT = false; @@ -52,6 +48,10 @@ public enum VariationType { private boolean allowsGeneratorOutOfActivePowerLimits = DEFAULT_ALLOWS_GENERATOR_OUT_OF_ACTIVE_POWER_LIMITS; + private DistributionMode distributionMode = null; + private VariationType variationType = null; + private double variationValue = 0.0; + public ScalingParameters() { } @@ -141,18 +141,36 @@ public ScalingParameters setAllowsGeneratorOutOfActivePowerLimits(boolean allows return this; } + /** + * @return the mode of distribution used to allocate the power to the different elements (loads, generators, etc.) + */ public DistributionMode getDistributionMode() { return distributionMode; } + public ScalingParameters setDistributionMode(DistributionMode distributionMode) { + this.distributionMode = distributionMode; + return this; + } + public VariationType getVariationType() { return variationType; } + public ScalingParameters setVariationType(VariationType variationType) { + this.variationType = variationType; + return this; + } + public Double getVariationValue() { return variationValue; } + public ScalingParameters setVariationValue(double variationValue) { + this.variationValue = variationValue; + return this; + } + public static ScalingParameters load() { return load(PlatformConfig.defaultConfig()); } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java new file mode 100644 index 00000000000..18fc4a6ab7c --- /dev/null +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2023. , All partners of the iTesla project (http://www.itesla-project.eu/consortium) + * 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.iidm.modification.scalable; + +import com.powsybl.commons.PowsyblException; +import com.powsybl.commons.reporter.ReporterModel; +import com.powsybl.iidm.network.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static com.powsybl.iidm.modification.scalable.ProportionalScalable.scaleOnGenerators; +import static com.powsybl.iidm.modification.scalable.ProportionalScalable.scaleOnLoads; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode.*; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.DELTA_P; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.TARGET_P; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class ProportionalScalableTest { + + private Network network; + private Scalable g1; + private Scalable g2; + private Scalable g3; + + private Scalable l1; + private Scalable l2; + private Scalable l3; + private Scalable s; + private Scalable unknownGenerator; + private Scalable unknownLoad; + private Scalable unknownDanglingLine; + private Scalable dl1; + + @BeforeEach + void setUp() { + + network = createNetwork(); + g1 = Scalable.onGenerator("g1"); + g2 = Scalable.onGenerator("g2"); + g3 = Scalable.onGenerator("g3", -10, 80); + s = Scalable.onGenerator("s"); + unknownGenerator = Scalable.onGenerator("unknown"); + + l1 = Scalable.onLoad("l1"); + l2 = Scalable.onLoad("l2", 20, 80); + l3 = Scalable.onLoad("l3", -50, 100); + unknownLoad = Scalable.onLoad("unknown"); + unknownDanglingLine = Scalable.onDanglingLine("unknown"); + dl1 = Scalable.onDanglingLine("dl1", 20, 80); + +// reset(); + } + + static Network createNetwork() { + Network network = Network.create("network", "test"); + Substation s = network.newSubstation() + .setId("s") + .setCountry(Country.US) + .add(); + VoltageLevel vl = s.newVoltageLevel() + .setId("vl1") + .setNominalV(380.0) + .setLowVoltageLimit(0.8 * 380.0) + .setHighVoltageLimit(1.2 * 380.0) + .setTopologyKind(TopologyKind.BUS_BREAKER) + .add(); + vl.getBusBreakerView().newBus() + .setId("bus1") + .add(); + vl.newGenerator() + .setId("g1") + .setBus("bus1") + .setConnectableBus("bus1") + .setMinP(0.0) + .setMaxP(150.0) + .setTargetP(80.0) + .setVoltageRegulatorOn(false) + .setTargetQ(0.0) + .add(); + vl.newGenerator() + .setId("g2") + .setBus("bus1") + .setConnectableBus("bus1") + .setMinP(10.0) + .setMaxP(100.0) + .setTargetP(50.0) + .setVoltageRegulatorOn(false) + .setTargetQ(0.0) + .add(); + vl.newGenerator() + .setId("g3") + .setBus("bus1") + .setConnectableBus("bus1") + .setMinP(20.0) + .setMaxP(80.0) + .setTargetP(30.0) + .setVoltageRegulatorOn(true) + .setTargetV(1.0) + .add(); + vl.newLoad() + .setId("l1") + .setBus("bus1") + .setConnectableBus("bus1") + .setP0(100.0) + .setQ0(0.0) + .setLoadType(LoadType.UNDEFINED) + .add(); + vl.newLoad() + .setId("l2") + .setBus("bus1") + .setConnectableBus("bus1") + .setP0(80.0) + .setQ0(0.0) + .setLoadType(LoadType.UNDEFINED) + .add(); + vl.newLoad() + .setId("l3") + .setBus("bus1") + .setConnectableBus("bus1") + .setP0(50.0) + .setQ0(0.0) + .setLoadType(LoadType.UNDEFINED) + .add(); + + VoltageLevel vl2 = s.newVoltageLevel() + .setId("vl2") + .setTopologyKind(TopologyKind.BUS_BREAKER) + .setNominalV(380) + .add(); + vl2.getBusBreakerView().newBus() + .setId("bus2") + .add(); + network.newLine() + .setId("l12") + .setVoltageLevel1("vl1") + .setConnectableBus1("bus1") + .setBus1("bus1") + .setVoltageLevel2("vl2") + .setConnectableBus2("bus2") + .setBus2("bus2") + .setR(1) + .setX(1) + .setG1(0) + .setG2(0) + .setB1(0) + .setB2(0) + .add(); + return network; + } + + private void reset() { + + Scalable.stack(g1, g2, g3).reset(network); + Scalable.stack(l1, l2, s, unknownGenerator, unknownLoad, unknownDanglingLine, dl1).reset(network); + l3.reset(network); + } + + @Test + void testScaleOnLoads() { + // Parameters + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List loadList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getLoad("l3")); + double variationDone; + + // Proportional to P0 + ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD, + true, true, true, true, + PROPORTIONAL_TO_P0, DELTA_P, 100.0); + variationDone = scaleOnLoads(network, reporterModel, scalingParametersProportional, loadList); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(100.0 * (1.0 + 100 / 230.0), network.getLoad("l1").getP0(), 1e-5); + assertEquals(80 * (1.0 + 100 / 230.0), network.getLoad("l2").getP0(), 1e-5); + assertEquals(50.0 * (1.0 + 100 / 230.0), network.getLoad("l3").getP0(), 1e-5); + reset(); + + // Regular distribution + ScalingParameters scalingParametersRegular = new ScalingParameters(Scalable.ScalingConvention.LOAD, + true, false, true, true, + REGULAR_DISTRIBUTION, TARGET_P, 100.0); + variationDone = scaleOnLoads(network, reporterModel, scalingParametersRegular, loadList); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(100.0 / 3.0, network.getLoad("l1").getP0(), 1e-5); + assertEquals(100.0 / 3.0, network.getLoad("l2").getP0(), 1e-5); + assertEquals(100.0 / 3.0, network.getLoad("l3").getP0(), 1e-5); + reset(); + + // Error in other cases + ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.LOAD, + true, false, true, true, + PROPORTIONAL_TO_PMAX, TARGET_P, 100.0); + IllegalArgumentException e0 = assertThrows(IllegalArgumentException.class, () -> scaleOnLoads( + network, + reporterModel, + scalingParametersError, + loadList)); + assertEquals("Variation mode cannot be PROPORTIONAL_TO_PMAX for LoadScalables", e0.getMessage()); + } + + @Test + void testScaleOnGenerators() { + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + double variationDone; + + // Proportional to Target P + ScalingParameters scalingParametersProportionalTarget = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, true, true, + PROPORTIONAL_TO_TARGETP, DELTA_P, 100.0); + variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalTarget, generatorList); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(80.0 * (1.0 + 100 / 160.0), network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(50.0 * (1.0 + 100 / 160.0), network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(30.0 * (1.0 + 100 / 160.0), network.getGenerator("g3").getTargetP(), 1e-5); + reset(); + + // Proportional to P_max + ScalingParameters scalingParametersProportionalPMax = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, true, true, + PROPORTIONAL_TO_PMAX, DELTA_P, 100.0); + variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalPMax, generatorList); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(150.0 * 100.0 / 330.0, network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(100.0 * 100.0 / 330.0, network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(80.0 * 100.0 / 330.0, network.getGenerator("g3").getTargetP(), 1e-5); + reset(); + + // Proportional to the available P + ScalingParameters scalingParametersProportionalAvailableP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, true, true, + PROPORTIONAL_TO_DIFF_PMAX_TARGETP, DELTA_P, 100.0); + variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalAvailableP, generatorList); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(150.0 * 100.0 / 330.0, network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(100.0 * 100.0 / 330.0, network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(80.0 * 100.0 / 330.0, network.getGenerator("g3").getTargetP(), 1e-5); + reset(); + + // Regular distribution + ScalingParameters scalingParametersRegular = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, false, true, true, + REGULAR_DISTRIBUTION, TARGET_P, 100.0); + variationDone = scaleOnGenerators(network, reporterModel, scalingParametersRegular, generatorList); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(100.0 / 3.0, network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(100.0 / 3.0, network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(100.0 / 3.0, network.getGenerator("g3").getTargetP(), 1e-5); + reset(); + + // Error in other cases + ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, false, true, true, + PROPORTIONAL_TO_P0, TARGET_P, 100.0); + IllegalArgumentException e0 = assertThrows(IllegalArgumentException.class, () -> scaleOnGenerators( + network, + reporterModel, + scalingParametersError, + generatorList)); + assertEquals("Variation mode cannot be PROPORTIONAL_TO_P0 for GeneratorScalables", e0.getMessage()); + } + + @Test + void testScaleOnGeneratorsUsedPower() { + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + double variationDone; + + // Proportional to the used P + ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, true, true, + PROPORTIONAL_TO_DIFF_TARGETP_PMIN, DELTA_P, 100.0); + variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(80.0 + 80.0 * 100 / 130.0, network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(50.0 + 40.0 * 100 / 130.0, network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(30.0 + 10.0 * 100 / 130.0, network.getGenerator("g3").getTargetP(), 1e-5); + reset(); + } + + @Test + void testScaleOnGeneratorsWithWrongParameter() { + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + + // Set of parameter for loads + ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.LOAD, + true, false, true, true, + REGULAR_DISTRIBUTION, TARGET_P, 100.0); + + // Error raised + PowsyblException e0 = assertThrows(PowsyblException.class, () -> scaleOnGenerators( + network, + reporterModel, + scalingParametersError, + generatorList)); + assertEquals("Scaling convention in the parameters cannot be LOAD for generators", e0.getMessage()); + } + + @Test + void testScaleOnLoadsWithWrongParameter() { + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List loadList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getLoad("l3")); + + // Set of parameter for loads + ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, false, true, true, + REGULAR_DISTRIBUTION, TARGET_P, 100.0); + + // Error raised + PowsyblException e0 = assertThrows(PowsyblException.class, () -> scaleOnLoads( + network, + reporterModel, + scalingParametersError, + loadList)); + assertEquals("Scaling convention in the parameters cannot be GENERATOR for loads", e0.getMessage()); + } + + @Test + void testScaleOnGeneratorsTargetPowerAtZero() { + // Modifications in the network in order to have a "used power" at zero + network.getGenerator("g1").setTargetP(0.0); + network.getGenerator("g2").setTargetP(0.0); + network.getGenerator("g3").setTargetP(0.0); + + // Parameters + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + double variationDone; + + // Proportional to the used P + ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, true, true, + PROPORTIONAL_TO_TARGETP, DELTA_P, 100.0); + variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(0.0 + 100.0 / 3.0, network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(0.0 + 100.0 / 3.0, network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(0.0 + 100.0 / 3.0, network.getGenerator("g3").getTargetP(), 1e-5); + } + + @Test + void testScaleOnGeneratorsUsedPowerAtZero() { + // Modifications in the network in order to have a "used power" at zero + network.getGenerator("g1").setTargetP(network.getGenerator("g1").getMinP()); + network.getGenerator("g2").setTargetP(network.getGenerator("g2").getMinP()); + network.getGenerator("g3").setTargetP(network.getGenerator("g3").getMinP()); + + // Parameters + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + double variationDone; + + // Proportional to the used P + ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, true, true, + PROPORTIONAL_TO_DIFF_TARGETP_PMIN, DELTA_P, 100.0); + variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(0.0 + 100.0 / 3.0, network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(10.0 + 100.0 / 3.0, network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(20.0 + 100.0 / 3.0, network.getGenerator("g3").getTargetP(), 1e-5); + } + + @Test + void testScaleOnGeneratorsAvailablePowerAtZero() { + // Modifications in the network in order to have a "used power" at zero + network.getGenerator("g1").setTargetP(network.getGenerator("g1").getMaxP()); + network.getGenerator("g2").setTargetP(network.getGenerator("g2").getMaxP()); + network.getGenerator("g3").setTargetP(network.getGenerator("g3").getMaxP()); + + // Parameters + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + double variationDone; + + // Proportional to the used P + ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, true, true, + PROPORTIONAL_TO_DIFF_PMAX_TARGETP, DELTA_P, 100.0); + variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); + assertEquals(0.0, variationDone, 1e-5); + assertEquals(150.0, network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(100.0, network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(80.0, network.getGenerator("g3").getTargetP(), 1e-5); + } + + @Test + void testScaleOnLoadsP0AtZero() { + // Modification of the network + network.getLoad("l1").setP0(0.0); + network.getLoad("l2").setP0(0.0); + network.getLoad("l3").setP0(0.0); + + // Parameters + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List loadList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getLoad("l3")); + double variationDone; + + // Proportional to P0 + ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD, + true, false, true, true, + PROPORTIONAL_TO_P0, DELTA_P, 100.0); + variationDone = scaleOnLoads(network, reporterModel, scalingParametersProportional, loadList); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(100.0 / 3.0, network.getLoad("l1").getP0(), 1e-5); + assertEquals(100.0 / 3.0, network.getLoad("l2").getP0(), 1e-5); + assertEquals(100.0 / 3.0, network.getLoad("l3").getP0(), 1e-5); + reset(); + } +} diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java index ed8a293216c..6d6359e1726 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java @@ -15,9 +15,13 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import static com.powsybl.iidm.modification.scalable.Scalable.ScalingConvention.*; +import static com.powsybl.iidm.modification.scalable.Scalable.getVariationAsked; import static com.powsybl.iidm.modification.scalable.ScalableTestNetwork.createNetwork; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.DELTA_P; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.TARGET_P; import static org.junit.jupiter.api.Assertions.*; /** @@ -570,16 +574,20 @@ void testScalableReuse() { } @Test - void testParameters() { - // Default - ScalingParameters parameters = new ScalingParameters(); - assertFalse(parameters.isConstantPowerFactor()); - assertFalse(parameters.isReconnect()); - assertEquals(GENERATOR, parameters.getScalingConvention()); - - ScalingParameters parameters1 = new ScalingParameters().setScalingConvention(LOAD).setReconnect(true); - assertEquals(LOAD, parameters1.getScalingConvention()); - assertTrue(parameters1.isReconnect()); - assertFalse(parameters1.isConstantPowerFactor()); + void testGetVariationAsked() { + assertEquals( + 100.0, + getVariationAsked(new ScalingParameters() + .setVariationValue(100.0) + .setVariationType(DELTA_P), + new AtomicReference<>(80.0)), + 0.0); + assertEquals( + 20.0, + getVariationAsked(new ScalingParameters() + .setVariationValue(100.0) + .setVariationType(TARGET_P), + new AtomicReference<>(80.0)), + 0.0); } } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java index b02eff7c54f..ad917680032 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java @@ -17,6 +17,9 @@ import java.nio.file.FileSystem; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode.*; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.DELTA_P; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.TARGET_P; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -60,6 +63,21 @@ void fullConstructorTest() { assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); } + @Test + void fullSecondConstructorTest() { + ScalingParameters parameters = new ScalingParameters(Scalable.ScalingConvention.LOAD, + true, true, true, true, + PROPORTIONAL_TO_P0, DELTA_P, 100.0); + assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); + assertTrue(parameters.isConstantPowerFactor()); + assertTrue(parameters.isIterative()); + assertTrue(parameters.isReconnect()); + assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); + assertEquals(PROPORTIONAL_TO_P0, parameters.getDistributionMode()); + assertEquals(DELTA_P, parameters.getVariationType()); + assertEquals(100.0, parameters.getVariationValue(), 0.0); + } + @Test void settersTest() { ScalingParameters parameters = new ScalingParameters() @@ -67,12 +85,18 @@ void settersTest() { .setConstantPowerFactor(true) .setIterative(true) .setReconnect(true) - .setAllowsGeneratorOutOfActivePowerLimits(true); + .setAllowsGeneratorOutOfActivePowerLimits(true) + .setDistributionMode(PROPORTIONAL_TO_P0) + .setVariationType(TARGET_P) + .setVariationValue(100.0); assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); assertTrue(parameters.isConstantPowerFactor()); assertTrue(parameters.isIterative()); assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); + assertEquals(PROPORTIONAL_TO_P0, parameters.getDistributionMode()); + assertEquals(TARGET_P, parameters.getVariationType()); + assertEquals(100.0, parameters.getVariationValue(), 0.0); } @Test From f45a7737bc3d68b0316846391b6dbb639e76ea1e Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Tue, 8 Aug 2023 17:57:59 +0200 Subject: [PATCH 05/18] Moved scaleOnLoads and scaleOnGenerators in Scalable, added STACKING_UP mode, added priorities Signed-off-by: Nicolas Rol --- .../scalable/GeneratorScalable.java | 7 + .../scalable/ProportionalScalable.java | 224 +++-------------- .../iidm/modification/scalable/Scalable.java | 231 +++++++++++++++++- .../scalable/ScalingParameters.java | 123 ++++++++-- .../json/ScalingParametersDeserializer.java | 43 ++-- .../json/ScalingParametersSerializer.java | 2 +- .../scalable/ProportionalScalableTest.java | 75 ++++-- .../modification/scalable/ScalableTest.java | 18 +- .../scalable/ScalingParametersTest.java | 37 +-- .../json/JsonScalingParametersTest.java | 12 +- .../resources/json/ScalingParameters.json | 4 +- .../json/ScalingParameters_v1.0.json | 7 + 12 files changed, 492 insertions(+), 291 deletions(-) create mode 100644 iidm/iidm-modification/src/test/resources/json/ScalingParameters_v1.0.json diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java index 41539814676..fdbb23e6d9f 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java @@ -154,4 +154,11 @@ public double scale(Network n, double asked, ScalingParameters parameters) { return done; } + + double availablePowerInPercentageOfAsked(Network network, double asked, double scalingPercentage) { + var generator = network.getGenerator(id); + var availablePower = generator.getMaxP() - generator.getTargetP(); + var askedPower = asked * scalingPercentage / 100; + return askedPower > availablePower ? availablePower / askedPower : 100.0; + } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java index 67beda9677f..157aa4ec1c3 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java @@ -6,16 +6,15 @@ */ package com.powsybl.iidm.modification.scalable; -import com.powsybl.commons.PowsyblException; -import com.powsybl.commons.reporter.Reporter; -import com.powsybl.commons.reporter.TypedValue; -import com.powsybl.iidm.network.Generator; -import com.powsybl.iidm.network.Load; import com.powsybl.iidm.network.Network; import java.util.*; import java.util.concurrent.atomic.AtomicReference; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode.STACKING_UP; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VENTILATION; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; + /** * Scalable that divides scale proportionally between multiple scalable. * @@ -25,12 +24,12 @@ class ProportionalScalable extends AbstractCompoundScalable { private static final double EPSILON = 1e-2; - private static final class ScalablePercentage { + static final class ScalablePercentage { private final Scalable scalable; private final float percentage; private double iterationPercentage; - private ScalablePercentage(Scalable scalable, float percentage) { + ScalablePercentage(Scalable scalable, float percentage) { this.scalable = scalable; this.percentage = percentage; this.iterationPercentage = percentage; @@ -63,7 +62,7 @@ void setIterationPercentage(double iterationPercentage) { private final List scalablePercentageList; - private ProportionalScalable() { + ProportionalScalable() { // Initialisation if the list this.scalablePercentageList = new ArrayList<>(); } @@ -76,193 +75,14 @@ private ProportionalScalable() { } } - /** - * Computes and applies a scaling variation of power on a list of loads, using variation parameters defined by the user - * @param network The network on which the scaling variation is applied - * @param subReporter The reporter - * @param scalingParameters The parameters for the scaling - * @param loads The loads on which the scaling will be done - * @return the value of the power that was finally allocated on the loads - */ - public static double scaleOnLoads(Network network, - Reporter subReporter, - ScalingParameters scalingParameters, - Collection loads) { - // Check that scalingParameters is coherent with the type of elements given - if (scalingParameters.getScalingConvention() != ScalingConvention.LOAD) { - throw new PowsyblException(String.format("Scaling convention in the parameters cannot be %s for loads", scalingParameters.getScalingConvention())); - } - - // Initialisation of the ProportionalScalable - ProportionalScalable proportionalScalable = new ProportionalScalable(); - - // Global current value - AtomicReference sumP0 = new AtomicReference<>(0D); - - // The variation mode chosen changes how the percentages are computed - switch (scalingParameters.getDistributionMode()) { - case PROPORTIONAL_TO_P0 -> { - // Proportional to the P0 of the loads - loads.forEach(load -> - sumP0.set(sumP0.get() + load.getP0()) - ); - if (sumP0.get() > 0.0) { - loads.forEach(load -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (load.getP0() * 100.0 / sumP0.get()))) - ); - } else { - // If no power is currently configured, a regular distribution is used - loads.forEach(load -> { - sumP0.set(sumP0.get() + load.getP0()); - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (100.0 / loads.size()))); - }); - } - } - case REGULAR_DISTRIBUTION -> - // Each load get the same - loads.forEach(load -> { - sumP0.set(sumP0.get() + load.getP0()); - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onLoad(load.getId()), (float) (100.0 / loads.size()))); - }); - default -> - throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", scalingParameters.getDistributionMode())); - } - - // Variation asked globally - double variationAsked = Scalable.getVariationAsked(scalingParameters, sumP0); - - // Do the repartition - double variationDone = proportionalScalable.scale(network, variationAsked, scalingParameters); - - // Report - Scalable.createReport(subReporter, - "scalingApplied", - String.format("Successfully scaled on loads using mode %s with a variation value asked of %s. Variation done is %s", - scalingParameters.getDistributionMode(), variationAsked, variationDone), - TypedValue.INFO_SEVERITY); - return variationDone; - } - - /** - * Computes and applies a scaling variation of power on a list of generators, using variation parameters defined by the user - * @param network The network on which the scaling variation is applied - * @param subReporter The reporter - * @param scalingParameters The parameters for the scaling - * @param generators The generators on which the scaling will be done - * @return the value of the power that was finally allocated on the generators - */ - public static double scaleOnGenerators(Network network, - Reporter subReporter, - ScalingParameters scalingParameters, - Collection generators) { - // Check that scalingParameters is coherent with the type of elements given - if (scalingParameters.getScalingConvention() != ScalingConvention.GENERATOR) { - throw new PowsyblException(String.format("Scaling convention in the parameters cannot be %s for generators", scalingParameters.getScalingConvention())); - } - - // Initialisation of the ProportionalScalable - ProportionalScalable proportionalScalable = new ProportionalScalable(); - - // Global current power - AtomicReference sumTargetP = new AtomicReference<>(0D); - - // The variation mode chosen changes how the percentages are computed - switch (scalingParameters.getDistributionMode()) { - case PROPORTIONAL_TO_TARGETP -> { - // Proportional to the target power of each generator - generators.forEach(generator -> - sumTargetP.set(sumTargetP.get() + generator.getTargetP()) - ); - if (sumTargetP.get() > 0.0) { - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getTargetP() * 100.0 / sumTargetP.get())))); - } else { - // If no power is currently configured, a regular distribution is used - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) - ); - } - } - case PROPORTIONAL_TO_PMAX -> { - // Proportional to the maximal power of each generator - // Global max power - AtomicReference sumPMax = new AtomicReference<>(0D); - generators.forEach(generator -> { - sumTargetP.set(sumTargetP.get() + generator.getTargetP()); - sumPMax.set(sumPMax.get() + generator.getMaxP()); - }); - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getMaxP() * 100.0 / sumPMax.get())))); - } - case PROPORTIONAL_TO_DIFF_PMAX_TARGETP -> { - // Proportional to the available power (Pmax - targetP) of each generator - // Global available power - AtomicReference sumAvailableP = new AtomicReference<>(0D); - generators.forEach(generator -> { - sumTargetP.set(sumTargetP.get() + generator.getTargetP()); - sumAvailableP.set(sumAvailableP.get() + (generator.getMaxP() - generator.getTargetP())); - }); - if (sumAvailableP.get() > 0.0) { - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getMaxP() - generator.getTargetP()) * 100.0 / sumAvailableP.get())))); - } else { - // If no power is currently available, a regular distribution is used - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) - ); - } - } - case PROPORTIONAL_TO_DIFF_TARGETP_PMIN -> { - // Proportional to the used power (targetP - Pmin) of each generator - // Global used power - AtomicReference sumUsedP = new AtomicReference<>(0D); - generators.forEach(generator -> { - sumTargetP.set(sumTargetP.get() + generator.getTargetP()); - sumUsedP.set(sumUsedP.get() + (generator.getTargetP() - generator.getMinP())); - }); - if (sumUsedP.get() > 0.0) { - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getTargetP() - generator.getMinP()) * 100.0 / sumUsedP.get())))); - } else { - // If no power is currently used, a regular distribution is used - generators.forEach(generator -> - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) - ); - } - } - case REGULAR_DISTRIBUTION -> - // Each load get the same - generators.forEach(generator -> { - sumTargetP.set(sumTargetP.get() + generator.getTargetP()); - proportionalScalable.scalablePercentageList.add(new ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))); - }); - default -> - throw new IllegalArgumentException(String.format("Variation mode cannot be %s for GeneratorScalables", scalingParameters.getDistributionMode())); - } - - // Variation asked globally - double variationAsked = Scalable.getVariationAsked(scalingParameters, sumTargetP); - - // Do the repartition - double variationDone = proportionalScalable.scale( - network, - variationAsked, - scalingParameters); - - // Report - Scalable.createReport(subReporter, - "scalingApplied", - String.format("Successfully scaled on generators using mode %s with a variation value asked of %s. Variation done is %s", - scalingParameters.getDistributionMode(), variationAsked, variationDone), - TypedValue.INFO_SEVERITY); - - return variationDone; - } - Collection getScalables() { return scalablePercentageList.stream().map(ScalablePercentage::getScalable).toList(); } + List getScalablePercentageList() { + return scalablePercentageList; + } + private static void checkPercentages(List percentages, List scalables) { Objects.requireNonNull(percentages); Objects.requireNonNull(scalables); @@ -332,7 +152,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { Objects.requireNonNull(n); Objects.requireNonNull(parameters); reinitIterationPercentage(); - if (parameters.isIterative()) { + if (parameters.getPriority() == VOLUME) { return iterativeScale(n, asked, parameters); } else { return scaleIteration(n, asked, parameters); @@ -343,5 +163,25 @@ private void reinitIterationPercentage() { scalablePercentageList.forEach(scalablePercentage -> scalablePercentage.setIterationPercentage(scalablePercentage.getPercentage())); } + /** + * Compute the power that can be scaled on the network while keeping the ventilation percentages valid. + * This method is only used if the distribution is not STACKING_UP and if the scaling priority is VENTILATION. + * @param asked power that shall be scaled on the network + * @param scalingParameters scaling parameters + * @param network network on which the scaling shall be done + * @return the effective power value that can be safely scaled while keeping the ventilation percentages valid + */ + double resizeAskedForVentilation(Network network, double asked, ScalingParameters scalingParameters) { + if (scalingParameters.getDistributionMode() != STACKING_UP && scalingParameters.getPriority() == VENTILATION) { + AtomicReference resizingPercentage = new AtomicReference<>(1.0); + scalablePercentageList.forEach(scalablePercentage -> + resizingPercentage.set(Math.min(((GeneratorScalable) scalablePercentage.getScalable()).availablePowerInPercentageOfAsked(network, asked, scalablePercentage.getPercentage()), resizingPercentage.get())) + ); + return asked * resizingPercentage.get(); + } else { + return asked; + } + } + } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java index 5a920a07e99..7e61b22c589 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java @@ -6,19 +6,23 @@ */ package com.powsybl.iidm.modification.scalable; +import com.powsybl.commons.PowsyblException; import com.powsybl.commons.reporter.Report; import com.powsybl.commons.reporter.Reporter; import com.powsybl.commons.reporter.TypedValue; +import com.powsybl.iidm.network.Generator; import com.powsybl.iidm.network.Injection; +import com.powsybl.iidm.network.Load; import com.powsybl.iidm.network.Network; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.DELTA_P; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; /** * @author Geoffroy Jamgotchian @@ -243,9 +247,9 @@ static UpDownScalable upDown(Scalable upScalable, Scalable downScalable) { * @return the variation value if the type is DELTA_P, else the difference between the variation value and the current global value sum */ static double getVariationAsked(ScalingParameters scalingParameters, AtomicReference sum) { - return scalingParameters.getVariationType() == DELTA_P - ? scalingParameters.getVariationValue() - : scalingParameters.getVariationValue() - sum.get(); + return scalingParameters.getScalingType() == DELTA_P + ? scalingParameters.getScalingValue() + : scalingParameters.getScalingValue() - sum.get(); } public static void createReport(Reporter reporter, String reporterKey, String message, TypedValue errorSeverity) { @@ -255,4 +259,223 @@ public static void createReport(Reporter reporter, String reporterKey, String me .withSeverity(errorSeverity) .build()); } + + /** + * Computes and applies a scaling variation of power on a list of loads, using variation parameters defined by the user. + * Depending on the distribution mode chosen, the distribution percentage for each load will be computed differently: + *
    + *
  • PROPORTIONAL_TO_P0: P0 divided by the sum of all the P0
  • + *
  • REGULAR_DISTRIBUTION: 100% divided by the number of loads
  • + *
+ * If the global sum computed for the PROPORTIONAL_TO_P0 mode is at zero, the system will default to the REGULAR_DISTRIBUTION mode. + * @param network The network on which the scaling variation is applied + * @param subReporter The reporter + * @param scalingParameters The parameters for the scaling + * @param loads The loads on which the scaling will be done + * @return the value of the power that was finally allocated on the loads + */ + static double scaleOnLoads(Network network, + Reporter subReporter, + ScalingParameters scalingParameters, + Collection loads) { + // Check that scalingParameters is coherent with the type of elements given + if (scalingParameters.getScalingConvention() != ScalingConvention.LOAD) { + throw new PowsyblException(String.format("Scaling convention in the parameters cannot be %s for loads", scalingParameters.getScalingConvention())); + } + + // Initialisation of the ProportionalScalable + ProportionalScalable proportionalScalable = new ProportionalScalable(); + + // Global current value + AtomicReference sumP0 = new AtomicReference<>(0D); + + // The variation mode chosen changes how the percentages are computed + switch (scalingParameters.getDistributionMode()) { + case PROPORTIONAL_TO_P0 -> { + // Proportional to the P0 of the loads + loads.forEach(load -> + sumP0.set(sumP0.get() + load.getP0()) + ); + if (sumP0.get() > 0.0) { + loads.forEach(load -> + proportionalScalable.getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onLoad(load.getId()), (float) (load.getP0() * 100.0 / sumP0.get()))) + ); + } else { + // If no power is currently configured, a regular distribution is used + loads.forEach(load -> { + sumP0.set(sumP0.get() + load.getP0()); + proportionalScalable.getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onLoad(load.getId()), (float) (100.0 / loads.size()))); + }); + } + } + case REGULAR_DISTRIBUTION -> + // Each load get the same + loads.forEach(load -> { + sumP0.set(sumP0.get() + load.getP0()); + proportionalScalable.getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onLoad(load.getId()), (float) (100.0 / loads.size()))); + }); + default -> + throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", scalingParameters.getDistributionMode())); + } + + // Variation asked globally + double variationAsked = Scalable.getVariationAsked(scalingParameters, sumP0); + + // Do the repartition + double variationDone = proportionalScalable.scale(network, variationAsked, scalingParameters); + + // Report + Scalable.createReport(subReporter, + "scalingApplied", + String.format("Successfully scaled on loads using mode %s with a variation value asked of %s. Variation done is %s", + scalingParameters.getDistributionMode(), variationAsked, variationDone), + TypedValue.INFO_SEVERITY); + return variationDone; + } + + /** + * Computes and applies a scaling variation of power on a list of generators, using variation parameters defined by the user. + * Depending on the distribution mode chosen, the distribution percentage for each generator will be computed differently: + *
    + *
  • PROPORTIONAL_TO_TARGETP: targetP divided by the sum of all the targetP
  • + *
  • PROPORTIONAL_TO_PMAX: Pmax divided by the sum of all the Pmax
  • + *
  • PROPORTIONAL_TO_DIFF_PMAX_TARGETP: available power (Pmax - targetP) divided by the sum of all the available power
  • + *
  • PROPORTIONAL_TO_DIFF_TARGETP_PMIN: used power (targetP - Pmin) divided by the sum of all the used power
  • + *
  • REGULAR_DISTRIBUTION: 100% divided by the number of generators
  • + *
  • STACKING_UP: generators are fully powered one after the other until the global power asked is reached
  • + *
+ * If the global sum computed for the chosen distribution mode is at zero, the system will default to the REGULAR_DISTRIBUTION mode. + * @param network The network on which the scaling variation is applied + * @param subReporter The reporter + * @param scalingParameters The parameters for the scaling + * @param generators The generators on which the scaling will be done + * @return the value of the power that was finally allocated on the generators + */ + static double scaleOnGenerators(Network network, + Reporter subReporter, + ScalingParameters scalingParameters, + Collection generators) { + // Check that scalingParameters is coherent with the type of elements given + if (scalingParameters.getScalingConvention() != ScalingConvention.GENERATOR) { + throw new PowsyblException(String.format("Scaling convention in the parameters cannot be %s for generators", scalingParameters.getScalingConvention())); + } + + // Initialisation of the ProportionalScalable + Scalable scalable; + + // Global current power + AtomicReference sumTargetP = new AtomicReference<>(0D); + + // The variation mode chosen changes how the percentages are computed + switch (scalingParameters.getDistributionMode()) { + case PROPORTIONAL_TO_TARGETP -> { + // Proportional to the target power of each generator + scalable = new ProportionalScalable(); + generators.forEach(generator -> + sumTargetP.set(sumTargetP.get() + generator.getTargetP()) + ); + if (sumTargetP.get() > 0.0) { + generators.forEach(generator -> + ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getTargetP() * 100.0 / sumTargetP.get())))); + } else { + // If no power is currently configured, a regular distribution is used + generators.forEach(generator -> + ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) + ); + } + } + case PROPORTIONAL_TO_PMAX -> { + // Proportional to the maximal power of each generator + scalable = new ProportionalScalable(); + + // Global max power + AtomicReference sumPMax = new AtomicReference<>(0D); + generators.forEach(generator -> { + sumTargetP.set(sumTargetP.get() + generator.getTargetP()); + sumPMax.set(sumPMax.get() + generator.getMaxP()); + }); + generators.forEach(generator -> + ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getMaxP() * 100.0 / sumPMax.get())))); + } + case PROPORTIONAL_TO_DIFF_PMAX_TARGETP -> { + // Proportional to the available power (Pmax - targetP) of each generator + scalable = new ProportionalScalable(); + + // Global available power + AtomicReference sumAvailableP = new AtomicReference<>(0D); + generators.forEach(generator -> { + sumTargetP.set(sumTargetP.get() + generator.getTargetP()); + sumAvailableP.set(sumAvailableP.get() + (generator.getMaxP() - generator.getTargetP())); + }); + if (sumAvailableP.get() > 0.0) { + generators.forEach(generator -> + ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getMaxP() - generator.getTargetP()) * 100.0 / sumAvailableP.get())))); + } else { + // If no power is currently available, a regular distribution is used + generators.forEach(generator -> + ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) + ); + } + } + case PROPORTIONAL_TO_DIFF_TARGETP_PMIN -> { + // Proportional to the used power (targetP - Pmin) of each generator + scalable = new ProportionalScalable(); + + // Global used power + AtomicReference sumUsedP = new AtomicReference<>(0D); + generators.forEach(generator -> { + sumTargetP.set(sumTargetP.get() + generator.getTargetP()); + sumUsedP.set(sumUsedP.get() + (generator.getTargetP() - generator.getMinP())); + }); + if (sumUsedP.get() > 0.0) { + generators.forEach(generator -> + ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getTargetP() - generator.getMinP()) * 100.0 / sumUsedP.get())))); + } else { + // If no power is currently used, a regular distribution is used + generators.forEach(generator -> + ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) + ); + } + } + case REGULAR_DISTRIBUTION -> { + // Each load get the same + scalable = new ProportionalScalable(); + generators.forEach(generator -> { + sumTargetP.set(sumTargetP.get() + generator.getTargetP()); + ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))); + }); + } + case STACKING_UP -> + // Fully charges generators one after the other until the power asked is reached + scalable = stack(generators.stream().map(generator -> { + sumTargetP.set(sumTargetP.get() + generator.getTargetP()); + return Scalable.onGenerator(generator.getId()); + }).toArray(Scalable[]::new)); + default -> + throw new IllegalArgumentException(String.format("Variation mode cannot be %s for GeneratorScalables", scalingParameters.getDistributionMode())); + } + + // Variation asked globally + double variationAsked = getVariationAsked(scalingParameters, sumTargetP); + + // Adapt the asked value if needed - only useful if using a proportional scalable + if (scalable instanceof ProportionalScalable proportionalScalable) { + variationAsked = proportionalScalable.resizeAskedForVentilation(network, variationAsked, scalingParameters); + } + + // Do the repartition + double variationDone = scalable.scale( + network, + variationAsked, + scalingParameters); + + // Report + Scalable.createReport(subReporter, + "scalingApplied", + String.format("Successfully scaled on generators using mode %s with a variation value asked of %s. Variation done is %s", + scalingParameters.getDistributionMode(), variationAsked, variationDone), + TypedValue.INFO_SEVERITY); + + return variationDone; + } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java index 508d8ff11ba..f5288442f2f 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java @@ -11,12 +11,15 @@ import java.util.Objects; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.ONESHOT; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; + /** * @author Coline Piloquet */ public class ScalingParameters { - public static final String VERSION = "1.0"; + public static final String VERSION = "1.1"; public enum DistributionMode { PROPORTIONAL_TO_TARGETP, @@ -24,19 +27,26 @@ public enum DistributionMode { PROPORTIONAL_TO_DIFF_PMAX_TARGETP, PROPORTIONAL_TO_DIFF_TARGETP_PMIN, PROPORTIONAL_TO_P0, - REGULAR_DISTRIBUTION + REGULAR_DISTRIBUTION, + STACKING_UP } - public enum VariationType { + public enum ScalingType { DELTA_P, TARGET_P } + public enum Priority { + VOLUME, + VENTILATION, + ONESHOT + } + public static final Scalable.ScalingConvention DEFAULT_SCALING_CONVENTION = Scalable.ScalingConvention.GENERATOR; public static final boolean DEFAULT_CONSTANT_POWER_FACTOR = false; public static final boolean DEFAULT_RECONNECT = false; - public static final boolean DEFAULT_ITERATIVE = false; public static final boolean DEFAULT_ALLOWS_GENERATOR_OUT_OF_ACTIVE_POWER_LIMITS = false; + public static final Priority DEFAULT_PRIORITY = ONESHOT; private Scalable.ScalingConvention scalingConvention = DEFAULT_SCALING_CONVENTION; @@ -44,38 +54,72 @@ public enum VariationType { private boolean constantPowerFactor = DEFAULT_CONSTANT_POWER_FACTOR; - private boolean iterative = DEFAULT_ITERATIVE; - private boolean allowsGeneratorOutOfActivePowerLimits = DEFAULT_ALLOWS_GENERATOR_OUT_OF_ACTIVE_POWER_LIMITS; private DistributionMode distributionMode = null; - private VariationType variationType = null; - private double variationValue = 0.0; + private ScalingType scalingType = null; + private double scalingValue = 0.0; + private Priority priority = DEFAULT_PRIORITY; public ScalingParameters() { } + /** + * @deprecated : replace with ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, + * Priority priority, boolean allowsGeneratorOutOfActivePowerLimits) + */ + @Deprecated(since = "v6.0.0") public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, boolean iterative, boolean allowsGeneratorOutOfActivePowerLimits) { this.scalingConvention = scalingConvention; this.reconnect = reconnect; this.constantPowerFactor = constantPowerFactor; - this.iterative = iterative; + this.priority = iterative ? VOLUME : ONESHOT; this.allowsGeneratorOutOfActivePowerLimits = allowsGeneratorOutOfActivePowerLimits; } + public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, + Priority priority, boolean allowsGeneratorOutOfActivePowerLimits) { + this.scalingConvention = scalingConvention; + this.reconnect = reconnect; + this.constantPowerFactor = constantPowerFactor; + this.priority = priority; + this.allowsGeneratorOutOfActivePowerLimits = allowsGeneratorOutOfActivePowerLimits; + } + + /** + * @deprecated : replace with (Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, + * Priority priority, boolean allowsGeneratorOutOfActivePowerLimits, + * DistributionMode distributionMode, ScalingType scalingType, + * double scalingValue) + */ + @Deprecated(since = "v6.0.0") public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, boolean iterative, boolean allowsGeneratorOutOfActivePowerLimits, - DistributionMode distributionMode, VariationType variationType, - double variationValue) { + DistributionMode distributionMode, ScalingType scalingType, + double scalingValue) { this.scalingConvention = scalingConvention; this.reconnect = reconnect; this.constantPowerFactor = constantPowerFactor; - this.iterative = iterative; + this.priority = iterative ? VOLUME : ONESHOT; this.allowsGeneratorOutOfActivePowerLimits = allowsGeneratorOutOfActivePowerLimits; this.distributionMode = distributionMode; - this.variationType = variationType; - this.variationValue = variationValue; + this.scalingType = scalingType; + this.scalingValue = scalingValue; + } + + public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, + Priority priority, boolean allowsGeneratorOutOfActivePowerLimits, + DistributionMode distributionMode, ScalingType scalingType, + double scalingValue) { + this.scalingConvention = scalingConvention; + this.reconnect = reconnect; + this.constantPowerFactor = constantPowerFactor; + this.priority = priority; + this.allowsGeneratorOutOfActivePowerLimits = allowsGeneratorOutOfActivePowerLimits; + this.distributionMode = distributionMode; + this.scalingType = scalingType; + this.scalingValue = scalingValue; } /** @@ -118,15 +162,20 @@ public ScalingParameters setConstantPowerFactor(boolean constantPowerFactor) { /** * Scale may be iterative or not for {@link ProportionalScalable}. If the iterative mode is activated, the residues * due to scalable saturation is divided between the other scalable composing the {@link ProportionalScalable}. + * @deprecated : replace with method "getPriority" * @return the iterative boolean, false by default. */ + @Deprecated(since = "v6.0.0") public boolean isIterative() { - return iterative; + return priority == VOLUME; } + /** + * @deprecated : replace with the method "setPriority" + */ + @Deprecated(since = "v6.0.0") public ScalingParameters setIterative(boolean iterative) { - this.iterative = iterative; - return this; + return iterative ? setPriority(VOLUME) : setPriority(ONESHOT); } /** @@ -153,21 +202,43 @@ public ScalingParameters setDistributionMode(DistributionMode distributionMode) return this; } - public VariationType getVariationType() { - return variationType; + /** + * @return the type of scaling asked (DELTA_P or TARGET_P) + */ + public ScalingType getScalingType() { + return scalingType; + } + + public ScalingParameters setScalingType(ScalingType scalingType) { + this.scalingType = scalingType; + return this; + } + + /** + * @return the power value configured for the scaling. + */ + public Double getScalingValue() { + return scalingValue; } - public ScalingParameters setVariationType(VariationType variationType) { - this.variationType = variationType; + public ScalingParameters setScalingValue(double scalingValue) { + this.scalingValue = scalingValue; return this; } - public Double getVariationValue() { - return variationValue; + /** + * @return an enum representing the priority of the scaling. It can be either VOLUME (the scaling will distribute the + * power asked as much as possible by iterating if elements get saturated, even if it means not respecting potential + * percentages), VENTILATION (the scaling will respect the percentages even if it means not scaling all what is + * asked), or ONESHOT (the scaling will distribute the power asked as is, in one iteration even if elements get + * saturated and even if it means not respecting potential percentages). + */ + public Priority getPriority() { + return priority; } - public ScalingParameters setVariationValue(double variationValue) { - this.variationValue = variationValue; + public ScalingParameters setPriority(Priority priority) { + this.priority = priority; return this; } @@ -182,7 +253,7 @@ public static ScalingParameters load(PlatformConfig platformConfig) { scalingParameters.setScalingConvention(config.getEnumProperty("scalingConvention", Scalable.ScalingConvention.class, DEFAULT_SCALING_CONVENTION)); scalingParameters.setConstantPowerFactor(config.getBooleanProperty("constantPowerFactor", DEFAULT_CONSTANT_POWER_FACTOR)); scalingParameters.setReconnect(config.getBooleanProperty("reconnect", DEFAULT_RECONNECT)); - scalingParameters.setIterative(config.getBooleanProperty("iterative", DEFAULT_ITERATIVE)); + scalingParameters.setPriority(config.getEnumProperty("priority", ScalingParameters.Priority.class, DEFAULT_PRIORITY)); scalingParameters.setAllowsGeneratorOutOfActivePowerLimits(config.getBooleanProperty("allowsGeneratorOutOfActivePowerLimits", DEFAULT_ALLOWS_GENERATOR_OUT_OF_ACTIVE_POWER_LIMITS)); }); return scalingParameters; diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersDeserializer.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersDeserializer.java index 7942bc4a56a..dd1c6d823b5 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersDeserializer.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersDeserializer.java @@ -17,11 +17,16 @@ import java.io.IOException; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.ONESHOT; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; + /** * @author Miora Vedelago */ public class ScalingParametersDeserializer extends StdDeserializer { + private static final String CONTEXT_NAME = "ScalingParameters"; + ScalingParametersDeserializer() { super(ScalingParameters.class); } @@ -33,34 +38,36 @@ public ScalingParameters deserialize(JsonParser parser, DeserializationContext c @Override public ScalingParameters deserialize(JsonParser parser, DeserializationContext context, ScalingParameters parameters) throws IOException { + String version = null; while (parser.nextToken() != JsonToken.END_OBJECT) { switch (parser.getCurrentName()) { - case "version": + case "version" -> { parser.nextToken(); // do nothing - break; - - case "scalingConvention": + version = parser.getValueAsString(); + } + case "scalingConvention" -> { parser.nextToken(); parameters.setScalingConvention(JsonUtil.readValue(context, parser, Scalable.ScalingConvention.class)); - break; - - case "constantPowerFactor": + } + case "constantPowerFactor" -> { parser.nextToken(); parameters.setConstantPowerFactor(parser.readValueAs(Boolean.class)); - break; - - case "reconnect": + } + case "reconnect" -> { parser.nextToken(); parameters.setReconnect(parser.readValueAs(Boolean.class)); - break; - - case "iterative": + } + case "iterative" -> { + JsonUtil.assertLessThanReferenceVersion(CONTEXT_NAME, "Tag: iterative", version, "1.1"); parser.nextToken(); - parameters.setIterative(parser.readValueAs(Boolean.class)); - break; - - default: - throw new IllegalStateException("Unexpected field: " + parser.getCurrentName()); + parameters.setPriority(Boolean.TRUE.equals(parser.readValueAs(Boolean.class)) ? VOLUME : ONESHOT); + } + case "priority" -> { + JsonUtil.assertGreaterOrEqualThanReferenceVersion(CONTEXT_NAME, "Tag: priority", version, "1.1"); + parser.nextToken(); + parameters.setPriority(JsonUtil.readValue(context, parser, ScalingParameters.Priority.class)); + } + default -> throw new IllegalStateException("Unexpected field: " + parser.getCurrentName()); } } return parameters; diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersSerializer.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersSerializer.java index 96760bf8a7c..da5bf00f46f 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersSerializer.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersSerializer.java @@ -31,7 +31,7 @@ public void serialize(ScalingParameters scalingParameters, JsonGenerator jsonGen jsonGenerator.writeStringField("scalingConvention", scalingParameters.getScalingConvention().name()); jsonGenerator.writeBooleanField("constantPowerFactor", scalingParameters.isConstantPowerFactor()); jsonGenerator.writeBooleanField("reconnect", scalingParameters.isReconnect()); - jsonGenerator.writeBooleanField("iterative", scalingParameters.isIterative()); + jsonGenerator.writeStringField("priority", scalingParameters.getPriority().name()); jsonGenerator.writeEndObject(); } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java index 18fc4a6ab7c..c1634a322c0 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java @@ -14,11 +14,12 @@ import java.util.Arrays; import java.util.List; -import static com.powsybl.iidm.modification.scalable.ProportionalScalable.scaleOnGenerators; -import static com.powsybl.iidm.modification.scalable.ProportionalScalable.scaleOnLoads; +import static com.powsybl.iidm.modification.scalable.Scalable.scaleOnGenerators; +import static com.powsybl.iidm.modification.scalable.Scalable.scaleOnLoads; import static com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode.*; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.DELTA_P; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.TARGET_P; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.*; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.TARGET_P; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -171,7 +172,7 @@ void testScaleOnLoads() { // Proportional to P0 ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, true, true, true, + true, true, VOLUME, true, PROPORTIONAL_TO_P0, DELTA_P, 100.0); variationDone = scaleOnLoads(network, reporterModel, scalingParametersProportional, loadList); assertEquals(100.0, variationDone, 1e-5); @@ -182,7 +183,7 @@ void testScaleOnLoads() { // Regular distribution ScalingParameters scalingParametersRegular = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, false, true, true, + true, false, VOLUME, true, REGULAR_DISTRIBUTION, TARGET_P, 100.0); variationDone = scaleOnLoads(network, reporterModel, scalingParametersRegular, loadList); assertEquals(100.0, variationDone, 1e-5); @@ -193,7 +194,7 @@ void testScaleOnLoads() { // Error in other cases ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, false, true, true, + true, false, VOLUME, true, PROPORTIONAL_TO_PMAX, TARGET_P, 100.0); IllegalArgumentException e0 = assertThrows(IllegalArgumentException.class, () -> scaleOnLoads( network, @@ -211,7 +212,7 @@ void testScaleOnGenerators() { // Proportional to Target P ScalingParameters scalingParametersProportionalTarget = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, true, true, + true, true, VOLUME, true, PROPORTIONAL_TO_TARGETP, DELTA_P, 100.0); variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalTarget, generatorList); assertEquals(100.0, variationDone, 1e-5); @@ -222,7 +223,7 @@ void testScaleOnGenerators() { // Proportional to P_max ScalingParameters scalingParametersProportionalPMax = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, true, true, + true, true, VOLUME, true, PROPORTIONAL_TO_PMAX, DELTA_P, 100.0); variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalPMax, generatorList); assertEquals(100.0, variationDone, 1e-5); @@ -233,7 +234,7 @@ void testScaleOnGenerators() { // Proportional to the available P ScalingParameters scalingParametersProportionalAvailableP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, true, true, + true, true, VOLUME, true, PROPORTIONAL_TO_DIFF_PMAX_TARGETP, DELTA_P, 100.0); variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalAvailableP, generatorList); assertEquals(100.0, variationDone, 1e-5); @@ -244,7 +245,7 @@ void testScaleOnGenerators() { // Regular distribution ScalingParameters scalingParametersRegular = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, false, true, true, + true, false, VOLUME, true, REGULAR_DISTRIBUTION, TARGET_P, 100.0); variationDone = scaleOnGenerators(network, reporterModel, scalingParametersRegular, generatorList); assertEquals(100.0, variationDone, 1e-5); @@ -255,7 +256,7 @@ void testScaleOnGenerators() { // Error in other cases ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, false, true, true, + true, false, VOLUME, true, PROPORTIONAL_TO_P0, TARGET_P, 100.0); IllegalArgumentException e0 = assertThrows(IllegalArgumentException.class, () -> scaleOnGenerators( network, @@ -273,7 +274,7 @@ void testScaleOnGeneratorsUsedPower() { // Proportional to the used P ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, true, true, + true, true, VOLUME, true, PROPORTIONAL_TO_DIFF_TARGETP_PMIN, DELTA_P, 100.0); variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); assertEquals(100.0, variationDone, 1e-5); @@ -283,6 +284,42 @@ void testScaleOnGeneratorsUsedPower() { reset(); } + @Test + void testScaleOnGeneratorsVentilationPriority() { + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + double variationDone; + + // Proportional to the used P + ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, VENTILATION, true, + PROPORTIONAL_TO_TARGETP, DELTA_P, 200.0); + variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); + assertEquals(200.0 * 0.7, variationDone, 1e-5); + assertEquals(80.0 * (1.0 + 200.0 * 0.7 / 160.0), network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(50.0 * (1.0 + 200.0 * 0.7 / 160.0), network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(30.0 * (1.0 + 200.0 * 0.7 / 160.0), network.getGenerator("g3").getTargetP(), 1e-5); + reset(); + } + + @Test + void testScaleOnGeneratorsStackingUp() { + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + double variationDone; + + // Proportional to the used P + ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, ONESHOT, true, + STACKING_UP, DELTA_P, 100.0); + variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(150.0, network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(80.0, network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(30.0, network.getGenerator("g3").getTargetP(), 1e-5); + reset(); + } + @Test void testScaleOnGeneratorsWithWrongParameter() { ReporterModel reporterModel = new ReporterModel("scaling", "default"); @@ -290,7 +327,7 @@ void testScaleOnGeneratorsWithWrongParameter() { // Set of parameter for loads ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, false, true, true, + true, false, VOLUME, true, REGULAR_DISTRIBUTION, TARGET_P, 100.0); // Error raised @@ -309,7 +346,7 @@ void testScaleOnLoadsWithWrongParameter() { // Set of parameter for loads ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, false, true, true, + true, false, VOLUME, true, REGULAR_DISTRIBUTION, TARGET_P, 100.0); // Error raised @@ -335,7 +372,7 @@ void testScaleOnGeneratorsTargetPowerAtZero() { // Proportional to the used P ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, true, true, + true, true, VOLUME, true, PROPORTIONAL_TO_TARGETP, DELTA_P, 100.0); variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); assertEquals(100.0, variationDone, 1e-5); @@ -358,7 +395,7 @@ void testScaleOnGeneratorsUsedPowerAtZero() { // Proportional to the used P ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, true, true, + true, true, VOLUME, true, PROPORTIONAL_TO_DIFF_TARGETP_PMIN, DELTA_P, 100.0); variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); assertEquals(100.0, variationDone, 1e-5); @@ -381,7 +418,7 @@ void testScaleOnGeneratorsAvailablePowerAtZero() { // Proportional to the used P ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, true, true, + true, true, VOLUME, true, PROPORTIONAL_TO_DIFF_PMAX_TARGETP, DELTA_P, 100.0); variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); assertEquals(0.0, variationDone, 1e-5); @@ -404,7 +441,7 @@ void testScaleOnLoadsP0AtZero() { // Proportional to P0 ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, false, true, true, + true, false, VOLUME, true, PROPORTIONAL_TO_P0, DELTA_P, 100.0); variationDone = scaleOnLoads(network, reporterModel, scalingParametersProportional, loadList); assertEquals(100.0, variationDone, 1e-5); diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java index 6d6359e1726..0807633eac2 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java @@ -20,8 +20,8 @@ import static com.powsybl.iidm.modification.scalable.Scalable.ScalingConvention.*; import static com.powsybl.iidm.modification.scalable.Scalable.getVariationAsked; import static com.powsybl.iidm.modification.scalable.ScalableTestNetwork.createNetwork; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.DELTA_P; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.TARGET_P; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.*; import static org.junit.jupiter.api.Assertions.*; /** @@ -494,7 +494,7 @@ void testProportionalScalableIterativeMode() { assertEquals(70.0, done, 0.0); assertEquals(70.0, network.getGenerator("g1").getTargetP(), 1e-5); - ScalingParameters parameters = new ScalingParameters().setIterative(true); + ScalingParameters parameters = new ScalingParameters().setPriority(VOLUME); reset(); done = Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, s, unknownGenerator)).scale(network, 100.0, parameters); @@ -545,7 +545,7 @@ void testProportionalScaleIterativeThreeSteps() { assertEquals(54, network.getGenerator("g2").getTargetP(), 1e-3); assertEquals(27, network.getGenerator("g3").getTargetP(), 1e-3); - ScalingParameters parameters = new ScalingParameters().setIterative(true); + ScalingParameters parameters = new ScalingParameters().setPriority(VOLUME); reset(); done = Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, g2, g3)).scale(network, 270.0, parameters); @@ -558,7 +558,7 @@ void testProportionalScaleIterativeThreeSteps() { @Test void testScalableReuse() { Scalable scalable = Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, g2, g3)); - ScalingParameters parameters = new ScalingParameters().setIterative(true); + ScalingParameters parameters = new ScalingParameters().setPriority(VOLUME); double done = scalable.scale(network, 270.0, parameters); assertEquals(270.0, done, 0.0); assertEquals(100.0, network.getGenerator("g1").getTargetP(), 1e-3); @@ -578,15 +578,15 @@ void testGetVariationAsked() { assertEquals( 100.0, getVariationAsked(new ScalingParameters() - .setVariationValue(100.0) - .setVariationType(DELTA_P), + .setScalingValue(100.0) + .setScalingType(DELTA_P), new AtomicReference<>(80.0)), 0.0); assertEquals( 20.0, getVariationAsked(new ScalingParameters() - .setVariationValue(100.0) - .setVariationType(TARGET_P), + .setScalingValue(100.0) + .setScalingType(TARGET_P), new AtomicReference<>(80.0)), 0.0); } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java index ad917680032..269d1a28025 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java @@ -18,8 +18,9 @@ import java.nio.file.FileSystem; import static com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode.*; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.DELTA_P; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.VariationType.TARGET_P; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.*; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.TARGET_P; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -47,7 +48,7 @@ void emptyConstructorTest() { ScalingParameters parameters = new ScalingParameters(); assertEquals(ScalingParameters.DEFAULT_SCALING_CONVENTION, parameters.getScalingConvention()); assertEquals(ScalingParameters.DEFAULT_CONSTANT_POWER_FACTOR, parameters.isConstantPowerFactor()); - assertEquals(ScalingParameters.DEFAULT_ITERATIVE, parameters.isIterative()); + assertEquals(ScalingParameters.DEFAULT_PRIORITY, parameters.getPriority()); assertEquals(ScalingParameters.DEFAULT_RECONNECT, parameters.isReconnect()); assertEquals(ScalingParameters.DEFAULT_ALLOWS_GENERATOR_OUT_OF_ACTIVE_POWER_LIMITS, parameters.isAllowsGeneratorOutOfActivePowerLimits()); } @@ -55,10 +56,10 @@ void emptyConstructorTest() { @Test void fullConstructorTest() { ScalingParameters parameters = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, true, true, true); + true, true, VOLUME, true); assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); assertTrue(parameters.isConstantPowerFactor()); - assertTrue(parameters.isIterative()); + assertEquals(VOLUME, parameters.getPriority()); assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); } @@ -66,16 +67,16 @@ void fullConstructorTest() { @Test void fullSecondConstructorTest() { ScalingParameters parameters = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, true, true, true, + true, true, VOLUME, true, PROPORTIONAL_TO_P0, DELTA_P, 100.0); assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); assertTrue(parameters.isConstantPowerFactor()); - assertTrue(parameters.isIterative()); + assertEquals(VOLUME, parameters.getPriority()); assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); assertEquals(PROPORTIONAL_TO_P0, parameters.getDistributionMode()); - assertEquals(DELTA_P, parameters.getVariationType()); - assertEquals(100.0, parameters.getVariationValue(), 0.0); + assertEquals(DELTA_P, parameters.getScalingType()); + assertEquals(100.0, parameters.getScalingValue(), 0.0); } @Test @@ -83,20 +84,20 @@ void settersTest() { ScalingParameters parameters = new ScalingParameters() .setScalingConvention(Scalable.ScalingConvention.LOAD) .setConstantPowerFactor(true) - .setIterative(true) + .setPriority(VOLUME) .setReconnect(true) .setAllowsGeneratorOutOfActivePowerLimits(true) .setDistributionMode(PROPORTIONAL_TO_P0) - .setVariationType(TARGET_P) - .setVariationValue(100.0); + .setScalingType(TARGET_P) + .setScalingValue(100.0); assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); assertTrue(parameters.isConstantPowerFactor()); - assertTrue(parameters.isIterative()); + assertEquals(VOLUME, parameters.getPriority()); assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); assertEquals(PROPORTIONAL_TO_P0, parameters.getDistributionMode()); - assertEquals(TARGET_P, parameters.getVariationType()); - assertEquals(100.0, parameters.getVariationValue(), 0.0); + assertEquals(TARGET_P, parameters.getScalingType()); + assertEquals(100.0, parameters.getScalingValue(), 0.0); } @Test @@ -104,7 +105,7 @@ void loadNoConfigTest() { ScalingParameters parameters = ScalingParameters.load(platformConfig); assertEquals(ScalingParameters.DEFAULT_SCALING_CONVENTION, parameters.getScalingConvention()); assertEquals(ScalingParameters.DEFAULT_CONSTANT_POWER_FACTOR, parameters.isConstantPowerFactor()); - assertEquals(ScalingParameters.DEFAULT_ITERATIVE, parameters.isIterative()); + assertEquals(ScalingParameters.DEFAULT_PRIORITY, parameters.getPriority()); assertEquals(ScalingParameters.DEFAULT_RECONNECT, parameters.isReconnect()); assertEquals(ScalingParameters.DEFAULT_ALLOWS_GENERATOR_OUT_OF_ACTIVE_POWER_LIMITS, parameters.isAllowsGeneratorOutOfActivePowerLimits()); } @@ -114,14 +115,14 @@ void loadConfigTest() { MapModuleConfig moduleConfig = platformConfig.createModuleConfig("scaling-default-parameters"); moduleConfig.setStringProperty("scalingConvention", "LOAD"); moduleConfig.setStringProperty("constantPowerFactor", "true"); - moduleConfig.setStringProperty("iterative", "true"); + moduleConfig.setStringProperty("priority", "VOLUME"); moduleConfig.setStringProperty("reconnect", "true"); moduleConfig.setStringProperty("allowsGeneratorOutOfActivePowerLimits", "true"); ScalingParameters parameters = ScalingParameters.load(platformConfig); assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); assertTrue(parameters.isConstantPowerFactor()); - assertTrue(parameters.isIterative()); + assertEquals(VOLUME, parameters.getPriority()); assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java index ec022178e64..a4e1bbf6671 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java @@ -10,12 +10,12 @@ import com.powsybl.commons.test.AbstractConverterTest; import com.powsybl.iidm.modification.scalable.Scalable; import com.powsybl.iidm.modification.scalable.ScalingParameters; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.io.IOException; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; /** * @author Miora Vedelago @@ -30,6 +30,14 @@ void roundTrip() throws IOException { roundTripTest(parameters, JsonScalingParameters::write, JsonScalingParameters::read, "/json/ScalingParameters.json"); } + @Test + @Disabled("TODO") + void testDeserializerV1dot1() throws IOException { + // TODO + assertTrue(true); +// ScalingParameters scalingParameters = deserialize("/json/ScalingParameters_v1.0.json") + } + @Test void error() throws IOException { try (var is = getClass().getResourceAsStream("/json/ScalingParametersError.json")) { diff --git a/iidm/iidm-modification/src/test/resources/json/ScalingParameters.json b/iidm/iidm-modification/src/test/resources/json/ScalingParameters.json index 9ead88926af..a8f35aa702a 100644 --- a/iidm/iidm-modification/src/test/resources/json/ScalingParameters.json +++ b/iidm/iidm-modification/src/test/resources/json/ScalingParameters.json @@ -1,7 +1,7 @@ { - "version" : "1.0", + "version" : "1.1", "scalingConvention" : "LOAD", "constantPowerFactor" : false, "reconnect" : true, - "iterative" : false + "priority" : "ONESHOT" } \ No newline at end of file diff --git a/iidm/iidm-modification/src/test/resources/json/ScalingParameters_v1.0.json b/iidm/iidm-modification/src/test/resources/json/ScalingParameters_v1.0.json new file mode 100644 index 00000000000..9ead88926af --- /dev/null +++ b/iidm/iidm-modification/src/test/resources/json/ScalingParameters_v1.0.json @@ -0,0 +1,7 @@ +{ + "version" : "1.0", + "scalingConvention" : "LOAD", + "constantPowerFactor" : false, + "reconnect" : true, + "iterative" : false +} \ No newline at end of file From d957c35af1d38e46d4af0c8a4416ef92d7054286 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Wed, 9 Aug 2023 11:00:12 +0200 Subject: [PATCH 06/18] Modified and moved the reporter, added a default value for a parameter, added a test on the depreciated methods Signed-off-by: Nicolas Rol --- .../scalable/ProportionalScalable.java | 6 ++-- .../iidm/modification/scalable/Scalable.java | 29 ++++++------------- .../scalable/ScalingParameters.java | 29 ++++--------------- .../util/ModificationReports.java | 13 +++++++++ .../scalable/ProportionalScalableTest.java | 8 +++-- .../scalable/ScalingParametersTest.java | 10 +++++++ .../json/JsonScalingParametersTest.java | 17 ++++++----- 7 files changed, 56 insertions(+), 56 deletions(-) diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java index 157aa4ec1c3..f3897d465a4 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java @@ -11,7 +11,6 @@ import java.util.*; import java.util.concurrent.atomic.AtomicReference; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode.STACKING_UP; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VENTILATION; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; @@ -165,14 +164,15 @@ private void reinitIterationPercentage() { /** * Compute the power that can be scaled on the network while keeping the ventilation percentages valid. - * This method is only used if the distribution is not STACKING_UP and if the scaling priority is VENTILATION. + * This method is only used if the distribution is not STACKING_UP (cannot happen since it's a + * {@link ProportionalScalable} and if the scaling priority is VENTILATION. * @param asked power that shall be scaled on the network * @param scalingParameters scaling parameters * @param network network on which the scaling shall be done * @return the effective power value that can be safely scaled while keeping the ventilation percentages valid */ double resizeAskedForVentilation(Network network, double asked, ScalingParameters scalingParameters) { - if (scalingParameters.getDistributionMode() != STACKING_UP && scalingParameters.getPriority() == VENTILATION) { + if (scalingParameters.getPriority() == VENTILATION) { AtomicReference resizingPercentage = new AtomicReference<>(1.0); scalablePercentageList.forEach(scalablePercentage -> resizingPercentage.set(Math.min(((GeneratorScalable) scalablePercentage.getScalable()).availablePowerInPercentageOfAsked(network, asked, scalablePercentage.getPercentage()), resizingPercentage.get())) diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java index 7e61b22c589..05086490fe9 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java @@ -7,9 +7,7 @@ package com.powsybl.iidm.modification.scalable; import com.powsybl.commons.PowsyblException; -import com.powsybl.commons.reporter.Report; import com.powsybl.commons.reporter.Reporter; -import com.powsybl.commons.reporter.TypedValue; import com.powsybl.iidm.network.Generator; import com.powsybl.iidm.network.Injection; import com.powsybl.iidm.network.Load; @@ -23,6 +21,7 @@ import java.util.stream.Collectors; import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; +import static com.powsybl.iidm.modification.util.ModificationReports.scalingReport; /** * @author Geoffroy Jamgotchian @@ -252,14 +251,6 @@ static double getVariationAsked(ScalingParameters scalingParameters, AtomicRefer : scalingParameters.getScalingValue() - sum.get(); } - public static void createReport(Reporter reporter, String reporterKey, String message, TypedValue errorSeverity) { - reporter.report(Report.builder() - .withKey(reporterKey) - .withDefaultMessage(message) - .withSeverity(errorSeverity) - .build()); - } - /** * Computes and applies a scaling variation of power on a list of loads, using variation parameters defined by the user. * Depending on the distribution mode chosen, the distribution percentage for each load will be computed differently: @@ -325,11 +316,10 @@ static double scaleOnLoads(Network network, double variationDone = proportionalScalable.scale(network, variationAsked, scalingParameters); // Report - Scalable.createReport(subReporter, - "scalingApplied", - String.format("Successfully scaled on loads using mode %s with a variation value asked of %s. Variation done is %s", - scalingParameters.getDistributionMode(), variationAsked, variationDone), - TypedValue.INFO_SEVERITY); + scalingReport(subReporter, + "loads", + scalingParameters.getDistributionMode(), + variationAsked, variationDone); return variationDone; } @@ -470,11 +460,10 @@ static double scaleOnGenerators(Network network, scalingParameters); // Report - Scalable.createReport(subReporter, - "scalingApplied", - String.format("Successfully scaled on generators using mode %s with a variation value asked of %s. Variation done is %s", - scalingParameters.getDistributionMode(), variationAsked, variationDone), - TypedValue.INFO_SEVERITY); + scalingReport(subReporter, + "generators", + scalingParameters.getDistributionMode(), + variationAsked, variationDone); return variationDone; } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java index f5288442f2f..6766dbba532 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java @@ -13,6 +13,8 @@ import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.ONESHOT; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode.REGULAR_DISTRIBUTION; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; /** * @author Coline Piloquet @@ -47,6 +49,8 @@ public enum Priority { public static final boolean DEFAULT_RECONNECT = false; public static final boolean DEFAULT_ALLOWS_GENERATOR_OUT_OF_ACTIVE_POWER_LIMITS = false; public static final Priority DEFAULT_PRIORITY = ONESHOT; + public static final DistributionMode DEFAULT_DISTRIBUTION_MODE = REGULAR_DISTRIBUTION; + public static final ScalingType DEFAULT_SCALING_TYPE = DELTA_P; private Scalable.ScalingConvention scalingConvention = DEFAULT_SCALING_CONVENTION; @@ -56,8 +60,8 @@ public enum Priority { private boolean allowsGeneratorOutOfActivePowerLimits = DEFAULT_ALLOWS_GENERATOR_OUT_OF_ACTIVE_POWER_LIMITS; - private DistributionMode distributionMode = null; - private ScalingType scalingType = null; + private DistributionMode distributionMode = DEFAULT_DISTRIBUTION_MODE; + private ScalingType scalingType = DEFAULT_SCALING_TYPE; private double scalingValue = 0.0; private Priority priority = DEFAULT_PRIORITY; @@ -87,27 +91,6 @@ public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean r this.allowsGeneratorOutOfActivePowerLimits = allowsGeneratorOutOfActivePowerLimits; } - /** - * @deprecated : replace with (Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, - * Priority priority, boolean allowsGeneratorOutOfActivePowerLimits, - * DistributionMode distributionMode, ScalingType scalingType, - * double scalingValue) - */ - @Deprecated(since = "v6.0.0") - public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, - boolean iterative, boolean allowsGeneratorOutOfActivePowerLimits, - DistributionMode distributionMode, ScalingType scalingType, - double scalingValue) { - this.scalingConvention = scalingConvention; - this.reconnect = reconnect; - this.constantPowerFactor = constantPowerFactor; - this.priority = iterative ? VOLUME : ONESHOT; - this.allowsGeneratorOutOfActivePowerLimits = allowsGeneratorOutOfActivePowerLimits; - this.distributionMode = distributionMode; - this.scalingType = scalingType; - this.scalingValue = scalingValue; - } - public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, Priority priority, boolean allowsGeneratorOutOfActivePowerLimits, DistributionMode distributionMode, ScalingType scalingType, diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java index ef1fb36d1c9..5d797d6104f 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java @@ -9,6 +9,7 @@ import com.powsybl.commons.reporter.Report; import com.powsybl.commons.reporter.Reporter; import com.powsybl.commons.reporter.TypedValue; +import com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode; import com.powsybl.iidm.network.*; /** @@ -618,4 +619,16 @@ public static void undefinedPercent(Reporter reporter) { private ModificationReports() { } + + public static void scalingReport(Reporter reporter, String type, DistributionMode mode, double asked, double done) { + reporter.report(Report.builder() + .withKey("scalingApplied") + .withDefaultMessage("Successfully scaled on ${identifiableType} using mode ${mode} with a variation value asked of ${asked}. Variation done is ${done}") + .withValue(IDENTIFIABLE_TYPE, type) + .withValue("mode", mode.name()) + .withValue("asked", asked) + .withValue("done", done) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java index c1634a322c0..5156a635c5d 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java @@ -1,6 +1,8 @@ -/* - * Copyright (c) 2023. , All partners of the iTesla project (http://www.itesla-project.eu/consortium) - * 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/. +/** + * Copyright (c) 2017, 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.iidm.modification.scalable; diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java index 269d1a28025..f84c71b59cb 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java @@ -126,4 +126,14 @@ void loadConfigTest() { assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); } + + /** + * This test will have to be deleted when the depreciated methods are deleted. + */ + @Test + void depreciatedMethodsTest() { + ScalingParameters parameters = new ScalingParameters() + .setIterative(true); + assertTrue(parameters.isIterative()); + } } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java index a4e1bbf6671..ac3ca5daa24 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java @@ -10,11 +10,12 @@ import com.powsybl.commons.test.AbstractConverterTest; import com.powsybl.iidm.modification.scalable.Scalable; import com.powsybl.iidm.modification.scalable.ScalingParameters; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.io.IOException; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.ONESHOT; +import static com.powsybl.iidm.modification.scalable.json.JsonScalingParameters.read; import static org.junit.jupiter.api.Assertions.*; /** @@ -31,17 +32,19 @@ void roundTrip() throws IOException { } @Test - @Disabled("TODO") - void testDeserializerV1dot1() throws IOException { - // TODO - assertTrue(true); -// ScalingParameters scalingParameters = deserialize("/json/ScalingParameters_v1.0.json") + void testDeserializerV1dot1() { + ScalingParameters parameters = read(getClass().getResourceAsStream("/json/ScalingParameters_v1.0.json")); + assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); + assertFalse(parameters.isConstantPowerFactor()); + assertEquals(ONESHOT, parameters.getPriority()); + assertTrue(parameters.isReconnect()); + assertFalse(parameters.isAllowsGeneratorOutOfActivePowerLimits()); } @Test void error() throws IOException { try (var is = getClass().getResourceAsStream("/json/ScalingParametersError.json")) { - IllegalStateException e = assertThrows(IllegalStateException.class, () -> JsonScalingParameters.read(is)); + IllegalStateException e = assertThrows(IllegalStateException.class, () -> read(is)); assertEquals("Unexpected field: error", e.getMessage()); } } From 4a40f8910d4340464594e0a4053c488ca370c524 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Wed, 9 Aug 2023 11:29:35 +0200 Subject: [PATCH 07/18] Added tests for coverage Signed-off-by: Nicolas Rol --- .../scalable/ScalingParametersTest.java | 15 +++++++++++++-- .../scalable/json/JsonScalingParametersTest.java | 4 ++++ .../resources/json/ScalingParameters_v1.0b.json | 7 +++++++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 iidm/iidm-modification/src/test/resources/json/ScalingParameters_v1.0b.json diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java index f84c71b59cb..892d6ce9dbe 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java @@ -21,8 +21,7 @@ import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.*; import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.TARGET_P; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; /** * @author Miora Vedelago @@ -135,5 +134,17 @@ void depreciatedMethodsTest() { ScalingParameters parameters = new ScalingParameters() .setIterative(true); assertTrue(parameters.isIterative()); + + parameters = new ScalingParameters() + .setIterative(false); + assertFalse(parameters.isIterative()); + + parameters = new ScalingParameters(Scalable.ScalingConvention.LOAD, + true, true, true, true); + assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); + assertTrue(parameters.isConstantPowerFactor()); + assertEquals(VOLUME, parameters.getPriority()); + assertTrue(parameters.isReconnect()); + assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); } } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java index ac3ca5daa24..93b8c4b30e7 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java @@ -15,6 +15,7 @@ import java.io.IOException; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.ONESHOT; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; import static com.powsybl.iidm.modification.scalable.json.JsonScalingParameters.read; import static org.junit.jupiter.api.Assertions.*; @@ -39,6 +40,9 @@ void testDeserializerV1dot1() { assertEquals(ONESHOT, parameters.getPriority()); assertTrue(parameters.isReconnect()); assertFalse(parameters.isAllowsGeneratorOutOfActivePowerLimits()); + + parameters = read(getClass().getResourceAsStream("/json/ScalingParameters_v1.0b.json")); + assertEquals(VOLUME, parameters.getPriority()); } @Test diff --git a/iidm/iidm-modification/src/test/resources/json/ScalingParameters_v1.0b.json b/iidm/iidm-modification/src/test/resources/json/ScalingParameters_v1.0b.json new file mode 100644 index 00000000000..a77cd250021 --- /dev/null +++ b/iidm/iidm-modification/src/test/resources/json/ScalingParameters_v1.0b.json @@ -0,0 +1,7 @@ +{ + "version" : "1.0", + "scalingConvention" : "LOAD", + "constantPowerFactor" : false, + "reconnect" : true, + "iterative" : true +} \ No newline at end of file From f51a09c4645c28365f8514461252c9718cb7afa0 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Wed, 9 Aug 2023 11:51:03 +0200 Subject: [PATCH 08/18] Added tests for coverage Signed-off-by: Nicolas Rol --- .../iidm/modification/scalable/ScalingParametersTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java index 892d6ce9dbe..1a5bd458f66 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java @@ -146,5 +146,13 @@ void depreciatedMethodsTest() { assertEquals(VOLUME, parameters.getPriority()); assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); + + parameters = new ScalingParameters(Scalable.ScalingConvention.LOAD, + true, true, false, true); + assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); + assertTrue(parameters.isConstantPowerFactor()); + assertEquals(ONESHOT, parameters.getPriority()); + assertTrue(parameters.isReconnect()); + assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); } } From 1134ed2960d28b384a3e91c86fb38cd87289a7c0 Mon Sep 17 00:00:00 2001 From: Philippe Edwards Date: Mon, 4 Sep 2023 13:04:05 +0200 Subject: [PATCH 09/18] create proportional and then scale rather than having a method doing both Signed-off-by: Philippe Edwards --- .../scalable/ProportionalScalable.java | 81 +++++- .../iidm/modification/scalable/Scalable.java | 259 +----------------- .../scalable/ScalableAdapter.java | 5 + .../scalable/ScalingParameters.java | 30 +- .../modification/scalable/ScalableTest.java | 19 -- 5 files changed, 95 insertions(+), 299 deletions(-) diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java index f3897d465a4..74100c39452 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java @@ -6,10 +6,12 @@ */ package com.powsybl.iidm.modification.scalable; -import com.powsybl.iidm.network.Network; +import com.powsybl.commons.PowsyblException; +import com.powsybl.iidm.network.*; import java.util.*; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VENTILATION; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; @@ -23,12 +25,20 @@ class ProportionalScalable extends AbstractCompoundScalable { private static final double EPSILON = 1e-2; + public enum DistributionMode { + PROPORTIONAL_TO_PMAX, + PROPORTIONAL_TO_DIFF_PMAX_TARGETP, + PROPORTIONAL_TO_DIFF_TARGETP_PMIN, + PROPORTIONAL_TO_P0, + UNIFORM_DISTRIBUTION + } + static final class ScalablePercentage { private final Scalable scalable; - private final float percentage; + private final double percentage; private double iterationPercentage; - ScalablePercentage(Scalable scalable, float percentage) { + ScalablePercentage(Scalable scalable, double percentage) { this.scalable = scalable; this.percentage = percentage; this.iterationPercentage = percentage; @@ -38,7 +48,7 @@ Scalable getScalable() { return scalable; } - float getPercentage() { + double getPercentage() { return percentage; } @@ -66,7 +76,7 @@ void setIterationPercentage(double iterationPercentage) { this.scalablePercentageList = new ArrayList<>(); } - ProportionalScalable(List percentages, List scalables) { + ProportionalScalable(List percentages, List scalables) { checkPercentages(percentages, scalables); this.scalablePercentageList = new ArrayList<>(); for (int i = 0; i < scalables.size(); i++) { @@ -74,6 +84,63 @@ void setIterationPercentage(double iterationPercentage) { } } + public ProportionalScalable(List injections, DistributionMode distributionMode) { + List injectionScalables = injections.stream().map(ScalableAdapter::new).collect(Collectors.toList()); + double totalDistribution = computeTotalDistribution(injections, distributionMode); + List percentages = injections.stream().map(injection -> getIndividualDistribution(injection, distributionMode) / totalDistribution).toList(); + checkPercentages(percentages, injectionScalables); + this.scalablePercentageList = new ArrayList<>(); + for (int i = 0; i < injectionScalables.size(); i++) { + this.scalablePercentageList.add(new ScalablePercentage(injectionScalables.get(i), percentages.get(i))); + } + } + + private double computeTotalDistribution(List injections, DistributionMode distributionMode) { + return injections.stream().mapToDouble(injection -> getIndividualDistribution(injection, distributionMode)).sum(); + } + + private double getIndividualDistribution(Injection injection, DistributionMode distributionMode) { + return switch (distributionMode) { + case PROPORTIONAL_TO_P0 -> getTargetP(injection); + case PROPORTIONAL_TO_PMAX -> getMaxP(injection); + case PROPORTIONAL_TO_DIFF_PMAX_TARGETP -> getMaxP(injection) - getTargetP(injection); + case PROPORTIONAL_TO_DIFF_TARGETP_PMIN -> getTargetP(injection) - getMinP(injection); + case UNIFORM_DISTRIBUTION -> 1; + }; + } + + private double getTargetP(Injection injection) { + if (injection instanceof Load load) { + return load.getP0(); + } else if (injection instanceof Generator generator) { + return generator.getTargetP(); + } else if (injection instanceof DanglingLine danglingLine) { + return danglingLine.getP0(); + } else { + throw new PowsyblException("Unable to create a scalable from " + injection.getClass()); + } + } + + private double getMaxP(Injection injection) { + if (injection instanceof Generator generator) { + return generator.getMaxP(); + } else if (injection instanceof Load || injection instanceof DanglingLine) { + throw new PowsyblException("Injection types and distribution mode used are incompatible"); + } else { + throw new PowsyblException("Unable to create a scalable from " + injection.getClass()); + } + } + + private double getMinP(Injection injection) { + if (injection instanceof Generator generator) { + return generator.getMinP(); + } else if (injection instanceof Load || injection instanceof DanglingLine) { + throw new PowsyblException("Injection types and distribution mode used are incompatible"); + } else { + throw new PowsyblException("Unable to create a scalable from " + injection.getClass()); + } + } + Collection getScalables() { return scalablePercentageList.stream().map(ScalablePercentage::getScalable).toList(); } @@ -82,7 +149,7 @@ List getScalablePercentageList() { return scalablePercentageList; } - private static void checkPercentages(List percentages, List scalables) { + private static void checkPercentages(List percentages, List scalables) { Objects.requireNonNull(percentages); Objects.requireNonNull(scalables); @@ -92,7 +159,7 @@ private static void checkPercentages(List percentages, List sca if (scalables.isEmpty()) { return; } - if (percentages.stream().anyMatch(p -> Float.isNaN(p))) { + if (percentages.stream().anyMatch(p -> Double.isNaN(p))) { throw new IllegalArgumentException("There is at least one undefined percentage"); } double sum = percentages.stream().mapToDouble(Double::valueOf).sum(); diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java index 05086490fe9..565577d6a68 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java @@ -6,23 +6,14 @@ */ package com.powsybl.iidm.modification.scalable; -import com.powsybl.commons.PowsyblException; -import com.powsybl.commons.reporter.Reporter; -import com.powsybl.iidm.network.Generator; import com.powsybl.iidm.network.Injection; -import com.powsybl.iidm.network.Load; import com.powsybl.iidm.network.Network; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; -import static com.powsybl.iidm.modification.util.ModificationReports.scalingReport; - /** * @author Geoffroy Jamgotchian * @author Ameni Walha @@ -198,34 +189,43 @@ static List scalables(String... ids) { return Arrays.stream(ids).map(ScalableAdapter::new).collect(Collectors.toList()); } - static ProportionalScalable proportional(List percentages, List scalables) { + static ProportionalScalable proportional(List injections, ProportionalScalable.DistributionMode distributionMode) { + return new ProportionalScalable(injections, distributionMode); + } + + static ProportionalScalable proportional(List percentages, List scalables) { return new ProportionalScalable(percentages, scalables); } - static ProportionalScalable proportional(float percentage, Scalable scalable) { + static ProportionalScalable proportional(double percentage, Scalable scalable) { return new ProportionalScalable(Collections.singletonList(percentage), Collections.singletonList(scalable)); } - static ProportionalScalable proportional(float percentage1, Scalable scalable1, float percentage2, Scalable scalable2) { + static ProportionalScalable proportional(double percentage1, Scalable scalable1, double percentage2, Scalable scalable2) { return new ProportionalScalable(Arrays.asList(percentage1, percentage2), Arrays.asList(scalable1, scalable2)); } - static ProportionalScalable proportional(float percentage1, Scalable scalable1, float percentage2, Scalable scalable2, float percentage3, Scalable scalable3) { + static ProportionalScalable proportional(double percentage1, Scalable scalable1, double percentage2, Scalable scalable2, double percentage3, Scalable scalable3) { return new ProportionalScalable(Arrays.asList(percentage1, percentage2, percentage3), Arrays.asList(scalable1, scalable2, scalable3)); } - static ProportionalScalable proportional(float percentage1, Scalable scalable1, float percentage2, Scalable scalable2, float percentage3, Scalable scalable3, float percentage4, Scalable scalable4) { + static ProportionalScalable proportional(double percentage1, Scalable scalable1, double percentage2, Scalable scalable2, double percentage3, Scalable scalable3, double percentage4, Scalable scalable4) { return new ProportionalScalable(Arrays.asList(percentage1, percentage2, percentage3, percentage4), Arrays.asList(scalable1, scalable2, scalable3, scalable4)); } - static ProportionalScalable proportional(float percentage1, Scalable scalable1, float percentage2, Scalable scalable2, float percentage3, Scalable scalable3, float percentage4, Scalable scalable4, float percentage5, Scalable scalable5) { + static ProportionalScalable proportional(double percentage1, Scalable scalable1, double percentage2, Scalable scalable2, double percentage3, Scalable scalable3, double percentage4, Scalable scalable4, double percentage5, Scalable scalable5) { return new ProportionalScalable(Arrays.asList(percentage1, percentage2, percentage3, percentage4, percentage5), Arrays.asList(scalable1, scalable2, scalable3, scalable4, scalable5)); } + static StackScalable stack(Injection... injections) { + List injectionScalables = Arrays.stream(injections).map(ScalableAdapter::new).collect(Collectors.toList()); + return new StackScalable(injectionScalables); + } + static StackScalable stack(Scalable... scalables) { return new StackScalable(scalables); } @@ -238,233 +238,4 @@ static StackScalable stack(String... ids) { static UpDownScalable upDown(Scalable upScalable, Scalable downScalable) { return new UpDownScalable(upScalable, downScalable); } - - /** - * Returns the value that has to be added to the network, depending on the type of variation chosen in the parameters - * @param scalingParameters Scaling parameters including a variation type (DELTA_P or TARGET_P) and a variation value - * @param sum current global value - * @return the variation value if the type is DELTA_P, else the difference between the variation value and the current global value sum - */ - static double getVariationAsked(ScalingParameters scalingParameters, AtomicReference sum) { - return scalingParameters.getScalingType() == DELTA_P - ? scalingParameters.getScalingValue() - : scalingParameters.getScalingValue() - sum.get(); - } - - /** - * Computes and applies a scaling variation of power on a list of loads, using variation parameters defined by the user. - * Depending on the distribution mode chosen, the distribution percentage for each load will be computed differently: - *
    - *
  • PROPORTIONAL_TO_P0: P0 divided by the sum of all the P0
  • - *
  • REGULAR_DISTRIBUTION: 100% divided by the number of loads
  • - *
- * If the global sum computed for the PROPORTIONAL_TO_P0 mode is at zero, the system will default to the REGULAR_DISTRIBUTION mode. - * @param network The network on which the scaling variation is applied - * @param subReporter The reporter - * @param scalingParameters The parameters for the scaling - * @param loads The loads on which the scaling will be done - * @return the value of the power that was finally allocated on the loads - */ - static double scaleOnLoads(Network network, - Reporter subReporter, - ScalingParameters scalingParameters, - Collection loads) { - // Check that scalingParameters is coherent with the type of elements given - if (scalingParameters.getScalingConvention() != ScalingConvention.LOAD) { - throw new PowsyblException(String.format("Scaling convention in the parameters cannot be %s for loads", scalingParameters.getScalingConvention())); - } - - // Initialisation of the ProportionalScalable - ProportionalScalable proportionalScalable = new ProportionalScalable(); - - // Global current value - AtomicReference sumP0 = new AtomicReference<>(0D); - - // The variation mode chosen changes how the percentages are computed - switch (scalingParameters.getDistributionMode()) { - case PROPORTIONAL_TO_P0 -> { - // Proportional to the P0 of the loads - loads.forEach(load -> - sumP0.set(sumP0.get() + load.getP0()) - ); - if (sumP0.get() > 0.0) { - loads.forEach(load -> - proportionalScalable.getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onLoad(load.getId()), (float) (load.getP0() * 100.0 / sumP0.get()))) - ); - } else { - // If no power is currently configured, a regular distribution is used - loads.forEach(load -> { - sumP0.set(sumP0.get() + load.getP0()); - proportionalScalable.getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onLoad(load.getId()), (float) (100.0 / loads.size()))); - }); - } - } - case REGULAR_DISTRIBUTION -> - // Each load get the same - loads.forEach(load -> { - sumP0.set(sumP0.get() + load.getP0()); - proportionalScalable.getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onLoad(load.getId()), (float) (100.0 / loads.size()))); - }); - default -> - throw new IllegalArgumentException(String.format("Variation mode cannot be %s for LoadScalables", scalingParameters.getDistributionMode())); - } - - // Variation asked globally - double variationAsked = Scalable.getVariationAsked(scalingParameters, sumP0); - - // Do the repartition - double variationDone = proportionalScalable.scale(network, variationAsked, scalingParameters); - - // Report - scalingReport(subReporter, - "loads", - scalingParameters.getDistributionMode(), - variationAsked, variationDone); - return variationDone; - } - - /** - * Computes and applies a scaling variation of power on a list of generators, using variation parameters defined by the user. - * Depending on the distribution mode chosen, the distribution percentage for each generator will be computed differently: - *
    - *
  • PROPORTIONAL_TO_TARGETP: targetP divided by the sum of all the targetP
  • - *
  • PROPORTIONAL_TO_PMAX: Pmax divided by the sum of all the Pmax
  • - *
  • PROPORTIONAL_TO_DIFF_PMAX_TARGETP: available power (Pmax - targetP) divided by the sum of all the available power
  • - *
  • PROPORTIONAL_TO_DIFF_TARGETP_PMIN: used power (targetP - Pmin) divided by the sum of all the used power
  • - *
  • REGULAR_DISTRIBUTION: 100% divided by the number of generators
  • - *
  • STACKING_UP: generators are fully powered one after the other until the global power asked is reached
  • - *
- * If the global sum computed for the chosen distribution mode is at zero, the system will default to the REGULAR_DISTRIBUTION mode. - * @param network The network on which the scaling variation is applied - * @param subReporter The reporter - * @param scalingParameters The parameters for the scaling - * @param generators The generators on which the scaling will be done - * @return the value of the power that was finally allocated on the generators - */ - static double scaleOnGenerators(Network network, - Reporter subReporter, - ScalingParameters scalingParameters, - Collection generators) { - // Check that scalingParameters is coherent with the type of elements given - if (scalingParameters.getScalingConvention() != ScalingConvention.GENERATOR) { - throw new PowsyblException(String.format("Scaling convention in the parameters cannot be %s for generators", scalingParameters.getScalingConvention())); - } - - // Initialisation of the ProportionalScalable - Scalable scalable; - - // Global current power - AtomicReference sumTargetP = new AtomicReference<>(0D); - - // The variation mode chosen changes how the percentages are computed - switch (scalingParameters.getDistributionMode()) { - case PROPORTIONAL_TO_TARGETP -> { - // Proportional to the target power of each generator - scalable = new ProportionalScalable(); - generators.forEach(generator -> - sumTargetP.set(sumTargetP.get() + generator.getTargetP()) - ); - if (sumTargetP.get() > 0.0) { - generators.forEach(generator -> - ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getTargetP() * 100.0 / sumTargetP.get())))); - } else { - // If no power is currently configured, a regular distribution is used - generators.forEach(generator -> - ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) - ); - } - } - case PROPORTIONAL_TO_PMAX -> { - // Proportional to the maximal power of each generator - scalable = new ProportionalScalable(); - - // Global max power - AtomicReference sumPMax = new AtomicReference<>(0D); - generators.forEach(generator -> { - sumTargetP.set(sumTargetP.get() + generator.getTargetP()); - sumPMax.set(sumPMax.get() + generator.getMaxP()); - }); - generators.forEach(generator -> - ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (generator.getMaxP() * 100.0 / sumPMax.get())))); - } - case PROPORTIONAL_TO_DIFF_PMAX_TARGETP -> { - // Proportional to the available power (Pmax - targetP) of each generator - scalable = new ProportionalScalable(); - - // Global available power - AtomicReference sumAvailableP = new AtomicReference<>(0D); - generators.forEach(generator -> { - sumTargetP.set(sumTargetP.get() + generator.getTargetP()); - sumAvailableP.set(sumAvailableP.get() + (generator.getMaxP() - generator.getTargetP())); - }); - if (sumAvailableP.get() > 0.0) { - generators.forEach(generator -> - ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getMaxP() - generator.getTargetP()) * 100.0 / sumAvailableP.get())))); - } else { - // If no power is currently available, a regular distribution is used - generators.forEach(generator -> - ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) - ); - } - } - case PROPORTIONAL_TO_DIFF_TARGETP_PMIN -> { - // Proportional to the used power (targetP - Pmin) of each generator - scalable = new ProportionalScalable(); - - // Global used power - AtomicReference sumUsedP = new AtomicReference<>(0D); - generators.forEach(generator -> { - sumTargetP.set(sumTargetP.get() + generator.getTargetP()); - sumUsedP.set(sumUsedP.get() + (generator.getTargetP() - generator.getMinP())); - }); - if (sumUsedP.get() > 0.0) { - generators.forEach(generator -> - ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) ((generator.getTargetP() - generator.getMinP()) * 100.0 / sumUsedP.get())))); - } else { - // If no power is currently used, a regular distribution is used - generators.forEach(generator -> - ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))) - ); - } - } - case REGULAR_DISTRIBUTION -> { - // Each load get the same - scalable = new ProportionalScalable(); - generators.forEach(generator -> { - sumTargetP.set(sumTargetP.get() + generator.getTargetP()); - ((ProportionalScalable) scalable).getScalablePercentageList().add(new ProportionalScalable.ScalablePercentage(Scalable.onGenerator(generator.getId()), (float) (100.0 / generators.size()))); - }); - } - case STACKING_UP -> - // Fully charges generators one after the other until the power asked is reached - scalable = stack(generators.stream().map(generator -> { - sumTargetP.set(sumTargetP.get() + generator.getTargetP()); - return Scalable.onGenerator(generator.getId()); - }).toArray(Scalable[]::new)); - default -> - throw new IllegalArgumentException(String.format("Variation mode cannot be %s for GeneratorScalables", scalingParameters.getDistributionMode())); - } - - // Variation asked globally - double variationAsked = getVariationAsked(scalingParameters, sumTargetP); - - // Adapt the asked value if needed - only useful if using a proportional scalable - if (scalable instanceof ProportionalScalable proportionalScalable) { - variationAsked = proportionalScalable.resizeAskedForVentilation(network, variationAsked, scalingParameters); - } - - // Do the repartition - double variationDone = scalable.scale( - network, - variationAsked, - scalingParameters); - - // Report - scalingReport(subReporter, - "generators", - scalingParameters.getDistributionMode(), - variationAsked, variationDone); - - return variationDone; - } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java index 0c1aa069e9e..2ef4d3cda40 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java @@ -20,6 +20,11 @@ public ScalableAdapter(String id) { this.id = Objects.requireNonNull(id); } + public ScalableAdapter(Injection injection) { + Objects.requireNonNull(injection); + this.id = injection.getId(); + } + private Scalable getScalable(Network n) { Objects.requireNonNull(n); Identifiable identifiable = n.getIdentifiable(id); diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java index 6766dbba532..4da55b1593d 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java @@ -13,7 +13,6 @@ import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.ONESHOT; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode.REGULAR_DISTRIBUTION; import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; /** @@ -23,16 +22,6 @@ public class ScalingParameters { public static final String VERSION = "1.1"; - public enum DistributionMode { - PROPORTIONAL_TO_TARGETP, - PROPORTIONAL_TO_PMAX, - PROPORTIONAL_TO_DIFF_PMAX_TARGETP, - PROPORTIONAL_TO_DIFF_TARGETP_PMIN, - PROPORTIONAL_TO_P0, - REGULAR_DISTRIBUTION, - STACKING_UP - } - public enum ScalingType { DELTA_P, TARGET_P @@ -49,7 +38,6 @@ public enum Priority { public static final boolean DEFAULT_RECONNECT = false; public static final boolean DEFAULT_ALLOWS_GENERATOR_OUT_OF_ACTIVE_POWER_LIMITS = false; public static final Priority DEFAULT_PRIORITY = ONESHOT; - public static final DistributionMode DEFAULT_DISTRIBUTION_MODE = REGULAR_DISTRIBUTION; public static final ScalingType DEFAULT_SCALING_TYPE = DELTA_P; private Scalable.ScalingConvention scalingConvention = DEFAULT_SCALING_CONVENTION; @@ -59,8 +47,6 @@ public enum Priority { private boolean constantPowerFactor = DEFAULT_CONSTANT_POWER_FACTOR; private boolean allowsGeneratorOutOfActivePowerLimits = DEFAULT_ALLOWS_GENERATOR_OUT_OF_ACTIVE_POWER_LIMITS; - - private DistributionMode distributionMode = DEFAULT_DISTRIBUTION_MODE; private ScalingType scalingType = DEFAULT_SCALING_TYPE; private double scalingValue = 0.0; private Priority priority = DEFAULT_PRIORITY; @@ -92,15 +78,13 @@ public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean r } public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, - Priority priority, boolean allowsGeneratorOutOfActivePowerLimits, - DistributionMode distributionMode, ScalingType scalingType, + Priority priority, boolean allowsGeneratorOutOfActivePowerLimits, ScalingType scalingType, double scalingValue) { this.scalingConvention = scalingConvention; this.reconnect = reconnect; this.constantPowerFactor = constantPowerFactor; this.priority = priority; this.allowsGeneratorOutOfActivePowerLimits = allowsGeneratorOutOfActivePowerLimits; - this.distributionMode = distributionMode; this.scalingType = scalingType; this.scalingValue = scalingValue; } @@ -173,18 +157,6 @@ public ScalingParameters setAllowsGeneratorOutOfActivePowerLimits(boolean allows return this; } - /** - * @return the mode of distribution used to allocate the power to the different elements (loads, generators, etc.) - */ - public DistributionMode getDistributionMode() { - return distributionMode; - } - - public ScalingParameters setDistributionMode(DistributionMode distributionMode) { - this.distributionMode = distributionMode; - return this; - } - /** * @return the type of scaling asked (DELTA_P or TARGET_P) */ diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java index 0807633eac2..93018ae552f 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java @@ -18,7 +18,6 @@ import java.util.concurrent.atomic.AtomicReference; import static com.powsybl.iidm.modification.scalable.Scalable.ScalingConvention.*; -import static com.powsybl.iidm.modification.scalable.Scalable.getVariationAsked; import static com.powsybl.iidm.modification.scalable.ScalableTestNetwork.createNetwork; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.*; @@ -572,22 +571,4 @@ void testScalableReuse() { assertEquals(100.0, network.getGenerator("g2").getTargetP(), 1e-3); assertEquals(70.0, network.getGenerator("g3").getTargetP(), 1e-3); } - - @Test - void testGetVariationAsked() { - assertEquals( - 100.0, - getVariationAsked(new ScalingParameters() - .setScalingValue(100.0) - .setScalingType(DELTA_P), - new AtomicReference<>(80.0)), - 0.0); - assertEquals( - 20.0, - getVariationAsked(new ScalingParameters() - .setScalingValue(100.0) - .setScalingType(TARGET_P), - new AtomicReference<>(80.0)), - 0.0); - } } From b3b2489a0d7de56e69546037099fcc021c153a9a Mon Sep 17 00:00:00 2001 From: Philippe Edwards Date: Mon, 4 Sep 2023 13:36:00 +0200 Subject: [PATCH 10/18] removed scalingValue from ScalingParameters Signed-off-by: Philippe Edwards --- .../scalable/ScalingParameters.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java index 4da55b1593d..ca231e1350f 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java @@ -48,7 +48,6 @@ public enum Priority { private boolean allowsGeneratorOutOfActivePowerLimits = DEFAULT_ALLOWS_GENERATOR_OUT_OF_ACTIVE_POWER_LIMITS; private ScalingType scalingType = DEFAULT_SCALING_TYPE; - private double scalingValue = 0.0; private Priority priority = DEFAULT_PRIORITY; public ScalingParameters() { @@ -78,15 +77,13 @@ public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean r } public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean reconnect, boolean constantPowerFactor, - Priority priority, boolean allowsGeneratorOutOfActivePowerLimits, ScalingType scalingType, - double scalingValue) { + Priority priority, boolean allowsGeneratorOutOfActivePowerLimits, ScalingType scalingType) { this.scalingConvention = scalingConvention; this.reconnect = reconnect; this.constantPowerFactor = constantPowerFactor; this.priority = priority; this.allowsGeneratorOutOfActivePowerLimits = allowsGeneratorOutOfActivePowerLimits; this.scalingType = scalingType; - this.scalingValue = scalingValue; } /** @@ -169,18 +166,6 @@ public ScalingParameters setScalingType(ScalingType scalingType) { return this; } - /** - * @return the power value configured for the scaling. - */ - public Double getScalingValue() { - return scalingValue; - } - - public ScalingParameters setScalingValue(double scalingValue) { - this.scalingValue = scalingValue; - return this; - } - /** * @return an enum representing the priority of the scaling. It can be either VOLUME (the scaling will distribute the * power asked as much as possible by iterating if elements get saturated, even if it means not respecting potential From 794eb69a0ec09a2f0c8e56da6e3662e1a37941e8 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 8 Sep 2023 11:37:27 +0200 Subject: [PATCH 11/18] Reorganized code for Scalables Signed-off-by: Nicolas Rol --- .../scalable/GeneratorScalable.java | 27 +- .../scalable/ProportionalScalable.java | 152 ++++-- .../iidm/modification/scalable/Scalable.java | 37 +- .../scalable/ScalableAdapter.java | 24 + .../scalable/ScalingParameters.java | 12 +- .../modification/scalable/StackScalable.java | 8 + .../json/ScalingParametersDeserializer.java | 4 +- .../util/ModificationReports.java | 2 +- .../scalable/ProportionalScalableTest.java | 472 +++++++++--------- .../modification/scalable/ScalableTest.java | 83 ++- .../scalable/ScalableTestNetwork.java | 130 +++++ .../scalable/ScalingParametersTest.java | 29 +- .../scalable/StackScalableTest.java | 96 ++++ .../json/JsonScalingParametersTest.java | 4 +- 14 files changed, 735 insertions(+), 345 deletions(-) create mode 100644 iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java index fdbb23e6d9f..028b6a92941 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java @@ -155,10 +155,31 @@ public double scale(Network n, double asked, ScalingParameters parameters) { return done; } - double availablePowerInPercentageOfAsked(Network network, double asked, double scalingPercentage) { + /** + * Compute the percentage of asked power available for the scale. It takes into account the scaling convention + * specified by the user and the sign of the asked power. + * + * @param network Network on which the scaling is done + * @param asked Asked power (can be positive or negative) + * @param scalingPercentage Percentage of the asked power that shall be distributed to the current injection + * @param scalingConvention Scaling convention (GENERATOR or LOAD) + * @return the percentage of asked power available for the scale on the current injection + */ + double availablePowerInPercentageOfAsked(Network network, double asked, double scalingPercentage, ScalingConvention scalingConvention) { var generator = network.getGenerator(id); - var availablePower = generator.getMaxP() - generator.getTargetP(); + + // In LOAD convention, a positive scale will imply a decrease of generators target power var askedPower = asked * scalingPercentage / 100; - return askedPower > availablePower ? availablePower / askedPower : 100.0; + if (scalingConvention == LOAD) { + askedPower = -askedPower; + } + + if (askedPower >= 0) { + var availablePower = Math.min(generator.getMaxP(), maxValue) - generator.getTargetP(); + return askedPower > availablePower ? availablePower / askedPower : 100.0; + } else { + var availablePower = Math.max(generator.getMinP(), minValue) - generator.getTargetP(); + return askedPower < availablePower ? availablePower / askedPower : 100.0; + } } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java index 74100c39452..c63c63c66f5 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java @@ -13,8 +13,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VENTILATION; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.RESPECT_OF_DISTRIBUTION; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.RESPECT_OF_VOLUME_ASKED; /** * Scalable that divides scale proportionally between multiple scalable. @@ -22,10 +22,13 @@ * @author Geoffroy Jamgotchian {@literal } * @author Sebastien Murgey {@literal } */ -class ProportionalScalable extends AbstractCompoundScalable { +public class ProportionalScalable extends AbstractCompoundScalable { private static final double EPSILON = 1e-2; + private static final String GENERIC_SCALABLE_CLASS_ERROR = "Unable to create a scalable from %s"; + private static final String GENERIC_INCONSISTENCY_ERROR = "Variable %s inconsistent with injection type %s"; public enum DistributionMode { + PROPORTIONAL_TO_TARGETP, PROPORTIONAL_TO_PMAX, PROPORTIONAL_TO_DIFF_PMAX_TARGETP, PROPORTIONAL_TO_DIFF_TARGETP_PMIN, @@ -70,11 +73,7 @@ void setIterationPercentage(double iterationPercentage) { } private final List scalablePercentageList; - - ProportionalScalable() { - // Initialisation if the list - this.scalablePercentageList = new ArrayList<>(); - } + private double currentGlobalPower = 0; ProportionalScalable(List percentages, List scalables) { checkPercentages(percentages, scalables); @@ -84,24 +83,58 @@ void setIterationPercentage(double iterationPercentage) { } } - public ProportionalScalable(List injections, DistributionMode distributionMode) { + public ProportionalScalable(List injections, DistributionMode distributionMode) { + // Create the scalable for each injection List injectionScalables = injections.stream().map(ScalableAdapter::new).collect(Collectors.toList()); + + // Compute the sum of every individual power double totalDistribution = computeTotalDistribution(injections, distributionMode); - List percentages = injections.stream().map(injection -> getIndividualDistribution(injection, distributionMode) / totalDistribution).toList(); + + // Compute the current power value + currentGlobalPower = injections.stream().mapToDouble(Scalable::getCurrentPower).sum(); + + // In some cases, a regular distribution is equivalent to the nominal distribution : + // - PROPORTIONAL_TO_P0 : if no power is currently configured + // - PROPORTIONAL_TO_TARGETP : if no power is currently configured + // - PROPORTIONAL_TO_DIFF_PMAX_TARGETP : if no power is currently available + // - PROPORTIONAL_TO_DIFF_TARGETP_PMIN : if no power is currently used + DistributionMode finalDistributionMode; + double finalTotalDistribution; + if (totalDistribution == 0.0 && + (distributionMode == DistributionMode.PROPORTIONAL_TO_P0 + || distributionMode == DistributionMode.PROPORTIONAL_TO_TARGETP + || distributionMode == DistributionMode.PROPORTIONAL_TO_DIFF_PMAX_TARGETP + || distributionMode == DistributionMode.PROPORTIONAL_TO_DIFF_TARGETP_PMIN)) { + finalDistributionMode = DistributionMode.UNIFORM_DISTRIBUTION; + finalTotalDistribution = computeTotalDistribution(injections, finalDistributionMode); + } else { + finalDistributionMode = distributionMode; + finalTotalDistribution = totalDistribution; + } + + // Compute the percentages for each injection + List percentages = injections.stream().map(injection -> getIndividualDistribution(injection, finalDistributionMode) * 100.0 / finalTotalDistribution).toList(); checkPercentages(percentages, injectionScalables); + + // Create the list of ScalablePercentage this.scalablePercentageList = new ArrayList<>(); for (int i = 0; i < injectionScalables.size(); i++) { this.scalablePercentageList.add(new ScalablePercentage(injectionScalables.get(i), percentages.get(i))); } } - private double computeTotalDistribution(List injections, DistributionMode distributionMode) { + private double computeTotalDistribution(List injections, DistributionMode distributionMode) { return injections.stream().mapToDouble(injection -> getIndividualDistribution(injection, distributionMode)).sum(); } - private double getIndividualDistribution(Injection injection, DistributionMode distributionMode) { + private double getIndividualDistribution(Injection injection, DistributionMode distributionMode) { + // Check the injection type + checkInjectionClass(injection); + + // Get the injection value according to the distribution mode return switch (distributionMode) { - case PROPORTIONAL_TO_P0 -> getTargetP(injection); + case PROPORTIONAL_TO_TARGETP -> getTargetP(injection); + case PROPORTIONAL_TO_P0 -> getP0(injection); case PROPORTIONAL_TO_PMAX -> getMaxP(injection); case PROPORTIONAL_TO_DIFF_PMAX_TARGETP -> getMaxP(injection) - getTargetP(injection); case PROPORTIONAL_TO_DIFF_TARGETP_PMIN -> getTargetP(injection) - getMinP(injection); @@ -109,35 +142,49 @@ private double getIndividualDistribution(Injection injection, DistributionMode d }; } - private double getTargetP(Injection injection) { + private void checkInjectionClass(Injection injection) { + if (!(injection instanceof Generator + || injection instanceof Load + || injection instanceof DanglingLine)) { + throw new PowsyblException(String.format(GENERIC_SCALABLE_CLASS_ERROR, injection.getClass())); + } + } + + private double getTargetP(Injection injection) { + if (injection instanceof Generator generator) { + return generator.getTargetP(); + } else { + throw new PowsyblException(String.format(GENERIC_INCONSISTENCY_ERROR, + "TargetP", injection.getClass())); + } + } + + private double getP0(Injection injection) { if (injection instanceof Load load) { return load.getP0(); - } else if (injection instanceof Generator generator) { - return generator.getTargetP(); } else if (injection instanceof DanglingLine danglingLine) { return danglingLine.getP0(); } else { - throw new PowsyblException("Unable to create a scalable from " + injection.getClass()); + throw new PowsyblException(String.format(GENERIC_INCONSISTENCY_ERROR, + "P0", injection.getClass())); } } - private double getMaxP(Injection injection) { + private double getMaxP(Injection injection) { if (injection instanceof Generator generator) { return generator.getMaxP(); - } else if (injection instanceof Load || injection instanceof DanglingLine) { - throw new PowsyblException("Injection types and distribution mode used are incompatible"); } else { - throw new PowsyblException("Unable to create a scalable from " + injection.getClass()); + throw new PowsyblException(String.format(GENERIC_INCONSISTENCY_ERROR, + "MaxP", injection.getClass())); } } - private double getMinP(Injection injection) { + private double getMinP(Injection injection) { if (injection instanceof Generator generator) { return generator.getMinP(); - } else if (injection instanceof Load || injection instanceof DanglingLine) { - throw new PowsyblException("Injection types and distribution mode used are incompatible"); } else { - throw new PowsyblException("Unable to create a scalable from " + injection.getClass()); + throw new PowsyblException(String.format(GENERIC_INCONSISTENCY_ERROR, + "MinP", injection.getClass())); } } @@ -145,10 +192,6 @@ Collection getScalables() { return scalablePercentageList.stream().map(ScalablePercentage::getScalable).toList(); } - List getScalablePercentageList() { - return scalablePercentageList; - } - private static void checkPercentages(List percentages, List scalables) { Objects.requireNonNull(percentages); Objects.requireNonNull(scalables); @@ -217,11 +260,29 @@ private double scaleIteration(Network n, double asked, ScalingParameters paramet public double scale(Network n, double asked, ScalingParameters parameters) { Objects.requireNonNull(n); Objects.requireNonNull(parameters); + + // Check the coherence of the asked value and the scaling type + checkPositiveAskedWhenTarget(asked, parameters); + + // Variation asked + double variationAsked = Scalable.getVariationAsked(parameters, asked, currentGlobalPower); + + // Adapt the asked value if needed - only used in VENTILATION mode + if (parameters.getPriority() == RESPECT_OF_DISTRIBUTION) { + variationAsked = resizeAskedForVentilation(n, variationAsked, parameters); + } + reinitIterationPercentage(); - if (parameters.getPriority() == VOLUME) { - return iterativeScale(n, asked, parameters); + if (parameters.getPriority() == RESPECT_OF_VOLUME_ASKED) { + return iterativeScale(n, variationAsked, parameters); } else { - return scaleIteration(n, asked, parameters); + return scaleIteration(n, variationAsked, parameters); + } + } + + private void checkPositiveAskedWhenTarget(double asked, ScalingParameters scalingParameters) { + if (asked < 0 && scalingParameters.getScalingType() == ScalingParameters.ScalingType.TARGET_P) { + throw new PowsyblException("The asked power value can only be positive when scaling type is TARGET_P"); } } @@ -234,20 +295,27 @@ private void reinitIterationPercentage() { * This method is only used if the distribution is not STACKING_UP (cannot happen since it's a * {@link ProportionalScalable} and if the scaling priority is VENTILATION. * @param asked power that shall be scaled on the network - * @param scalingParameters scaling parameters * @param network network on which the scaling shall be done * @return the effective power value that can be safely scaled while keeping the ventilation percentages valid */ double resizeAskedForVentilation(Network network, double asked, ScalingParameters scalingParameters) { - if (scalingParameters.getPriority() == VENTILATION) { - AtomicReference resizingPercentage = new AtomicReference<>(1.0); - scalablePercentageList.forEach(scalablePercentage -> - resizingPercentage.set(Math.min(((GeneratorScalable) scalablePercentage.getScalable()).availablePowerInPercentageOfAsked(network, asked, scalablePercentage.getPercentage()), resizingPercentage.get())) - ); - return asked * resizingPercentage.get(); - } else { - return asked; - } + AtomicReference resizingPercentage = new AtomicReference<>(1.0); + scalablePercentageList.forEach(scalablePercentage -> { + if (scalablePercentage.getScalable() instanceof GeneratorScalable generatorScalable) { + resizingPercentage.set(Math.min( + generatorScalable.availablePowerInPercentageOfAsked(network, asked, scalablePercentage.getPercentage(), scalingParameters.getScalingConvention()), + resizingPercentage.get())); + } else if (scalablePercentage.getScalable() instanceof ScalableAdapter scalableAdapter) { + resizingPercentage.set(Math.min( + scalableAdapter.availablePowerInPercentageOfAsked(network, asked, scalablePercentage.getPercentage(), scalingParameters.getScalingConvention()), + resizingPercentage.get())); + } else { + throw new PowsyblException(String.format("VENTILATION mode can only be used with ScalableAdapter, not %s", + scalablePercentage.getScalable().getClass())); + } + } + ); + return asked * resizingPercentage.get(); } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java index 565577d6a68..4ad9aa83fe8 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java @@ -6,14 +6,16 @@ */ package com.powsybl.iidm.modification.scalable; -import com.powsybl.iidm.network.Injection; -import com.powsybl.iidm.network.Network; +import com.powsybl.commons.PowsyblException; +import com.powsybl.iidm.network.*; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; + /** * @author Geoffroy Jamgotchian * @author Ameni Walha @@ -189,7 +191,7 @@ static List scalables(String... ids) { return Arrays.stream(ids).map(ScalableAdapter::new).collect(Collectors.toList()); } - static ProportionalScalable proportional(List injections, ProportionalScalable.DistributionMode distributionMode) { + static ProportionalScalable proportional(List injections, ProportionalScalable.DistributionMode distributionMode) { return new ProportionalScalable(injections, distributionMode); } @@ -226,6 +228,11 @@ static StackScalable stack(Injection... injections) { return new StackScalable(injectionScalables); } + static StackScalable stack(List> injections) { + List injectionScalables = injections.stream().map(ScalableAdapter::new).collect(Collectors.toList()); + return new StackScalable(injectionScalables); + } + static StackScalable stack(Scalable... scalables) { return new StackScalable(scalables); } @@ -238,4 +245,28 @@ static StackScalable stack(String... ids) { static UpDownScalable upDown(Scalable upScalable, Scalable downScalable) { return new UpDownScalable(upScalable, downScalable); } + + /** + * Returns the value that has to be added to the network, depending on the type of variation chosen in the parameters + * @param scalingParameters Scaling parameters including a variation type (DELTA_P or TARGET_P) and a variation value + * @param currentGlobalPower current global power + * @return the variation value if the type is DELTA_P, else the difference between the variation value and the current global value sum + */ + static double getVariationAsked(ScalingParameters scalingParameters, double askedValue, double currentGlobalPower) { + return scalingParameters.getScalingType() == DELTA_P + ? askedValue + : askedValue - currentGlobalPower; + } + + static double getCurrentPower(Injection injection) { + if (injection instanceof Generator generator) { + return generator.getTargetP(); + } else if (injection instanceof Load load ) { + return load.getP0(); + } else if (injection instanceof DanglingLine danglingLine) { + return danglingLine.getP0(); + } else { + throw new PowsyblException(String.format("Unable to create a scalable from %s", injection.getClass())); + } + } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java index 2ef4d3cda40..80984c24b07 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Objects; + class ScalableAdapter extends AbstractScalable { private final String id; @@ -32,6 +33,8 @@ private Scalable getScalable(Network n) { return new GeneratorScalable(id); } else if (identifiable instanceof Load) { return new LoadScalable(id); + } else if (identifiable instanceof DanglingLine) { + return new DanglingLineScalable(id); } else { throw new PowsyblException("Unable to create a scalable from " + identifiable.getClass()); } @@ -66,4 +69,25 @@ public void filterInjections(Network network, List injections, List identifiable = network.getIdentifiable(id); + throw new PowsyblException(String.format("VENTILATION mode can only be used with a Generator, not %s", + identifiable.getClass())); + } + } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java index ca231e1350f..b1e3a775704 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java @@ -12,7 +12,7 @@ import java.util.Objects; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.ONESHOT; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.RESPECT_OF_VOLUME_ASKED; import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; /** @@ -28,8 +28,8 @@ public enum ScalingType { } public enum Priority { - VOLUME, - VENTILATION, + RESPECT_OF_VOLUME_ASKED, + RESPECT_OF_DISTRIBUTION, ONESHOT } @@ -63,7 +63,7 @@ public ScalingParameters(Scalable.ScalingConvention scalingConvention, boolean r this.scalingConvention = scalingConvention; this.reconnect = reconnect; this.constantPowerFactor = constantPowerFactor; - this.priority = iterative ? VOLUME : ONESHOT; + this.priority = iterative ? RESPECT_OF_VOLUME_ASKED : ONESHOT; this.allowsGeneratorOutOfActivePowerLimits = allowsGeneratorOutOfActivePowerLimits; } @@ -131,7 +131,7 @@ public ScalingParameters setConstantPowerFactor(boolean constantPowerFactor) { */ @Deprecated(since = "v6.0.0") public boolean isIterative() { - return priority == VOLUME; + return priority == RESPECT_OF_VOLUME_ASKED; } /** @@ -139,7 +139,7 @@ public boolean isIterative() { */ @Deprecated(since = "v6.0.0") public ScalingParameters setIterative(boolean iterative) { - return iterative ? setPriority(VOLUME) : setPriority(ONESHOT); + return iterative ? setPriority(RESPECT_OF_VOLUME_ASKED) : setPriority(ONESHOT); } /** diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java index 7565e8713f4..b6bd76bd500 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java @@ -6,6 +6,7 @@ */ package com.powsybl.iidm.modification.scalable; +import com.powsybl.commons.PowsyblException; import com.powsybl.iidm.network.Network; import java.util.Arrays; @@ -13,6 +14,8 @@ import java.util.List; import java.util.Objects; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; + /** * @author Geoffroy Jamgotchian */ @@ -38,6 +41,11 @@ Collection getScalables() { public double scale(Network n, double asked, ScalingParameters parameters) { Objects.requireNonNull(n); + // The stacking only works with the DELTA_P ScalingType + if (parameters.getScalingType() != DELTA_P) { + throw new PowsyblException("Stacking only works with DELTA_P ScalingType"); + } + double done = 0; double remaining = asked; for (Scalable scalable : scalables) { diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersDeserializer.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersDeserializer.java index dd1c6d823b5..2826b8997e6 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersDeserializer.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/json/ScalingParametersDeserializer.java @@ -18,7 +18,7 @@ import java.io.IOException; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.ONESHOT; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.RESPECT_OF_VOLUME_ASKED; /** * @author Miora Vedelago @@ -60,7 +60,7 @@ public ScalingParameters deserialize(JsonParser parser, DeserializationContext c case "iterative" -> { JsonUtil.assertLessThanReferenceVersion(CONTEXT_NAME, "Tag: iterative", version, "1.1"); parser.nextToken(); - parameters.setPriority(Boolean.TRUE.equals(parser.readValueAs(Boolean.class)) ? VOLUME : ONESHOT); + parameters.setPriority(Boolean.TRUE.equals(parser.readValueAs(Boolean.class)) ? RESPECT_OF_VOLUME_ASKED : ONESHOT); } case "priority" -> { JsonUtil.assertGreaterOrEqualThanReferenceVersion(CONTEXT_NAME, "Tag: priority", version, "1.1"); diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java index 5d797d6104f..6dadef152f4 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java @@ -9,7 +9,7 @@ import com.powsybl.commons.reporter.Report; import com.powsybl.commons.reporter.Reporter; import com.powsybl.commons.reporter.TypedValue; -import com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode; +import com.powsybl.iidm.modification.scalable.ProportionalScalable.DistributionMode; import com.powsybl.iidm.network.*; /** diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java index 5156a635c5d..4112ed56424 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java @@ -11,17 +11,19 @@ import com.powsybl.commons.reporter.ReporterModel; import com.powsybl.iidm.network.*; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.util.Arrays; +import java.util.Collections; import java.util.List; -import static com.powsybl.iidm.modification.scalable.Scalable.scaleOnGenerators; -import static com.powsybl.iidm.modification.scalable.Scalable.scaleOnLoads; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode.*; +import static com.powsybl.iidm.modification.scalable.ProportionalScalable.DistributionMode.*; +import static com.powsybl.iidm.modification.scalable.ScalableTestNetwork.createNetworkwithDanglingLineAndBattery; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.*; import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.TARGET_P; +import static com.powsybl.iidm.modification.util.ModificationReports.scalingReport; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -44,7 +46,7 @@ class ProportionalScalableTest { @BeforeEach void setUp() { - network = createNetwork(); + network = createNetworkwithDanglingLineAndBattery(); g1 = Scalable.onGenerator("g1"); g2 = Scalable.onGenerator("g2"); g3 = Scalable.onGenerator("g3", -10, 80); @@ -61,103 +63,6 @@ void setUp() { // reset(); } - static Network createNetwork() { - Network network = Network.create("network", "test"); - Substation s = network.newSubstation() - .setId("s") - .setCountry(Country.US) - .add(); - VoltageLevel vl = s.newVoltageLevel() - .setId("vl1") - .setNominalV(380.0) - .setLowVoltageLimit(0.8 * 380.0) - .setHighVoltageLimit(1.2 * 380.0) - .setTopologyKind(TopologyKind.BUS_BREAKER) - .add(); - vl.getBusBreakerView().newBus() - .setId("bus1") - .add(); - vl.newGenerator() - .setId("g1") - .setBus("bus1") - .setConnectableBus("bus1") - .setMinP(0.0) - .setMaxP(150.0) - .setTargetP(80.0) - .setVoltageRegulatorOn(false) - .setTargetQ(0.0) - .add(); - vl.newGenerator() - .setId("g2") - .setBus("bus1") - .setConnectableBus("bus1") - .setMinP(10.0) - .setMaxP(100.0) - .setTargetP(50.0) - .setVoltageRegulatorOn(false) - .setTargetQ(0.0) - .add(); - vl.newGenerator() - .setId("g3") - .setBus("bus1") - .setConnectableBus("bus1") - .setMinP(20.0) - .setMaxP(80.0) - .setTargetP(30.0) - .setVoltageRegulatorOn(true) - .setTargetV(1.0) - .add(); - vl.newLoad() - .setId("l1") - .setBus("bus1") - .setConnectableBus("bus1") - .setP0(100.0) - .setQ0(0.0) - .setLoadType(LoadType.UNDEFINED) - .add(); - vl.newLoad() - .setId("l2") - .setBus("bus1") - .setConnectableBus("bus1") - .setP0(80.0) - .setQ0(0.0) - .setLoadType(LoadType.UNDEFINED) - .add(); - vl.newLoad() - .setId("l3") - .setBus("bus1") - .setConnectableBus("bus1") - .setP0(50.0) - .setQ0(0.0) - .setLoadType(LoadType.UNDEFINED) - .add(); - - VoltageLevel vl2 = s.newVoltageLevel() - .setId("vl2") - .setTopologyKind(TopologyKind.BUS_BREAKER) - .setNominalV(380) - .add(); - vl2.getBusBreakerView().newBus() - .setId("bus2") - .add(); - network.newLine() - .setId("l12") - .setVoltageLevel1("vl1") - .setConnectableBus1("bus1") - .setBus1("bus1") - .setVoltageLevel2("vl2") - .setConnectableBus2("bus2") - .setBus2("bus2") - .setR(1) - .setX(1) - .setG1(0) - .setG2(0) - .setB1(0) - .setB2(0) - .add(); - return network; - } - private void reset() { Scalable.stack(g1, g2, g3).reset(network); @@ -166,57 +71,60 @@ private void reset() { } @Test - void testScaleOnLoads() { - // Parameters + void testOnInjections() { ReporterModel reporterModel = new ReporterModel("scaling", "default"); - List loadList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getLoad("l3")); + List> injectionsList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getDanglingLine("dl1")); + ProportionalScalable proportionalScalable; double variationDone; + // Proportional to P0 ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, true, VOLUME, true, - PROPORTIONAL_TO_P0, DELTA_P, 100.0); - variationDone = scaleOnLoads(network, reporterModel, scalingParametersProportional, loadList); + true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P); + proportionalScalable = Scalable.proportional(injectionsList, PROPORTIONAL_TO_P0); + variationDone = proportionalScalable.scale(network, 100.0, scalingParametersProportional); + scalingReport(reporterModel, + "loads and dangling lines", + PROPORTIONAL_TO_P0, + 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(100.0 * (1.0 + 100 / 230.0), network.getLoad("l1").getP0(), 1e-5); assertEquals(80 * (1.0 + 100 / 230.0), network.getLoad("l2").getP0(), 1e-5); - assertEquals(50.0 * (1.0 + 100 / 230.0), network.getLoad("l3").getP0(), 1e-5); + assertEquals(50.0 * (1.0 + 100 / 230.0), network.getDanglingLine("dl1").getP0(), 1e-5); reset(); // Regular distribution - ScalingParameters scalingParametersRegular = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, false, VOLUME, true, - REGULAR_DISTRIBUTION, TARGET_P, 100.0); - variationDone = scaleOnLoads(network, reporterModel, scalingParametersRegular, loadList); + ScalingParameters scalingParametersUniform = new ScalingParameters(Scalable.ScalingConvention.LOAD, + true, false, RESPECT_OF_VOLUME_ASKED, true, DELTA_P); + proportionalScalable = Scalable.proportional(injectionsList, UNIFORM_DISTRIBUTION); + variationDone = proportionalScalable.scale(network, 100.0, scalingParametersUniform); + scalingReport(reporterModel, + "loads and dangling lines", + UNIFORM_DISTRIBUTION, + 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(100.0 / 3.0, network.getLoad("l1").getP0(), 1e-5); assertEquals(100.0 / 3.0, network.getLoad("l2").getP0(), 1e-5); - assertEquals(100.0 / 3.0, network.getLoad("l3").getP0(), 1e-5); + assertEquals(100.0 / 3.0, network.getDanglingLine("dl1").getP0(), 1e-5); reset(); - - // Error in other cases - ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, false, VOLUME, true, - PROPORTIONAL_TO_PMAX, TARGET_P, 100.0); - IllegalArgumentException e0 = assertThrows(IllegalArgumentException.class, () -> scaleOnLoads( - network, - reporterModel, - scalingParametersError, - loadList)); - assertEquals("Variation mode cannot be PROPORTIONAL_TO_PMAX for LoadScalables", e0.getMessage()); } @Test - void testScaleOnGenerators() { + void testOnGenerator() { ReporterModel reporterModel = new ReporterModel("scaling", "default"); List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P); + ProportionalScalable proportionalScalable; double variationDone; // Proportional to Target P - ScalingParameters scalingParametersProportionalTarget = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, VOLUME, true, - PROPORTIONAL_TO_TARGETP, DELTA_P, 100.0); - variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalTarget, generatorList); + proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_TARGETP); + variationDone = proportionalScalable.scale(network, 100.0, scalingParameters); + scalingReport(reporterModel, + "generators", + PROPORTIONAL_TO_TARGETP, + 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(80.0 * (1.0 + 100 / 160.0), network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(50.0 * (1.0 + 100 / 160.0), network.getGenerator("g2").getTargetP(), 1e-5); @@ -224,10 +132,12 @@ void testScaleOnGenerators() { reset(); // Proportional to P_max - ScalingParameters scalingParametersProportionalPMax = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, VOLUME, true, - PROPORTIONAL_TO_PMAX, DELTA_P, 100.0); - variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalPMax, generatorList); + proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_PMAX); + variationDone = proportionalScalable.scale(network, 100.0, scalingParameters); + scalingReport(reporterModel, + "generators", + PROPORTIONAL_TO_PMAX, + 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(150.0 * 100.0 / 330.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(100.0 * 100.0 / 330.0, network.getGenerator("g2").getTargetP(), 1e-5); @@ -235,68 +145,94 @@ void testScaleOnGenerators() { reset(); // Proportional to the available P - ScalingParameters scalingParametersProportionalAvailableP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, VOLUME, true, - PROPORTIONAL_TO_DIFF_PMAX_TARGETP, DELTA_P, 100.0); - variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalAvailableP, generatorList); + proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_DIFF_PMAX_TARGETP); + variationDone = proportionalScalable.scale(network, 100.0, scalingParameters); + scalingReport(reporterModel, + "generators", + PROPORTIONAL_TO_DIFF_PMAX_TARGETP, + 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(150.0 * 100.0 / 330.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(100.0 * 100.0 / 330.0, network.getGenerator("g2").getTargetP(), 1e-5); assertEquals(80.0 * 100.0 / 330.0, network.getGenerator("g3").getTargetP(), 1e-5); reset(); - // Regular distribution - ScalingParameters scalingParametersRegular = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, false, VOLUME, true, - REGULAR_DISTRIBUTION, TARGET_P, 100.0); - variationDone = scaleOnGenerators(network, reporterModel, scalingParametersRegular, generatorList); + // Uniform distribution + proportionalScalable = Scalable.proportional(generatorList, UNIFORM_DISTRIBUTION); + variationDone = proportionalScalable.scale(network, 100.0, scalingParameters); + scalingReport(reporterModel, + "generators", + UNIFORM_DISTRIBUTION, + 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(100.0 / 3.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(100.0 / 3.0, network.getGenerator("g2").getTargetP(), 1e-5); assertEquals(100.0 / 3.0, network.getGenerator("g3").getTargetP(), 1e-5); reset(); - - // Error in other cases - ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, false, VOLUME, true, - PROPORTIONAL_TO_P0, TARGET_P, 100.0); - IllegalArgumentException e0 = assertThrows(IllegalArgumentException.class, () -> scaleOnGenerators( - network, - reporterModel, - scalingParametersError, - generatorList)); - assertEquals("Variation mode cannot be PROPORTIONAL_TO_P0 for GeneratorScalables", e0.getMessage()); } @Test void testScaleOnGeneratorsUsedPower() { ReporterModel reporterModel = new ReporterModel("scaling", "default"); List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P); + ProportionalScalable proportionalScalable; double variationDone; - // Proportional to the used P - ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, VOLUME, true, - PROPORTIONAL_TO_DIFF_TARGETP_PMIN, DELTA_P, 100.0); - variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); + // Proportional to Target P + proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_DIFF_TARGETP_PMIN); + variationDone = proportionalScalable.scale(network, 100.0, scalingParameters); assertEquals(100.0, variationDone, 1e-5); + scalingReport(reporterModel, + "generators", + PROPORTIONAL_TO_DIFF_TARGETP_PMIN, + 100.0, variationDone); assertEquals(80.0 + 80.0 * 100 / 130.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(50.0 + 40.0 * 100 / 130.0, network.getGenerator("g2").getTargetP(), 1e-5); assertEquals(30.0 + 10.0 * 100 / 130.0, network.getGenerator("g3").getTargetP(), 1e-5); reset(); } + @Test + void testScaleOnGeneratorsWithTargetPScalingType() { + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, RESPECT_OF_VOLUME_ASKED, true, TARGET_P); + ProportionalScalable proportionalScalable; + double variationDone; + + // Proportional to Target P + proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_TARGETP); + variationDone = proportionalScalable.scale(network, 260.0, scalingParameters); + scalingReport(reporterModel, + "generators", + PROPORTIONAL_TO_TARGETP, + 260.0, variationDone); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(80.0 * (1.0 + 100 / 160.0), network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(50.0 * (1.0 + 100 / 160.0), network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(30.0 * (1.0 + 100 / 160.0), network.getGenerator("g3").getTargetP(), 1e-5); + reset(); + } + @Test void testScaleOnGeneratorsVentilationPriority() { ReporterModel reporterModel = new ReporterModel("scaling", "default"); List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, RESPECT_OF_DISTRIBUTION, true, DELTA_P); + ProportionalScalable proportionalScalable; double variationDone; - // Proportional to the used P - ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, VENTILATION, true, - PROPORTIONAL_TO_TARGETP, DELTA_P, 200.0); - variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); + // Proportional to Target P + proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_TARGETP); + variationDone = proportionalScalable.scale(network, 200.0, scalingParameters); + scalingReport(reporterModel, + "generators", + PROPORTIONAL_TO_TARGETP, + 200.0, variationDone); assertEquals(200.0 * 0.7, variationDone, 1e-5); assertEquals(80.0 * (1.0 + 200.0 * 0.7 / 160.0), network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(50.0 * (1.0 + 200.0 * 0.7 / 160.0), network.getGenerator("g2").getTargetP(), 1e-5); @@ -305,59 +241,91 @@ void testScaleOnGeneratorsVentilationPriority() { } @Test - void testScaleOnGeneratorsStackingUp() { - ReporterModel reporterModel = new ReporterModel("scaling", "default"); - List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); - double variationDone; + void testScaleOnLoadsVentilationPriority() { + List loadList = Collections.singletonList(network.getLoad("l1")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, RESPECT_OF_DISTRIBUTION, true, DELTA_P); + ProportionalScalable proportionalScalable; - // Proportional to the used P - ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, ONESHOT, true, - STACKING_UP, DELTA_P, 100.0); - variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); - assertEquals(100.0, variationDone, 1e-5); - assertEquals(150.0, network.getGenerator("g1").getTargetP(), 1e-5); - assertEquals(80.0, network.getGenerator("g2").getTargetP(), 1e-5); - assertEquals(30.0, network.getGenerator("g3").getTargetP(), 1e-5); + // Proportional to Target P + proportionalScalable = Scalable.proportional(loadList, PROPORTIONAL_TO_P0); + + // Error raised + PowsyblException e0 = assertThrows(PowsyblException.class, () -> proportionalScalable.scale(network, 100.0, scalingParameters)); + assertEquals("VENTILATION mode can only be used with a Generator, not class com.powsybl.iidm.network.impl.LoadImpl", e0.getMessage()); reset(); } @Test - void testScaleOnGeneratorsWithWrongParameter() { - ReporterModel reporterModel = new ReporterModel("scaling", "default"); - List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + void testScaleOnGeneratorsWithWrongParametersTargetP() { + List danglinglineList = Collections.singletonList(network.getDanglingLine("dl1")); + List loadList = Collections.singletonList(network.getLoad("l1")); + List batteryList = Collections.singletonList(network.getBattery("BAT")); + + // Error raised + PowsyblException e0 = assertThrows(PowsyblException.class, () -> Scalable.proportional(danglinglineList, PROPORTIONAL_TO_TARGETP)); + assertEquals("Variable TargetP inconsistent with injection type class com.powsybl.iidm.network.impl.DanglingLineImpl", e0.getMessage()); - // Set of parameter for loads - ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, false, VOLUME, true, - REGULAR_DISTRIBUTION, TARGET_P, 100.0); + // Error raised + PowsyblException e1 = assertThrows(PowsyblException.class, () -> Scalable.proportional(loadList, PROPORTIONAL_TO_TARGETP)); + assertEquals("Variable TargetP inconsistent with injection type class com.powsybl.iidm.network.impl.LoadImpl", e1.getMessage()); // Error raised - PowsyblException e0 = assertThrows(PowsyblException.class, () -> scaleOnGenerators( - network, - reporterModel, - scalingParametersError, - generatorList)); - assertEquals("Scaling convention in the parameters cannot be LOAD for generators", e0.getMessage()); + PowsyblException e2 = assertThrows(PowsyblException.class, () -> Scalable.proportional(batteryList, PROPORTIONAL_TO_TARGETP)); + assertEquals("Unable to create a scalable from class com.powsybl.iidm.network.impl.BatteryImpl", e2.getMessage()); } @Test - void testScaleOnLoadsWithWrongParameter() { - ReporterModel reporterModel = new ReporterModel("scaling", "default"); - List loadList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getLoad("l3")); + void testScaleOnGeneratorsWithWrongParametersMaxP() { + List danglinglineList = Collections.singletonList(network.getDanglingLine("dl1")); + List loadList = Collections.singletonList(network.getLoad("l1")); + List batteryList = Collections.singletonList(network.getBattery("BAT")); + + // Error raised + PowsyblException e0 = assertThrows(PowsyblException.class, () -> Scalable.proportional(danglinglineList, PROPORTIONAL_TO_PMAX)); + assertEquals("Variable MaxP inconsistent with injection type class com.powsybl.iidm.network.impl.DanglingLineImpl", e0.getMessage()); - // Set of parameter for loads - ScalingParameters scalingParametersError = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, false, VOLUME, true, - REGULAR_DISTRIBUTION, TARGET_P, 100.0); + // Error raised + PowsyblException e1 = assertThrows(PowsyblException.class, () -> Scalable.proportional(loadList, PROPORTIONAL_TO_PMAX)); + assertEquals("Variable MaxP inconsistent with injection type class com.powsybl.iidm.network.impl.LoadImpl", e1.getMessage()); + + // Error raised + PowsyblException e2 = assertThrows(PowsyblException.class, () -> Scalable.proportional(batteryList, PROPORTIONAL_TO_PMAX)); + assertEquals("Unable to create a scalable from class com.powsybl.iidm.network.impl.BatteryImpl", e2.getMessage()); + } + + @Test + @Disabled("Error is raised on TargetP before being raised on MinP") + void testScaleOnGeneratorsWithWrongParametersMinP() { + List danglinglineList = Collections.singletonList(network.getDanglingLine("dl1")); + List loadList = Collections.singletonList(network.getLoad("l1")); + List batteryList = Collections.singletonList(network.getBattery("BAT")); + + // Error raised + PowsyblException e0 = assertThrows(PowsyblException.class, () -> Scalable.proportional(danglinglineList, PROPORTIONAL_TO_DIFF_TARGETP_PMIN)); + assertEquals("Variable MinP inconsistent with injection type class com.powsybl.iidm.network.impl.DanglingLineImpl", e0.getMessage()); + + // Error raised + PowsyblException e1 = assertThrows(PowsyblException.class, () -> Scalable.proportional(loadList, PROPORTIONAL_TO_DIFF_TARGETP_PMIN)); + assertEquals("Variable MinP inconsistent with injection type class com.powsybl.iidm.network.impl.LoadImpl", e1.getMessage()); // Error raised - PowsyblException e0 = assertThrows(PowsyblException.class, () -> scaleOnLoads( - network, - reporterModel, - scalingParametersError, - loadList)); - assertEquals("Scaling convention in the parameters cannot be GENERATOR for loads", e0.getMessage()); + PowsyblException e2 = assertThrows(PowsyblException.class, () -> Scalable.proportional(batteryList, PROPORTIONAL_TO_DIFF_TARGETP_PMIN)); + assertEquals("Unable to create a scalable from class com.powsybl.iidm.network.impl.BatteryImpl", e2.getMessage()); + } + + @Test + void testScaleOnLoadsWithWrongParameters() { + List generatorList = Collections.singletonList(network.getGenerator("g1")); + List batteryList = Collections.singletonList(network.getBattery("BAT")); + + // Error raised + PowsyblException e0 = assertThrows(PowsyblException.class, () -> Scalable.proportional(generatorList, PROPORTIONAL_TO_P0)); + assertEquals("Variable P0 inconsistent with injection type class com.powsybl.iidm.network.impl.GeneratorImpl", e0.getMessage()); + + // Error raised + PowsyblException e2 = assertThrows(PowsyblException.class, () -> Scalable.proportional(batteryList, PROPORTIONAL_TO_P0)); + assertEquals("Unable to create a scalable from class com.powsybl.iidm.network.impl.BatteryImpl", e2.getMessage()); } @Test @@ -367,20 +335,25 @@ void testScaleOnGeneratorsTargetPowerAtZero() { network.getGenerator("g2").setTargetP(0.0); network.getGenerator("g3").setTargetP(0.0); - // Parameters ReporterModel reporterModel = new ReporterModel("scaling", "default"); List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P); + ProportionalScalable proportionalScalable; double variationDone; - // Proportional to the used P - ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, VOLUME, true, - PROPORTIONAL_TO_TARGETP, DELTA_P, 100.0); - variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); + // Proportional to Target P + proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_TARGETP); + variationDone = proportionalScalable.scale(network, 100.0, scalingParameters); + scalingReport(reporterModel, + "generators", + PROPORTIONAL_TO_TARGETP, + 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(0.0 + 100.0 / 3.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(0.0 + 100.0 / 3.0, network.getGenerator("g2").getTargetP(), 1e-5); assertEquals(0.0 + 100.0 / 3.0, network.getGenerator("g3").getTargetP(), 1e-5); + reset(); } @Test @@ -390,20 +363,25 @@ void testScaleOnGeneratorsUsedPowerAtZero() { network.getGenerator("g2").setTargetP(network.getGenerator("g2").getMinP()); network.getGenerator("g3").setTargetP(network.getGenerator("g3").getMinP()); - // Parameters ReporterModel reporterModel = new ReporterModel("scaling", "default"); List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P); + ProportionalScalable proportionalScalable; double variationDone; - // Proportional to the used P - ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, VOLUME, true, - PROPORTIONAL_TO_DIFF_TARGETP_PMIN, DELTA_P, 100.0); - variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); + // Proportional to Target P + proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_DIFF_TARGETP_PMIN); + variationDone = proportionalScalable.scale(network, 100.0, scalingParameters); + scalingReport(reporterModel, + "generators", + PROPORTIONAL_TO_DIFF_TARGETP_PMIN, + 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(0.0 + 100.0 / 3.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(10.0 + 100.0 / 3.0, network.getGenerator("g2").getTargetP(), 1e-5); assertEquals(20.0 + 100.0 / 3.0, network.getGenerator("g3").getTargetP(), 1e-5); + reset(); } @Test @@ -413,20 +391,25 @@ void testScaleOnGeneratorsAvailablePowerAtZero() { network.getGenerator("g2").setTargetP(network.getGenerator("g2").getMaxP()); network.getGenerator("g3").setTargetP(network.getGenerator("g3").getMaxP()); - // Parameters ReporterModel reporterModel = new ReporterModel("scaling", "default"); List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P); + ProportionalScalable proportionalScalable; double variationDone; - // Proportional to the used P - ScalingParameters scalingParametersProportionalUsedP = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, - true, true, VOLUME, true, - PROPORTIONAL_TO_DIFF_PMAX_TARGETP, DELTA_P, 100.0); - variationDone = scaleOnGenerators(network, reporterModel, scalingParametersProportionalUsedP, generatorList); + // Proportional to Target P + proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_DIFF_TARGETP_PMIN); + variationDone = proportionalScalable.scale(network, 100.0, scalingParameters); + scalingReport(reporterModel, + "generators", + PROPORTIONAL_TO_DIFF_TARGETP_PMIN, + 100.0, variationDone); assertEquals(0.0, variationDone, 1e-5); assertEquals(150.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(100.0, network.getGenerator("g2").getTargetP(), 1e-5); assertEquals(80.0, network.getGenerator("g3").getTargetP(), 1e-5); + reset(); } @Test @@ -436,20 +419,59 @@ void testScaleOnLoadsP0AtZero() { network.getLoad("l2").setP0(0.0); network.getLoad("l3").setP0(0.0); - // Parameters - ReporterModel reporterModel = new ReporterModel("scaling", "default"); List loadList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getLoad("l3")); + ProportionalScalable proportionalScalable; double variationDone; // Proportional to P0 ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, false, VOLUME, true, - PROPORTIONAL_TO_P0, DELTA_P, 100.0); - variationDone = scaleOnLoads(network, reporterModel, scalingParametersProportional, loadList); + true, false, RESPECT_OF_VOLUME_ASKED, true, DELTA_P); + proportionalScalable = Scalable.proportional(loadList, PROPORTIONAL_TO_P0); + variationDone = proportionalScalable.scale(network, 100.0, scalingParametersProportional); assertEquals(100.0, variationDone, 1e-5); assertEquals(100.0 / 3.0, network.getLoad("l1").getP0(), 1e-5); assertEquals(100.0 / 3.0, network.getLoad("l2").getP0(), 1e-5); assertEquals(100.0 / 3.0, network.getLoad("l3").getP0(), 1e-5); reset(); } + + @Test + void testResizeAskedForVentilation() { + + // Proportional to Target P + ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD, + true, false, RESPECT_OF_DISTRIBUTION, true, DELTA_P); + + // Works for generators in load convention + List generatorList = Collections.singletonList(network.getGenerator("g1")); + ProportionalScalable proportionalGeneratorsScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_TARGETP); + double variationDone = proportionalGeneratorsScalable.scale(network, 100.0, scalingParametersProportional); + assertEquals(80.0, variationDone, 1e-5); + assertEquals(0.0, network.getGenerator("g1").getTargetP(), 1e-5); + reset(); + + // Works for generators in load convention with negative asked value + variationDone = proportionalGeneratorsScalable.scale(network, -200.0, scalingParametersProportional); + assertEquals(-150.0, variationDone, 1e-5); + assertEquals(150.0, network.getGenerator("g1").getTargetP(), 1e-5); + reset(); + + // Works for GeneratorScalable + proportionalGeneratorsScalable = Scalable.proportional(100.0, g1); + variationDone = proportionalGeneratorsScalable.scale(network, -200.0, scalingParametersProportional); + assertEquals(-150.0, variationDone, 1e-5); + assertEquals(150.0, network.getGenerator("g1").getTargetP(), 1e-5); + reset(); + + // Error raised for LoadScalable + ProportionalScalable proportionalLoadScalable = Scalable.proportional(100.0, l1); + PowsyblException e0 = assertThrows(PowsyblException.class, () -> proportionalLoadScalable.scale(network, 100.0, scalingParametersProportional)); + assertEquals("VENTILATION mode can only be used with ScalableAdapter, not class com.powsybl.iidm.modification.scalable.LoadScalable", e0.getMessage()); + + // Error raised for Loads + List loadList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getLoad("l3")); + ProportionalScalable proportionalScalable = Scalable.proportional(loadList, PROPORTIONAL_TO_P0); + PowsyblException e1 = assertThrows(PowsyblException.class, () -> proportionalScalable.scale(network, 100.0, scalingParametersProportional)); + assertEquals("VENTILATION mode can only be used with a Generator, not class com.powsybl.iidm.network.impl.LoadImpl", e1.getMessage()); + } } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java index 93018ae552f..f7721760e19 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTest.java @@ -15,12 +15,10 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; import static com.powsybl.iidm.modification.scalable.Scalable.ScalingConvention.*; import static com.powsybl.iidm.modification.scalable.ScalableTestNetwork.createNetwork; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.*; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.RESPECT_OF_VOLUME_ASKED; import static org.junit.jupiter.api.Assertions.*; /** @@ -83,13 +81,13 @@ void testInitialValue() { assertEquals(0.0, s.initialValue(network), 0.0); - assertEquals(0., Scalable.proportional(Arrays.asList(70.f, 30.f), Arrays.asList(g1, l1)).initialValue(network), 1e-3); + assertEquals(0., Scalable.proportional(Arrays.asList(70.0, 30.0), Arrays.asList(g1, l1)).initialValue(network), 1e-3); - testInvalidProportionalScalable(Collections.singletonList(100.0f), Collections.emptyList()); - testInvalidProportionalScalable(Arrays.asList(70.f, 20.f), Arrays.asList(g1, l1)); + testInvalidProportionalScalable(Collections.singletonList(100.0), Collections.emptyList()); + testInvalidProportionalScalable(Arrays.asList(70.0, 20.0), Arrays.asList(g1, l1)); } - private void testInvalidProportionalScalable(List percentages, List scalables) { + private void testInvalidProportionalScalable(List percentages, List scalables) { try { Scalable.proportional(percentages, scalables); fail(); @@ -114,8 +112,8 @@ void testMaximumValue() { assertEquals(80, Scalable.stack(g1, l1, l2).maximumValue(network), 0.0); //test ProportionalScalable - assertEquals(280, Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, g2, g3)).maximumValue(network), 1e-3); - assertEquals(80, Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, l1, l2)).maximumValue(network), 1e-3); + assertEquals(280, Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, g2, g3)).maximumValue(network), 1e-3); + assertEquals(80, Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, l1, l2)).maximumValue(network), 1e-3); } @Test @@ -134,8 +132,8 @@ void testMaximumValueLoadConvention() { assertEquals(Double.MAX_VALUE, Scalable.stack(g1, l1, l2).maximumValue(network, convention), 0.0); //test ProportionalScalable - assertEquals(0, Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, g2, g3)).maximumValue(network, convention), 1e-3); - assertEquals(Double.MAX_VALUE, Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, l1, l2)).maximumValue(network, convention), 1e-3); + assertEquals(0, Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, g2, g3)).maximumValue(network, convention), 1e-3); + assertEquals(Double.MAX_VALUE, Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, l1, l2)).maximumValue(network, convention), 1e-3); } @Test @@ -154,8 +152,8 @@ void testMinimumValue() { assertEquals(-Double.MAX_VALUE, Scalable.stack(g1, l1, l2).minimumValue(network), 0.0); //test ProportionalScalable - assertEquals(0., Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, g2, g3)).minimumValue(network), 1e-3); - assertEquals(-Double.MAX_VALUE, Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, l1, l2)).minimumValue(network), 1e-3); + assertEquals(0., Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, g2, g3)).minimumValue(network), 1e-3); + assertEquals(-Double.MAX_VALUE, Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, l1, l2)).minimumValue(network), 1e-3); } @Test @@ -174,13 +172,13 @@ void testMinimumValueLoadConvention() { assertEquals(-80, Scalable.stack(g1, l1, l2).minimumValue(network, convention), 0.0); //test ProportionalScalable - assertEquals(-280., Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, g2, g3)).minimumValue(network, convention), 1e-3); - assertEquals(-80, Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, l1, l2)).minimumValue(network, convention), 1e-3); + assertEquals(-280., Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, g2, g3)).minimumValue(network, convention), 1e-3); + assertEquals(-80, Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, l1, l2)).minimumValue(network, convention), 1e-3); } @Test void testProportionalScalableGenerator() { - double done = Scalable.proportional(Arrays.asList(70.f, 30.f), Arrays.asList(g1, g2)).scale(network, 100.0); + double done = Scalable.proportional(Arrays.asList(70.0, 30.0), Arrays.asList(g1, g2)).scale(network, 100.0); assertEquals(100.0, done, 0.0); assertEquals(70.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(30.0, network.getGenerator("g2").getTargetP(), 1e-5); @@ -219,7 +217,7 @@ void testProportionalScalableGenerator() { assertEquals(100.0, network.getGenerator("g1").getTargetP(), 0.0); reset(); - done = Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, s, unknownGenerator)).scale(network, 100.0); + done = Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, s, unknownGenerator)).scale(network, 100.0); assertEquals(70.0, done, 0.0); assertEquals(70.0, network.getGenerator("g1").getTargetP(), 1e-5); } @@ -228,25 +226,25 @@ void testProportionalScalableGenerator() { void testProportionalScale() { //By default, ScalingConvention.GENERATOR reset(); - double done = Scalable.proportional(Arrays.asList(70.f, 30.f), Arrays.asList(g1, l1)).scale(network, 100.0); + double done = Scalable.proportional(Arrays.asList(70.0, 30.0), Arrays.asList(g1, l1)).scale(network, 100.0); assertEquals(70.0, done, 0.0); assertEquals(70.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(0.0, network.getLoad("l1").getP0(), 1e-5); reset(); - done = Scalable.proportional(Arrays.asList(70.f, 30.f), Arrays.asList(g1, l1)).scale(network, -100.0); + done = Scalable.proportional(Arrays.asList(70.0, 30.0), Arrays.asList(g1, l1)).scale(network, -100.0); assertEquals(-30.0, done, 0.0); assertEquals(0.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(30, network.getLoad("l1").getP0(), 1e-5); reset(); - done = Scalable.proportional(Arrays.asList(90.f, 10.f), Arrays.asList(g3, l3)).scale(network, 100.0); + done = Scalable.proportional(Arrays.asList(90.0, 10.0), Arrays.asList(g3, l3)).scale(network, 100.0); assertEquals(90.0, done, 0.0); assertEquals(80.0, network.getGenerator("g3").getTargetP(), 1e-5); assertEquals(-10.0, network.getLoad("l1").getP0(), 1e-5); reset(); - done = Scalable.proportional(Arrays.asList(30.f, 70.f), Arrays.asList(l1, l2)).scale(network, -100.0); + done = Scalable.proportional(Arrays.asList(30.0, 70.0), Arrays.asList(l1, l2)).scale(network, -100.0); assertEquals(-80.0, done, 0.0); assertEquals(80.0, network.getLoad("l1").getP0(), 1e-5); @@ -258,31 +256,31 @@ void testProportionalScaleLoadConvention() { reset(); ScalingParameters parameters = new ScalingParameters().setScalingConvention(convention); - double done = Scalable.proportional(Arrays.asList(70.f, 30.f), Arrays.asList(g1, l1)).scale(network, 100.0, parameters); + double done = Scalable.proportional(Arrays.asList(70.0, 30.0), Arrays.asList(g1, l1)).scale(network, 100.0, parameters); assertEquals(30.0, done, 0.0); assertEquals(0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(30.0, network.getLoad("l1").getP0(), 1e-5); reset(); - done = Scalable.proportional(Arrays.asList(70.f, 30.f), Arrays.asList(g1, l1)).scale(network, -100.0, parameters); + done = Scalable.proportional(Arrays.asList(70.0, 30.0), Arrays.asList(g1, l1)).scale(network, -100.0, parameters); assertEquals(-70.0, done, 0.0); assertEquals(70.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(0.0, network.getLoad("l1").getP0(), 1e-5); reset(); - done = Scalable.proportional(Arrays.asList(90.f, 10.f), Arrays.asList(g3, l3)).scale(network, 100.0, parameters); + done = Scalable.proportional(Arrays.asList(90.0, 10.0), Arrays.asList(g3, l3)).scale(network, 100.0, parameters); assertEquals(10.0, done, 0.0); assertEquals(0.0, network.getGenerator("g3").getTargetP(), 1e-5); assertEquals(10.0, network.getLoad("l1").getP0(), 1e-5); reset(); - done = Scalable.proportional(Arrays.asList(90.f, 10.f), Arrays.asList(l3, g3)).scale(network, -100.0, parameters); + done = Scalable.proportional(Arrays.asList(90.0, 10.0), Arrays.asList(l3, g3)).scale(network, -100.0, parameters); assertEquals(-60.0, done, 0.0); assertEquals(-50.0, network.getLoad("l1").getP0(), 1e-5); assertEquals(10.0, network.getGenerator("g3").getTargetP(), 1e-5); reset(); - done = Scalable.proportional(Arrays.asList(50.f, 50.f), Arrays.asList(l1, l2)).scale(network, 100.0, parameters); + done = Scalable.proportional(Arrays.asList(50.0, 50.0), Arrays.asList(l1, l2)).scale(network, 100.0, parameters); assertEquals(80.0, done, 0.0); assertEquals(80.0, network.getLoad("l1").getP0(), 1e-5); @@ -294,7 +292,7 @@ void testConstantPowerFactorScaling() { ScalingParameters parameters = new ScalingParameters().setConstantPowerFactor(true); network.getLoad("l1").setQ0(10); network.getLoad("l1").setP0(100); - double done = Scalable.proportional(Arrays.asList(50.f, 50.f), Arrays.asList(g1, l1)).scale(network, 100.0, parameters); + double done = Scalable.proportional(Arrays.asList(50.0, 50.0), Arrays.asList(g1, l1)).scale(network, 100.0, parameters); assertEquals(100.0, done, 1e-5); assertEquals(50.0, network.getLoad("l1").getP0(), 1e-5); assertEquals(5.0, network.getLoad("l1").getQ0(), 1e-5); @@ -308,7 +306,7 @@ void testConstantPowerFactorScalingWithLoadConvention() { network.getLoad("l1").setQ0(10); network.getLoad("l1").setP0(100); network.getGenerator("g1").setTargetP(70); - double done = Scalable.proportional(Arrays.asList(50.f, 50.f), Arrays.asList(g1, l1)).scale(network, 100.0, parameters); + double done = Scalable.proportional(Arrays.asList(50.0, 50.0), Arrays.asList(g1, l1)).scale(network, 100.0, parameters); assertEquals(100.0, done, 1e-5); assertEquals(150.0, network.getLoad("l1").getP0(), 1e-5); assertEquals(15.0, network.getLoad("l1").getQ0(), 1e-5); @@ -317,7 +315,7 @@ void testConstantPowerFactorScalingWithLoadConvention() { @Test void testStackScale() { - //By default ScalingConvention.GENERATOR + // By default, ScalingConvention.GENERATOR Scalable scalable = Scalable.stack(g1, g2); double done = scalable.scale(network, 150.0); @@ -410,7 +408,6 @@ void testFilterInjections() { Generator generator2 = network.getGenerator("g2"); Load load1 = network.getLoad("l1"); - List generatorList = g1.filterInjections(network); List generators = g1.filterInjections(network); assertEquals(1, generators.size()); assertSame(generator1, generators.get(0)); @@ -489,38 +486,38 @@ void testFilterInjections() { @Test void testProportionalScalableIterativeMode() { - double done = Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, s, unknownGenerator)).scale(network, 100.0); + double done = Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, s, unknownGenerator)).scale(network, 100.0); assertEquals(70.0, done, 0.0); assertEquals(70.0, network.getGenerator("g1").getTargetP(), 1e-5); - ScalingParameters parameters = new ScalingParameters().setPriority(VOLUME); + ScalingParameters parameters = new ScalingParameters().setPriority(RESPECT_OF_VOLUME_ASKED); reset(); - done = Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, s, unknownGenerator)).scale(network, 100.0, parameters); + done = Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, s, unknownGenerator)).scale(network, 100.0, parameters); assertEquals(100.0, done, 0.0); assertEquals(100.0, network.getGenerator("g1").getTargetP(), 1e-5); reset(); - done = Scalable.proportional(Arrays.asList(2.5f, 7.5f, 90.f), Arrays.asList(g1, g2, g3)).scale(network, 100.0); + done = Scalable.proportional(Arrays.asList(2.5, 7.5, 90.0), Arrays.asList(g1, g2, g3)).scale(network, 100.0); assertEquals(90.0, done, 0.0); assertEquals(2.5, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(7.5, network.getGenerator("g2").getTargetP(), 1e-5); assertEquals(80.0, network.getGenerator("g3").getTargetP(), 1e-5); reset(); - done = Scalable.proportional(Arrays.asList(2.5f, 7.5f, 90.f), Arrays.asList(g1, g2, g3)).scale(network, 100.0, parameters); + done = Scalable.proportional(Arrays.asList(2.5, 7.5, 90.0), Arrays.asList(g1, g2, g3)).scale(network, 100.0, parameters); assertEquals(100.0, done, 0.0); assertEquals(5, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(15.0, network.getGenerator("g2").getTargetP(), 1e-5); assertEquals(80.0, network.getGenerator("g3").getTargetP(), 1e-5); reset(); - done = Scalable.proportional(Arrays.asList(70.f, 10.f, 20.f), Arrays.asList(g3, s, unknownGenerator)).scale(network, 100.0); + done = Scalable.proportional(Arrays.asList(70.0, 10.0, 20.0), Arrays.asList(g3, s, unknownGenerator)).scale(network, 100.0); assertEquals(70.0, done, 0.0); assertEquals(70.0, network.getGenerator("g3").getTargetP(), 1e-5); reset(); - done = Scalable.proportional(Arrays.asList(70.f, 10.f, 20.f), Arrays.asList(g3, s, unknownGenerator)).scale(network, 100.0, parameters); + done = Scalable.proportional(Arrays.asList(70.0, 10.0, 20.0), Arrays.asList(g3, s, unknownGenerator)).scale(network, 100.0, parameters); assertEquals(80.0, done, 0.0); assertEquals(80.0, network.getGenerator("g3").getTargetP(), 1e-5); } @@ -530,7 +527,7 @@ void testExceptionWhenIncorrectArgumentsInProportionalScalableConstructor() { var gens = Arrays.asList(g1, g2, g3); assertThrows(NullPointerException.class, () -> Scalable.proportional(null, gens)); - var percents = Arrays.asList(50.f, 50.f); + var percents = Arrays.asList(50.0, 50.0); assertThrows(NullPointerException.class, () -> Scalable.proportional(percents, null)); assertThrows(IllegalArgumentException.class, () -> Scalable.proportional(percents, gens)); @@ -538,16 +535,16 @@ void testExceptionWhenIncorrectArgumentsInProportionalScalableConstructor() { @Test void testProportionalScaleIterativeThreeSteps() { - double done = Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, g2, g3)).scale(network, 270.0); + double done = Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, g2, g3)).scale(network, 270.0); assertEquals(181.0, done, 0.0); assertEquals(100.0, network.getGenerator("g1").getTargetP(), 1e-3); assertEquals(54, network.getGenerator("g2").getTargetP(), 1e-3); assertEquals(27, network.getGenerator("g3").getTargetP(), 1e-3); - ScalingParameters parameters = new ScalingParameters().setPriority(VOLUME); + ScalingParameters parameters = new ScalingParameters().setPriority(RESPECT_OF_VOLUME_ASKED); reset(); - done = Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, g2, g3)).scale(network, 270.0, parameters); + done = Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, g2, g3)).scale(network, 270.0, parameters); assertEquals(270.0, done, 0.0); assertEquals(100.0, network.getGenerator("g1").getTargetP(), 1e-3); assertEquals(100.0, network.getGenerator("g2").getTargetP(), 1e-3); @@ -556,8 +553,8 @@ void testProportionalScaleIterativeThreeSteps() { @Test void testScalableReuse() { - Scalable scalable = Scalable.proportional(Arrays.asList(70.f, 20.f, 10.f), Arrays.asList(g1, g2, g3)); - ScalingParameters parameters = new ScalingParameters().setPriority(VOLUME); + Scalable scalable = Scalable.proportional(Arrays.asList(70.0, 20.0, 10.0), Arrays.asList(g1, g2, g3)); + ScalingParameters parameters = new ScalingParameters().setPriority(RESPECT_OF_VOLUME_ASKED); double done = scalable.scale(network, 270.0, parameters); assertEquals(270.0, done, 0.0); assertEquals(100.0, network.getGenerator("g1").getTargetP(), 1e-3); diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTestNetwork.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTestNetwork.java index 4ee4b3ba513..c38c9a58f04 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTestNetwork.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalableTestNetwork.java @@ -189,4 +189,134 @@ static Network createNetworkWithDanglingLine() { .add(); return network; } + + static Network createNetworkwithDanglingLineAndBattery() { + Network network = Network.create("network", "test"); + + // Substation + Substation s = network.newSubstation() + .setId("s") + .setCountry(Country.US) + .add(); + + // First voltage level + VoltageLevel vl = s.newVoltageLevel() + .setId("vl1") + .setNominalV(380.0) + .setLowVoltageLimit(0.8 * 380.0) + .setHighVoltageLimit(1.2 * 380.0) + .setTopologyKind(TopologyKind.BUS_BREAKER) + .add(); + vl.getBusBreakerView().newBus() + .setId("bus1") + .add(); + vl.newGenerator() + .setId("g1") + .setBus("bus1") + .setConnectableBus("bus1") + .setMinP(0.0) + .setMaxP(150.0) + .setTargetP(80.0) + .setVoltageRegulatorOn(false) + .setTargetQ(0.0) + .add(); + vl.newGenerator() + .setId("g2") + .setBus("bus1") + .setConnectableBus("bus1") + .setMinP(10.0) + .setMaxP(100.0) + .setTargetP(50.0) + .setVoltageRegulatorOn(false) + .setTargetQ(0.0) + .add(); + vl.newGenerator() + .setId("g3") + .setBus("bus1") + .setConnectableBus("bus1") + .setMinP(20.0) + .setMaxP(80.0) + .setTargetP(30.0) + .setVoltageRegulatorOn(true) + .setTargetV(1.0) + .add(); + vl.newLoad() + .setId("l1") + .setBus("bus1") + .setConnectableBus("bus1") + .setP0(100.0) + .setQ0(0.0) + .setLoadType(LoadType.UNDEFINED) + .add(); + vl.newLoad() + .setId("l2") + .setBus("bus1") + .setConnectableBus("bus1") + .setP0(80.0) + .setQ0(0.0) + .setLoadType(LoadType.UNDEFINED) + .add(); + vl.newLoad() + .setId("l3") + .setBus("bus1") + .setConnectableBus("bus1") + .setP0(50.0) + .setQ0(0.0) + .setLoadType(LoadType.UNDEFINED) + .add(); + + // Second Voltage level + VoltageLevel vl2 = s.newVoltageLevel() + .setId("vl2") + .setTopologyKind(TopologyKind.BUS_BREAKER) + .setNominalV(380) + .add(); + vl2.getBusBreakerView().newBus() + .setId("bus2") + .add(); + vl2.newDanglingLine() + .setId("dl1") + .setBus("bus2") + .setConnectableBus("bus2") + .setP0(50.0) + .setQ0(0.0) + .setR(0.0) + .setX(10.) + .setB(0.0) + .setG(0.0) + .add(); + Battery battery = vl2.newBattery() + .setId("BAT") + .setBus("bus2") + .setConnectableBus("bus2") + .setTargetP(9999.99) + .setTargetQ(9999.99) + .setMinP(-9999.99) + .setMaxP(9999.99) + .add(); + battery.newMinMaxReactiveLimits() + .setMinQ(-9999.99) + .setMaxQ(9999.99) + .add(); + battery.getTerminal().setP(-605); + battery.getTerminal().setQ(-225); + + // Line between the two voltage levels + network.newLine() + .setId("l12") + .setVoltageLevel1("vl1") + .setConnectableBus1("bus1") + .setBus1("bus1") + .setVoltageLevel2("vl2") + .setConnectableBus2("bus2") + .setBus2("bus2") + .setR(1) + .setX(1) + .setG1(0) + .setG2(0) + .setB1(0) + .setB2(0) + .add(); + return network; + } } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java index 1a5bd458f66..84e02debebe 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ScalingParametersTest.java @@ -17,7 +17,6 @@ import java.nio.file.FileSystem; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.DistributionMode.*; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.*; import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.TARGET_P; @@ -55,10 +54,10 @@ void emptyConstructorTest() { @Test void fullConstructorTest() { ScalingParameters parameters = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, true, VOLUME, true); + true, true, RESPECT_OF_VOLUME_ASKED, true); assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); assertTrue(parameters.isConstantPowerFactor()); - assertEquals(VOLUME, parameters.getPriority()); + assertEquals(RESPECT_OF_VOLUME_ASKED, parameters.getPriority()); assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); } @@ -66,16 +65,14 @@ void fullConstructorTest() { @Test void fullSecondConstructorTest() { ScalingParameters parameters = new ScalingParameters(Scalable.ScalingConvention.LOAD, - true, true, VOLUME, true, - PROPORTIONAL_TO_P0, DELTA_P, 100.0); + true, true, RESPECT_OF_VOLUME_ASKED, true, + DELTA_P); assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); assertTrue(parameters.isConstantPowerFactor()); - assertEquals(VOLUME, parameters.getPriority()); + assertEquals(RESPECT_OF_VOLUME_ASKED, parameters.getPriority()); assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); - assertEquals(PROPORTIONAL_TO_P0, parameters.getDistributionMode()); assertEquals(DELTA_P, parameters.getScalingType()); - assertEquals(100.0, parameters.getScalingValue(), 0.0); } @Test @@ -83,20 +80,16 @@ void settersTest() { ScalingParameters parameters = new ScalingParameters() .setScalingConvention(Scalable.ScalingConvention.LOAD) .setConstantPowerFactor(true) - .setPriority(VOLUME) + .setPriority(RESPECT_OF_VOLUME_ASKED) .setReconnect(true) .setAllowsGeneratorOutOfActivePowerLimits(true) - .setDistributionMode(PROPORTIONAL_TO_P0) - .setScalingType(TARGET_P) - .setScalingValue(100.0); + .setScalingType(TARGET_P); assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); assertTrue(parameters.isConstantPowerFactor()); - assertEquals(VOLUME, parameters.getPriority()); + assertEquals(RESPECT_OF_VOLUME_ASKED, parameters.getPriority()); assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); - assertEquals(PROPORTIONAL_TO_P0, parameters.getDistributionMode()); assertEquals(TARGET_P, parameters.getScalingType()); - assertEquals(100.0, parameters.getScalingValue(), 0.0); } @Test @@ -114,14 +107,14 @@ void loadConfigTest() { MapModuleConfig moduleConfig = platformConfig.createModuleConfig("scaling-default-parameters"); moduleConfig.setStringProperty("scalingConvention", "LOAD"); moduleConfig.setStringProperty("constantPowerFactor", "true"); - moduleConfig.setStringProperty("priority", "VOLUME"); + moduleConfig.setStringProperty("priority", "RESPECT_OF_VOLUME_ASKED"); moduleConfig.setStringProperty("reconnect", "true"); moduleConfig.setStringProperty("allowsGeneratorOutOfActivePowerLimits", "true"); ScalingParameters parameters = ScalingParameters.load(platformConfig); assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); assertTrue(parameters.isConstantPowerFactor()); - assertEquals(VOLUME, parameters.getPriority()); + assertEquals(RESPECT_OF_VOLUME_ASKED, parameters.getPriority()); assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); } @@ -143,7 +136,7 @@ void depreciatedMethodsTest() { true, true, true, true); assertEquals(Scalable.ScalingConvention.LOAD, parameters.getScalingConvention()); assertTrue(parameters.isConstantPowerFactor()); - assertEquals(VOLUME, parameters.getPriority()); + assertEquals(RESPECT_OF_VOLUME_ASKED, parameters.getPriority()); assertTrue(parameters.isReconnect()); assertTrue(parameters.isAllowsGeneratorOutOfActivePowerLimits()); diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java new file mode 100644 index 00000000000..b4f03c5dc21 --- /dev/null +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023. , 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.iidm.modification.scalable; + +import com.powsybl.commons.PowsyblException; +import com.powsybl.commons.reporter.ReporterModel; +import com.powsybl.iidm.network.Generator; +import com.powsybl.iidm.network.Network; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static com.powsybl.iidm.modification.scalable.ScalableTestNetwork.createNetworkwithDanglingLineAndBattery; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.ONESHOT; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class StackScalableTest { + + private Network network; + private Scalable g1; + private Scalable g2; + private Scalable g3; + + private Scalable l1; + private Scalable l2; + private Scalable l3; + private Scalable s; + private Scalable unknownGenerator; + private Scalable unknownLoad; + private Scalable unknownDanglingLine; + private Scalable dl1; + + @BeforeEach + void setUp() { + + network = createNetworkwithDanglingLineAndBattery(); + g1 = Scalable.onGenerator("g1"); + g2 = Scalable.onGenerator("g2"); + g3 = Scalable.onGenerator("g3", -10, 80); + s = Scalable.onGenerator("s"); + unknownGenerator = Scalable.onGenerator("unknown"); + + l1 = Scalable.onLoad("l1"); + l2 = Scalable.onLoad("l2", 20, 80); + l3 = Scalable.onLoad("l3", -50, 100); + unknownLoad = Scalable.onLoad("unknown"); + unknownDanglingLine = Scalable.onDanglingLine("unknown"); + dl1 = Scalable.onDanglingLine("dl1", 20, 80); + } + + private void reset() { + Scalable.stack(g1, g2, g3).reset(network); + Scalable.stack(l1, l2, s, unknownGenerator, unknownLoad, unknownDanglingLine, dl1).reset(network); + l3.reset(network); + } + + @Test + void testScaleOnGeneratorsStackingUp() { + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, ONESHOT, true, DELTA_P); + + // Proportional to Target P + StackScalable stackScalable = Scalable.stack(generatorList); + double variationDone = stackScalable.scale(network, 100.0, scalingParameters); + assertEquals(100.0, variationDone, 1e-5); + assertEquals(150.0, network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(80.0, network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(30.0, network.getGenerator("g3").getTargetP(), 1e-5); + reset(); + } + + @Test + void testScaleOnGeneratorsStackingUpWrongScalingType() { + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, ONESHOT, true, TARGET_P); + + // Proportional to Target P + StackScalable stackScalable = Scalable.stack(generatorList); + + // Error raised + PowsyblException e0 = assertThrows(PowsyblException.class, () -> stackScalable.scale(network, 100.0, scalingParameters)); + assertEquals("Stacking only works with DELTA_P ScalingType", e0.getMessage()); + reset(); + } +} diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java index 93b8c4b30e7..cbca1d7fd08 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/json/JsonScalingParametersTest.java @@ -15,7 +15,7 @@ import java.io.IOException; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.ONESHOT; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.VOLUME; +import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.RESPECT_OF_VOLUME_ASKED; import static com.powsybl.iidm.modification.scalable.json.JsonScalingParameters.read; import static org.junit.jupiter.api.Assertions.*; @@ -42,7 +42,7 @@ void testDeserializerV1dot1() { assertFalse(parameters.isAllowsGeneratorOutOfActivePowerLimits()); parameters = read(getClass().getResourceAsStream("/json/ScalingParameters_v1.0b.json")); - assertEquals(VOLUME, parameters.getPriority()); + assertEquals(RESPECT_OF_VOLUME_ASKED, parameters.getPriority()); } @Test From ce4410a281629af711f2ae3dab67256fdaa34a82 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 8 Sep 2023 13:38:49 +0200 Subject: [PATCH 12/18] Checkstyle corrections Signed-off-by: Nicolas Rol --- .../java/com/powsybl/iidm/modification/scalable/Scalable.java | 2 +- .../com/powsybl/iidm/modification/scalable/ScalableAdapter.java | 1 - .../powsybl/iidm/modification/ReplaceTieLinesByLinesTest.java | 2 +- .../iidm/modification/scalable/ProportionalScalableTest.java | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java index 4ad9aa83fe8..bd66cc5e12d 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java @@ -261,7 +261,7 @@ static double getVariationAsked(ScalingParameters scalingParameters, double aske static double getCurrentPower(Injection injection) { if (injection instanceof Generator generator) { return generator.getTargetP(); - } else if (injection instanceof Load load ) { + } else if (injection instanceof Load load) { return load.getP0(); } else if (injection instanceof DanglingLine danglingLine) { return danglingLine.getP0(); diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java index 80984c24b07..557eb804dcf 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java @@ -12,7 +12,6 @@ import java.util.List; import java.util.Objects; - class ScalableAdapter extends AbstractScalable { private final String id; diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/ReplaceTieLinesByLinesTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/ReplaceTieLinesByLinesTest.java index c3665041b86..d2194c057a3 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/ReplaceTieLinesByLinesTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/ReplaceTieLinesByLinesTest.java @@ -85,7 +85,7 @@ private static Network createDummyNodeBreakerNetwork() { return network; } - private static class DummyIdentifiableExtension> extends AbstractExtension { + private static final class DummyIdentifiableExtension> extends AbstractExtension { @Override public String getName() { return "foo"; diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java index 4112ed56424..1318e35c289 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java @@ -77,7 +77,6 @@ void testOnInjections() { ProportionalScalable proportionalScalable; double variationDone; - // Proportional to P0 ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD, true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P); From e91aceac29930d03bfae6e96f629d7106729f88f Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 11 Sep 2023 09:50:28 +0200 Subject: [PATCH 13/18] Correction of testProportional (float to double) Signed-off-by: Nicolas Rol --- action/action-dsl/src/test/resources/scalable.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action/action-dsl/src/test/resources/scalable.groovy b/action/action-dsl/src/test/resources/scalable.groovy index b9cfbebd59f..fa8e209213c 100644 --- a/action/action-dsl/src/test/resources/scalable.groovy +++ b/action/action-dsl/src/test/resources/scalable.groovy @@ -33,7 +33,7 @@ action('testProportional') { script { variationValue = 15000 gens = scalables('GEN', 'GEN2', 'GEN3') - variation = proportional([50.0f,20.0f,30.0f], gens) + variation = proportional([50.0d,20.0d,30.0d], gens) variation.reset(network) variation.scale(network, variationValue) } From bd21317067703a4e8934d31288e16d38de7d9abb Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Wed, 13 Sep 2023 11:56:00 +0200 Subject: [PATCH 14/18] deletion of checkPositiveAskedWhenTarget and modification of getCurrentPower Signed-off-by: Nicolas Rol --- .../scalable/DanglingLineScalable.java | 23 ++++++---- .../scalable/GeneratorScalable.java | 17 +++++++- .../modification/scalable/LoadScalable.java | 18 ++++++++ .../scalable/ProportionalScalable.java | 38 +++++++---------- .../iidm/modification/scalable/Scalable.java | 18 +++----- .../scalable/ScalableAdapter.java | 11 +++-- .../modification/scalable/StackScalable.java | 19 +++++---- .../modification/scalable/UpDownScalable.java | 6 +++ .../util/ModificationReports.java | 18 +++++++- .../scalable/ProportionalScalableTest.java | 42 +++++++++++++++++-- .../scalable/StackScalableTest.java | 41 +++++++++++++++--- .../scalable/UpDownScalableTest.java | 16 ++++++- 12 files changed, 200 insertions(+), 67 deletions(-) diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java index a4626dd9ef9..913cb8faf14 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java @@ -6,10 +6,7 @@ */ package com.powsybl.iidm.modification.scalable; -import com.powsybl.iidm.network.DanglingLine; -import com.powsybl.iidm.network.Injection; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.Terminal; +import com.powsybl.iidm.network.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -104,9 +101,10 @@ public void filterInjections(Network n, List injections, List /** * {@inheritDoc} - *

- * If scalingConvention is LOAD, the load active power increases for positive "asked" and decreases inversely - * If scalingConvention is GENERATOR, the load active power decreases for positive "asked" and increases inversely + *

    + *
  • If scalingConvention is LOAD, the load active power increases for positive "asked" and decreases inversely.
  • + *
  • If scalingConvention is GENERATOR, the load active power decreases for positive "asked" and increases inversely.
  • + *
*/ @Override public double scale(Network n, double asked, ScalingParameters parameters) { @@ -166,4 +164,15 @@ public double maximumValue(Network n) { public double minimumValue(Network n) { return minimumValue(n, scalingConvention); } + + @Override + public double getCurrentPower(Network network, ScalingConvention scalingConvention) { + DanglingLine line = network.getDanglingLine(id); + if (line == null) { + LOGGER.warn("DanglingLine {} not found", id); + return 0.0; + } else { + return scalingConvention == LOAD ? line.getP0() : -line.getP0(); + } + } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java index 028b6a92941..f462ffa30c9 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java @@ -102,8 +102,10 @@ public void filterInjections(Network n, List injections, List /** * {@inheritDoc} * - * If scalingConvention is GENERATOR, the generator active power increases for positive "asked" and decreases inversely - * If scalingConvention is LOAD, the generator active power decreases for positive "asked" and increases inversely + *
    + *
  • If scalingConvention is GENERATOR, the generator active power increases for positive "asked" and decreases inversely.
  • + *
  • If scalingConvention is LOAD, the generator active power decreases for positive "asked" and increases inversely.
  • + *
*/ @Override public double scale(Network n, double asked, ScalingParameters parameters) { @@ -182,4 +184,15 @@ public double scale(Network n, double asked, ScalingParameters parameters) { return askedPower < availablePower ? availablePower / askedPower : 100.0; } } + + @Override + public double getCurrentPower(Network network, ScalingConvention scalingConvention) { + Generator generator = network.getGenerator(id); + if (generator == null) { + LOGGER.warn("Generator {} not found", id); + return 0.0; + } else { + return scalingConvention == GENERATOR ? generator.getTargetP() : -generator.getTargetP(); + } + } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java index af5494316fc..7802e280040 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java @@ -95,6 +95,14 @@ public void filterInjections(Network n, List injections, List } } + /** + * {@inheritDoc} + * + *
    + *
  • If scalingConvention is LOAD, the load active power increases for positive "asked" and decreases inversely.
  • + *
  • If scalingConvention is GENERATOR, the load active power decreases for positive "asked" and increases inversely.
  • + *
+ */ @Override public double scale(Network n, double asked, ScalingParameters parameters) { Objects.requireNonNull(n); @@ -151,4 +159,14 @@ public double scale(Network n, double asked, ScalingParameters parameters) { return done; } + @Override + public double getCurrentPower(Network network, ScalingConvention scalingConvention) { + Load load = network.getLoad(id); + if (load == null) { + LOGGER.warn("Load {} not found", id); + return 0.0; + } else { + return scalingConvention == LOAD ? load.getP0() : -load.getP0(); + } + } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java index c63c63c66f5..985b83216d6 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java @@ -73,7 +73,6 @@ void setIterationPercentage(double iterationPercentage) { } private final List scalablePercentageList; - private double currentGlobalPower = 0; ProportionalScalable(List percentages, List scalables) { checkPercentages(percentages, scalables); @@ -90,9 +89,6 @@ public ProportionalScalable(List injections, DistributionMo // Compute the sum of every individual power double totalDistribution = computeTotalDistribution(injections, distributionMode); - // Compute the current power value - currentGlobalPower = injections.stream().mapToDouble(Scalable::getCurrentPower).sum(); - // In some cases, a regular distribution is equivalent to the nominal distribution : // - PROPORTIONAL_TO_P0 : if no power is currently configured // - PROPORTIONAL_TO_TARGETP : if no power is currently configured @@ -261,15 +257,15 @@ public double scale(Network n, double asked, ScalingParameters parameters) { Objects.requireNonNull(n); Objects.requireNonNull(parameters); - // Check the coherence of the asked value and the scaling type - checkPositiveAskedWhenTarget(asked, parameters); + // Compute the current power value + double currentGlobalPower = getCurrentPower(n, parameters.getScalingConvention()); // Variation asked double variationAsked = Scalable.getVariationAsked(parameters, asked, currentGlobalPower); - // Adapt the asked value if needed - only used in VENTILATION mode + // Adapt the asked value if needed - only used in RESPECT_OF_DISTRIBUTION mode if (parameters.getPriority() == RESPECT_OF_DISTRIBUTION) { - variationAsked = resizeAskedForVentilation(n, variationAsked, parameters); + variationAsked = resizeAskedForFixedDistribution(n, variationAsked, parameters); } reinitIterationPercentage(); @@ -280,25 +276,19 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } } - private void checkPositiveAskedWhenTarget(double asked, ScalingParameters scalingParameters) { - if (asked < 0 && scalingParameters.getScalingType() == ScalingParameters.ScalingType.TARGET_P) { - throw new PowsyblException("The asked power value can only be positive when scaling type is TARGET_P"); - } - } - private void reinitIterationPercentage() { scalablePercentageList.forEach(scalablePercentage -> scalablePercentage.setIterationPercentage(scalablePercentage.getPercentage())); } /** - * Compute the power that can be scaled on the network while keeping the ventilation percentages valid. - * This method is only used if the distribution is not STACKING_UP (cannot happen since it's a - * {@link ProportionalScalable} and if the scaling priority is VENTILATION. + * Compute the power that can be scaled on the network while keeping the distribution percentages valid. + * This method is only used on generators, using a GeneratorScalable or a ScalableAdapter, and when the + * scaling priority is RESPECT_OF_DISTRIBUTION. * @param asked power that shall be scaled on the network * @param network network on which the scaling shall be done - * @return the effective power value that can be safely scaled while keeping the ventilation percentages valid + * @return the effective power value that can be safely scaled while keeping the distribution percentages valid */ - double resizeAskedForVentilation(Network network, double asked, ScalingParameters scalingParameters) { + double resizeAskedForFixedDistribution(Network network, double asked, ScalingParameters scalingParameters) { AtomicReference resizingPercentage = new AtomicReference<>(1.0); scalablePercentageList.forEach(scalablePercentage -> { if (scalablePercentage.getScalable() instanceof GeneratorScalable generatorScalable) { @@ -310,13 +300,17 @@ private void reinitIterationPercentage() { scalableAdapter.availablePowerInPercentageOfAsked(network, asked, scalablePercentage.getPercentage(), scalingParameters.getScalingConvention()), resizingPercentage.get())); } else { - throw new PowsyblException(String.format("VENTILATION mode can only be used with ScalableAdapter, not %s", + throw new PowsyblException(String.format("RESPECT_OF_DISTRIBUTION mode can only be used with ScalableAdapter or GeneratorScalable, not %s", scalablePercentage.getScalable().getClass())); } - } - ); + }); return asked * resizingPercentage.get(); } + @Override + public double getCurrentPower(Network network, ScalingConvention scalingConvention) { + return scalablePercentageList.stream().mapToDouble(scalablePercentage -> scalablePercentage.getScalable().getCurrentPower(network, scalingConvention)).sum(); + } + } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java index bd66cc5e12d..66bb4e3aa55 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java @@ -6,7 +6,6 @@ */ package com.powsybl.iidm.modification.scalable; -import com.powsybl.commons.PowsyblException; import com.powsybl.iidm.network.*; import java.util.Arrays; @@ -258,15 +257,10 @@ static double getVariationAsked(ScalingParameters scalingParameters, double aske : askedValue - currentGlobalPower; } - static double getCurrentPower(Injection injection) { - if (injection instanceof Generator generator) { - return generator.getTargetP(); - } else if (injection instanceof Load load) { - return load.getP0(); - } else if (injection instanceof DanglingLine danglingLine) { - return danglingLine.getP0(); - } else { - throw new PowsyblException(String.format("Unable to create a scalable from %s", injection.getClass())); - } - } + /** + * Returns the current power value for the injections corresponding to this Scalable + * @param network Network in which the injections are defined + * @return the current power value + */ + double getCurrentPower(Network network, ScalingConvention scalingConvention); } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java index 557eb804dcf..a8e9e54ac62 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java @@ -20,14 +20,14 @@ public ScalableAdapter(String id) { this.id = Objects.requireNonNull(id); } - public ScalableAdapter(Injection injection) { + public ScalableAdapter(Injection injection) { Objects.requireNonNull(injection); this.id = injection.getId(); } private Scalable getScalable(Network n) { Objects.requireNonNull(n); - Identifiable identifiable = n.getIdentifiable(id); + Identifiable identifiable = n.getIdentifiable(id); if (identifiable instanceof Generator) { return new GeneratorScalable(id); } else if (identifiable instanceof Load) { @@ -85,8 +85,13 @@ public double scale(Network n, double asked, ScalingParameters parameters) { return generatorScalable.availablePowerInPercentageOfAsked(network, asked, scalingPercentage, scalingConvention); } else { Identifiable identifiable = network.getIdentifiable(id); - throw new PowsyblException(String.format("VENTILATION mode can only be used with a Generator, not %s", + throw new PowsyblException(String.format("RESPECT_OF_DISTRIBUTION mode can only be used with a Generator, not %s", identifiable.getClass())); } } + + @Override + public double getCurrentPower(Network network, ScalingConvention scalingConvention) { + return getScalable(network).getCurrentPower(network, scalingConvention); + } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java index b6bd76bd500..c6fd009fc85 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java @@ -6,7 +6,6 @@ */ package com.powsybl.iidm.modification.scalable; -import com.powsybl.commons.PowsyblException; import com.powsybl.iidm.network.Network; import java.util.Arrays; @@ -14,8 +13,6 @@ import java.util.List; import java.util.Objects; -import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.DELTA_P; - /** * @author Geoffroy Jamgotchian */ @@ -41,13 +38,14 @@ Collection getScalables() { public double scale(Network n, double asked, ScalingParameters parameters) { Objects.requireNonNull(n); - // The stacking only works with the DELTA_P ScalingType - if (parameters.getScalingType() != DELTA_P) { - throw new PowsyblException("Stacking only works with DELTA_P ScalingType"); - } + // Compute the current power value + double currentGlobalPower = getCurrentPower(n, parameters.getScalingConvention()); + + // Variation asked + double variationAsked = Scalable.getVariationAsked(parameters, asked, currentGlobalPower); double done = 0; - double remaining = asked; + double remaining = variationAsked; for (Scalable scalable : scalables) { if (Math.abs(remaining) > EPSILON) { double v = scalable.scale(n, remaining, parameters); @@ -57,4 +55,9 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } return done; } + + @Override + public double getCurrentPower(Network network, ScalingConvention scalingConvention) { + return scalables.stream().mapToDouble(scalable -> scalable.getCurrentPower(network, scalingConvention)).sum(); + } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java index 7b960894853..c8332a726a2 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java @@ -6,6 +6,7 @@ */ package com.powsybl.iidm.modification.scalable; +import com.powsybl.commons.PowsyblException; import com.powsybl.iidm.network.Injection; import com.powsybl.iidm.network.Network; @@ -63,4 +64,9 @@ public void filterInjections(Network network, List injections, List 0 ? upScalable.scale(n, asked, parameters) : downScalable.scale(n, asked, parameters); } + + @Override + public double getCurrentPower(Network network, ScalingConvention scalingConvention) { + throw new PowsyblException("getCurrentPower should not be used on UpDownScalable, only on other types of Scalable"); + } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java index 6dadef152f4..48f38bc259c 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/util/ModificationReports.java @@ -10,6 +10,7 @@ import com.powsybl.commons.reporter.Reporter; import com.powsybl.commons.reporter.TypedValue; import com.powsybl.iidm.modification.scalable.ProportionalScalable.DistributionMode; +import com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType; import com.powsybl.iidm.network.*; /** @@ -620,12 +621,25 @@ public static void undefinedPercent(Reporter reporter) { private ModificationReports() { } - public static void scalingReport(Reporter reporter, String type, DistributionMode mode, double asked, double done) { + public static void scalingReport(Reporter reporter, String type, DistributionMode mode, ScalingType scalingType, double asked, double done) { reporter.report(Report.builder() .withKey("scalingApplied") - .withDefaultMessage("Successfully scaled on ${identifiableType} using mode ${mode} with a variation value asked of ${asked}. Variation done is ${done}") + .withDefaultMessage("Successfully scaled on ${identifiableType} using mode ${mode} and type ${type} with a variation value asked of ${asked}. Variation done is ${done}") .withValue(IDENTIFIABLE_TYPE, type) .withValue("mode", mode.name()) + .withValue("type", scalingType.name()) + .withValue("asked", asked) + .withValue("done", done) + .withSeverity(TypedValue.INFO_SEVERITY) + .build()); + } + + public static void scalingReport(Reporter reporter, String type, ScalingType scalingType, double asked, double done) { + reporter.report(Report.builder() + .withKey("scalingApplied") + .withDefaultMessage("Successfully scaled on ${identifiableType} using mode STACKING and type ${type} with a variation value asked of ${asked}. Variation done is ${done}") + .withValue(IDENTIFIABLE_TYPE, type) + .withValue("type", scalingType.name()) .withValue("asked", asked) .withValue("done", done) .withSeverity(TypedValue.INFO_SEVERITY) diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java index 1318e35c289..1567ccd5b3d 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java @@ -85,6 +85,7 @@ void testOnInjections() { scalingReport(reporterModel, "loads and dangling lines", PROPORTIONAL_TO_P0, + scalingParametersProportional.getScalingType(), 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(100.0 * (1.0 + 100 / 230.0), network.getLoad("l1").getP0(), 1e-5); @@ -100,6 +101,7 @@ void testOnInjections() { scalingReport(reporterModel, "loads and dangling lines", UNIFORM_DISTRIBUTION, + scalingParametersUniform.getScalingType(), 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(100.0 / 3.0, network.getLoad("l1").getP0(), 1e-5); @@ -123,6 +125,7 @@ void testOnGenerator() { scalingReport(reporterModel, "generators", PROPORTIONAL_TO_TARGETP, + scalingParameters.getScalingType(), 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(80.0 * (1.0 + 100 / 160.0), network.getGenerator("g1").getTargetP(), 1e-5); @@ -136,6 +139,7 @@ void testOnGenerator() { scalingReport(reporterModel, "generators", PROPORTIONAL_TO_PMAX, + scalingParameters.getScalingType(), 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(150.0 * 100.0 / 330.0, network.getGenerator("g1").getTargetP(), 1e-5); @@ -149,6 +153,7 @@ void testOnGenerator() { scalingReport(reporterModel, "generators", PROPORTIONAL_TO_DIFF_PMAX_TARGETP, + scalingParameters.getScalingType(), 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(150.0 * 100.0 / 330.0, network.getGenerator("g1").getTargetP(), 1e-5); @@ -162,6 +167,7 @@ void testOnGenerator() { scalingReport(reporterModel, "generators", UNIFORM_DISTRIBUTION, + scalingParameters.getScalingType(), 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(100.0 / 3.0, network.getGenerator("g1").getTargetP(), 1e-5); @@ -186,6 +192,7 @@ void testScaleOnGeneratorsUsedPower() { scalingReport(reporterModel, "generators", PROPORTIONAL_TO_DIFF_TARGETP_PMIN, + scalingParameters.getScalingType(), 100.0, variationDone); assertEquals(80.0 + 80.0 * 100 / 130.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(50.0 + 40.0 * 100 / 130.0, network.getGenerator("g2").getTargetP(), 1e-5); @@ -208,6 +215,7 @@ void testScaleOnGeneratorsWithTargetPScalingType() { scalingReport(reporterModel, "generators", PROPORTIONAL_TO_TARGETP, + scalingParameters.getScalingType(), 260.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(80.0 * (1.0 + 100 / 160.0), network.getGenerator("g1").getTargetP(), 1e-5); @@ -216,6 +224,30 @@ void testScaleOnGeneratorsWithTargetPScalingType() { reset(); } + @Test + void testScaleOnLoadsWithTargetPScalingType() { + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List loadList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getLoad("l3")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, false, RESPECT_OF_VOLUME_ASKED, true, TARGET_P); + ProportionalScalable proportionalScalable; + double variationDone; + + // Proportional to Target P + proportionalScalable = Scalable.proportional(loadList, PROPORTIONAL_TO_P0); + variationDone = proportionalScalable.scale(network, -500.0, scalingParameters); + scalingReport(reporterModel, + "loads", + PROPORTIONAL_TO_P0, + scalingParameters.getScalingType(), + -500, variationDone); + assertEquals(-270, variationDone, 1e-5); + assertEquals(100.0 * (1.0 + 270 / 230.0), network.getLoad("l1").getP0(), 1e-5); + assertEquals(80.0 * (1.0 + 270 / 230.0), network.getLoad("l2").getP0(), 1e-5); + assertEquals(50.0 * (1.0 + 270 / 230.0), network.getLoad("l3").getP0(), 1e-5); + reset(); + } + @Test void testScaleOnGeneratorsVentilationPriority() { ReporterModel reporterModel = new ReporterModel("scaling", "default"); @@ -231,6 +263,7 @@ void testScaleOnGeneratorsVentilationPriority() { scalingReport(reporterModel, "generators", PROPORTIONAL_TO_TARGETP, + scalingParameters.getScalingType(), 200.0, variationDone); assertEquals(200.0 * 0.7, variationDone, 1e-5); assertEquals(80.0 * (1.0 + 200.0 * 0.7 / 160.0), network.getGenerator("g1").getTargetP(), 1e-5); @@ -251,7 +284,7 @@ void testScaleOnLoadsVentilationPriority() { // Error raised PowsyblException e0 = assertThrows(PowsyblException.class, () -> proportionalScalable.scale(network, 100.0, scalingParameters)); - assertEquals("VENTILATION mode can only be used with a Generator, not class com.powsybl.iidm.network.impl.LoadImpl", e0.getMessage()); + assertEquals("RESPECT_OF_DISTRIBUTION mode can only be used with a Generator, not class com.powsybl.iidm.network.impl.LoadImpl", e0.getMessage()); reset(); } @@ -347,6 +380,7 @@ void testScaleOnGeneratorsTargetPowerAtZero() { scalingReport(reporterModel, "generators", PROPORTIONAL_TO_TARGETP, + scalingParameters.getScalingType(), 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(0.0 + 100.0 / 3.0, network.getGenerator("g1").getTargetP(), 1e-5); @@ -375,6 +409,7 @@ void testScaleOnGeneratorsUsedPowerAtZero() { scalingReport(reporterModel, "generators", PROPORTIONAL_TO_DIFF_TARGETP_PMIN, + scalingParameters.getScalingType(), 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(0.0 + 100.0 / 3.0, network.getGenerator("g1").getTargetP(), 1e-5); @@ -403,6 +438,7 @@ void testScaleOnGeneratorsAvailablePowerAtZero() { scalingReport(reporterModel, "generators", PROPORTIONAL_TO_DIFF_TARGETP_PMIN, + scalingParameters.getScalingType(), 100.0, variationDone); assertEquals(0.0, variationDone, 1e-5); assertEquals(150.0, network.getGenerator("g1").getTargetP(), 1e-5); @@ -465,12 +501,12 @@ void testResizeAskedForVentilation() { // Error raised for LoadScalable ProportionalScalable proportionalLoadScalable = Scalable.proportional(100.0, l1); PowsyblException e0 = assertThrows(PowsyblException.class, () -> proportionalLoadScalable.scale(network, 100.0, scalingParametersProportional)); - assertEquals("VENTILATION mode can only be used with ScalableAdapter, not class com.powsybl.iidm.modification.scalable.LoadScalable", e0.getMessage()); + assertEquals("RESPECT_OF_DISTRIBUTION mode can only be used with ScalableAdapter or GeneratorScalable, not class com.powsybl.iidm.modification.scalable.LoadScalable", e0.getMessage()); // Error raised for Loads List loadList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getLoad("l3")); ProportionalScalable proportionalScalable = Scalable.proportional(loadList, PROPORTIONAL_TO_P0); PowsyblException e1 = assertThrows(PowsyblException.class, () -> proportionalScalable.scale(network, 100.0, scalingParametersProportional)); - assertEquals("VENTILATION mode can only be used with a Generator, not class com.powsybl.iidm.network.impl.LoadImpl", e1.getMessage()); + assertEquals("RESPECT_OF_DISTRIBUTION mode can only be used with a Generator, not class com.powsybl.iidm.network.impl.LoadImpl", e1.getMessage()); } } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java index b4f03c5dc21..afa34649e39 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java @@ -5,7 +5,6 @@ package com.powsybl.iidm.modification.scalable; -import com.powsybl.commons.PowsyblException; import com.powsybl.commons.reporter.ReporterModel; import com.powsybl.iidm.network.Generator; import com.powsybl.iidm.network.Network; @@ -18,8 +17,8 @@ import static com.powsybl.iidm.modification.scalable.ScalableTestNetwork.createNetworkwithDanglingLineAndBattery; import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.ONESHOT; import static com.powsybl.iidm.modification.scalable.ScalingParameters.ScalingType.*; +import static com.powsybl.iidm.modification.util.ModificationReports.scalingReport; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; class StackScalableTest { @@ -71,6 +70,10 @@ void testScaleOnGeneratorsStackingUp() { // Proportional to Target P StackScalable stackScalable = Scalable.stack(generatorList); double variationDone = stackScalable.scale(network, 100.0, scalingParameters); + scalingReport(reporterModel, + "generators", + scalingParameters.getScalingType(), + 100.0, variationDone); assertEquals(100.0, variationDone, 1e-5); assertEquals(150.0, network.getGenerator("g1").getTargetP(), 1e-5); assertEquals(80.0, network.getGenerator("g2").getTargetP(), 1e-5); @@ -79,7 +82,7 @@ void testScaleOnGeneratorsStackingUp() { } @Test - void testScaleOnGeneratorsStackingUpWrongScalingType() { + void testScaleOnGeneratorsStackingTargetPMoreThanCurrent() { ReporterModel reporterModel = new ReporterModel("scaling", "default"); List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, @@ -87,10 +90,36 @@ void testScaleOnGeneratorsStackingUpWrongScalingType() { // Proportional to Target P StackScalable stackScalable = Scalable.stack(generatorList); + double variationDone = stackScalable.scale(network, 300.0, scalingParameters); + scalingReport(reporterModel, + "generators", + scalingParameters.getScalingType(), + 300.0, variationDone); + assertEquals(140.0, variationDone, 1e-5); + assertEquals(150.0, network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(100.0, network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(50.0, network.getGenerator("g3").getTargetP(), 1e-5); + reset(); + } - // Error raised - PowsyblException e0 = assertThrows(PowsyblException.class, () -> stackScalable.scale(network, 100.0, scalingParameters)); - assertEquals("Stacking only works with DELTA_P ScalingType", e0.getMessage()); + @Test + void testScaleOnGeneratorsStackingTargetPLessThanCurrent() { + ReporterModel reporterModel = new ReporterModel("scaling", "default"); + List generatorList = Arrays.asList(network.getGenerator("g1"), network.getGenerator("g2"), network.getGenerator("g3")); + ScalingParameters scalingParameters = new ScalingParameters(Scalable.ScalingConvention.GENERATOR, + true, true, ONESHOT, true, TARGET_P); + + // Proportional to Target P + StackScalable stackScalable = Scalable.stack(generatorList); + double variationDone = stackScalable.scale(network, 100.0, scalingParameters); + scalingReport(reporterModel, + "generators", + scalingParameters.getScalingType(), + 100.0, variationDone); + assertEquals(-60.0, variationDone, 1e-5); + assertEquals(20.0, network.getGenerator("g1").getTargetP(), 1e-5); + assertEquals(50.0, network.getGenerator("g2").getTargetP(), 1e-5); + assertEquals(30.0, network.getGenerator("g3").getTargetP(), 1e-5); reset(); } } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java index 3cb050792ef..47a1abcfaa5 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java @@ -6,6 +6,7 @@ */ package com.powsybl.iidm.modification.scalable; +import com.powsybl.commons.PowsyblException; import com.powsybl.iidm.network.Injection; import com.powsybl.iidm.network.Network; import org.junit.jupiter.api.Test; @@ -13,8 +14,7 @@ import java.util.ArrayList; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; /** * @author Sebastien Murgey {@literal } @@ -82,4 +82,16 @@ void checkInjectionFilteringWorksAsExpected() { assertEquals(1, notFoundIds.size()); assertTrue(notFoundIds.contains("unknown generator")); } + + @Test + void checkErrorOnGetCurrentPower() { + Network testNetwork = ScalableTestNetwork.createNetwork(); + Scalable upScalable = Scalable.proportional(50, Scalable.onGenerator("g2"), 50, Scalable.onGenerator("unknown generator")); + Scalable downScalable = Scalable.onLoad("l1", 50, 200); + Scalable upDownScalable = Scalable.upDown(upScalable, downScalable); + + // Error raised + PowsyblException e0 = assertThrows(PowsyblException.class, () -> upDownScalable.getCurrentPower(testNetwork, Scalable.ScalingConvention.LOAD)); + assertEquals("getCurrentPower should not be used on UpDownScalable, only on other types of Scalable", e0.getMessage()); + } } From 2395cc1e03f389cb60a7598c8e3a79c5ed7efa2e Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 18 Sep 2023 11:06:32 +0200 Subject: [PATCH 15/18] Renamed getCurrentPower to getOngoingPower Signed-off-by: Nicolas Rol --- .../iidm/modification/scalable/DanglingLineScalable.java | 2 +- .../iidm/modification/scalable/GeneratorScalable.java | 2 +- .../powsybl/iidm/modification/scalable/LoadScalable.java | 2 +- .../iidm/modification/scalable/ProportionalScalable.java | 6 +++--- .../com/powsybl/iidm/modification/scalable/Scalable.java | 2 +- .../powsybl/iidm/modification/scalable/ScalableAdapter.java | 4 ++-- .../powsybl/iidm/modification/scalable/StackScalable.java | 6 +++--- .../powsybl/iidm/modification/scalable/UpDownScalable.java | 2 +- .../iidm/modification/scalable/UpDownScalableTest.java | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java index 913cb8faf14..d6488eee66e 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java @@ -166,7 +166,7 @@ public double minimumValue(Network n) { } @Override - public double getCurrentPower(Network network, ScalingConvention scalingConvention) { + public double getOngoingPower(Network network, ScalingConvention scalingConvention) { DanglingLine line = network.getDanglingLine(id); if (line == null) { LOGGER.warn("DanglingLine {} not found", id); diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java index f462ffa30c9..4c439ac3bf2 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java @@ -186,7 +186,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } @Override - public double getCurrentPower(Network network, ScalingConvention scalingConvention) { + public double getOngoingPower(Network network, ScalingConvention scalingConvention) { Generator generator = network.getGenerator(id); if (generator == null) { LOGGER.warn("Generator {} not found", id); diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java index 7802e280040..e93dcef13ef 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java @@ -160,7 +160,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } @Override - public double getCurrentPower(Network network, ScalingConvention scalingConvention) { + public double getOngoingPower(Network network, ScalingConvention scalingConvention) { Load load = network.getLoad(id); if (load == null) { LOGGER.warn("Load {} not found", id); diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java index 985b83216d6..a517a23a1d3 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java @@ -258,7 +258,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { Objects.requireNonNull(parameters); // Compute the current power value - double currentGlobalPower = getCurrentPower(n, parameters.getScalingConvention()); + double currentGlobalPower = getOngoingPower(n, parameters.getScalingConvention()); // Variation asked double variationAsked = Scalable.getVariationAsked(parameters, asked, currentGlobalPower); @@ -308,8 +308,8 @@ private void reinitIterationPercentage() { } @Override - public double getCurrentPower(Network network, ScalingConvention scalingConvention) { - return scalablePercentageList.stream().mapToDouble(scalablePercentage -> scalablePercentage.getScalable().getCurrentPower(network, scalingConvention)).sum(); + public double getOngoingPower(Network network, ScalingConvention scalingConvention) { + return scalablePercentageList.stream().mapToDouble(scalablePercentage -> scalablePercentage.getScalable().getOngoingPower(network, scalingConvention)).sum(); } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java index 66bb4e3aa55..d8137daf1c7 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java @@ -262,5 +262,5 @@ static double getVariationAsked(ScalingParameters scalingParameters, double aske * @param network Network in which the injections are defined * @return the current power value */ - double getCurrentPower(Network network, ScalingConvention scalingConvention); + double getOngoingPower(Network network, ScalingConvention scalingConvention); } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java index a8e9e54ac62..cfce7e47db9 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java @@ -91,7 +91,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } @Override - public double getCurrentPower(Network network, ScalingConvention scalingConvention) { - return getScalable(network).getCurrentPower(network, scalingConvention); + public double getOngoingPower(Network network, ScalingConvention scalingConvention) { + return getScalable(network).getOngoingPower(network, scalingConvention); } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java index c6fd009fc85..833c6eb8c01 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java @@ -39,7 +39,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { Objects.requireNonNull(n); // Compute the current power value - double currentGlobalPower = getCurrentPower(n, parameters.getScalingConvention()); + double currentGlobalPower = getOngoingPower(n, parameters.getScalingConvention()); // Variation asked double variationAsked = Scalable.getVariationAsked(parameters, asked, currentGlobalPower); @@ -57,7 +57,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } @Override - public double getCurrentPower(Network network, ScalingConvention scalingConvention) { - return scalables.stream().mapToDouble(scalable -> scalable.getCurrentPower(network, scalingConvention)).sum(); + public double getOngoingPower(Network network, ScalingConvention scalingConvention) { + return scalables.stream().mapToDouble(scalable -> scalable.getOngoingPower(network, scalingConvention)).sum(); } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java index c8332a726a2..943e124e4f8 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java @@ -66,7 +66,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } @Override - public double getCurrentPower(Network network, ScalingConvention scalingConvention) { + public double getOngoingPower(Network network, ScalingConvention scalingConvention) { throw new PowsyblException("getCurrentPower should not be used on UpDownScalable, only on other types of Scalable"); } } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java index 47a1abcfaa5..18526216d54 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java @@ -91,7 +91,7 @@ void checkErrorOnGetCurrentPower() { Scalable upDownScalable = Scalable.upDown(upScalable, downScalable); // Error raised - PowsyblException e0 = assertThrows(PowsyblException.class, () -> upDownScalable.getCurrentPower(testNetwork, Scalable.ScalingConvention.LOAD)); + PowsyblException e0 = assertThrows(PowsyblException.class, () -> upDownScalable.getOngoingPower(testNetwork, Scalable.ScalingConvention.LOAD)); assertEquals("getCurrentPower should not be used on UpDownScalable, only on other types of Scalable", e0.getMessage()); } } From 0f4dd2195624b6083bc69d5f235ecfb138e607d1 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 18 Sep 2023 13:21:53 +0200 Subject: [PATCH 16/18] Renamed getOngoingPower to getSteadyStatePower Signed-off-by: Nicolas Rol --- .../iidm/modification/scalable/DanglingLineScalable.java | 2 +- .../iidm/modification/scalable/GeneratorScalable.java | 2 +- .../powsybl/iidm/modification/scalable/LoadScalable.java | 2 +- .../iidm/modification/scalable/ProportionalScalable.java | 6 +++--- .../com/powsybl/iidm/modification/scalable/Scalable.java | 2 +- .../powsybl/iidm/modification/scalable/ScalableAdapter.java | 4 ++-- .../powsybl/iidm/modification/scalable/StackScalable.java | 6 +++--- .../powsybl/iidm/modification/scalable/UpDownScalable.java | 2 +- .../iidm/modification/scalable/UpDownScalableTest.java | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java index d6488eee66e..19a55494522 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/DanglingLineScalable.java @@ -166,7 +166,7 @@ public double minimumValue(Network n) { } @Override - public double getOngoingPower(Network network, ScalingConvention scalingConvention) { + public double getSteadyStatePower(Network network, ScalingConvention scalingConvention) { DanglingLine line = network.getDanglingLine(id); if (line == null) { LOGGER.warn("DanglingLine {} not found", id); diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java index 4c439ac3bf2..7dc35dc2ba9 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/GeneratorScalable.java @@ -186,7 +186,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } @Override - public double getOngoingPower(Network network, ScalingConvention scalingConvention) { + public double getSteadyStatePower(Network network, ScalingConvention scalingConvention) { Generator generator = network.getGenerator(id); if (generator == null) { LOGGER.warn("Generator {} not found", id); diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java index e93dcef13ef..c2bbef0b23a 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/LoadScalable.java @@ -160,7 +160,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } @Override - public double getOngoingPower(Network network, ScalingConvention scalingConvention) { + public double getSteadyStatePower(Network network, ScalingConvention scalingConvention) { Load load = network.getLoad(id); if (load == null) { LOGGER.warn("Load {} not found", id); diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java index a517a23a1d3..92f3fe1d93e 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ProportionalScalable.java @@ -258,7 +258,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { Objects.requireNonNull(parameters); // Compute the current power value - double currentGlobalPower = getOngoingPower(n, parameters.getScalingConvention()); + double currentGlobalPower = getSteadyStatePower(n, parameters.getScalingConvention()); // Variation asked double variationAsked = Scalable.getVariationAsked(parameters, asked, currentGlobalPower); @@ -308,8 +308,8 @@ private void reinitIterationPercentage() { } @Override - public double getOngoingPower(Network network, ScalingConvention scalingConvention) { - return scalablePercentageList.stream().mapToDouble(scalablePercentage -> scalablePercentage.getScalable().getOngoingPower(network, scalingConvention)).sum(); + public double getSteadyStatePower(Network network, ScalingConvention scalingConvention) { + return scalablePercentageList.stream().mapToDouble(scalablePercentage -> scalablePercentage.getScalable().getSteadyStatePower(network, scalingConvention)).sum(); } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java index d8137daf1c7..2e47d456d55 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/Scalable.java @@ -262,5 +262,5 @@ static double getVariationAsked(ScalingParameters scalingParameters, double aske * @param network Network in which the injections are defined * @return the current power value */ - double getOngoingPower(Network network, ScalingConvention scalingConvention); + double getSteadyStatePower(Network network, ScalingConvention scalingConvention); } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java index cfce7e47db9..e9df14d3872 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalableAdapter.java @@ -91,7 +91,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } @Override - public double getOngoingPower(Network network, ScalingConvention scalingConvention) { - return getScalable(network).getOngoingPower(network, scalingConvention); + public double getSteadyStatePower(Network network, ScalingConvention scalingConvention) { + return getScalable(network).getSteadyStatePower(network, scalingConvention); } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java index 833c6eb8c01..31c70fc851e 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/StackScalable.java @@ -39,7 +39,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { Objects.requireNonNull(n); // Compute the current power value - double currentGlobalPower = getOngoingPower(n, parameters.getScalingConvention()); + double currentGlobalPower = getSteadyStatePower(n, parameters.getScalingConvention()); // Variation asked double variationAsked = Scalable.getVariationAsked(parameters, asked, currentGlobalPower); @@ -57,7 +57,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } @Override - public double getOngoingPower(Network network, ScalingConvention scalingConvention) { - return scalables.stream().mapToDouble(scalable -> scalable.getOngoingPower(network, scalingConvention)).sum(); + public double getSteadyStatePower(Network network, ScalingConvention scalingConvention) { + return scalables.stream().mapToDouble(scalable -> scalable.getSteadyStatePower(network, scalingConvention)).sum(); } } diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java index 943e124e4f8..7bc4f4b6b4c 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/UpDownScalable.java @@ -66,7 +66,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) { } @Override - public double getOngoingPower(Network network, ScalingConvention scalingConvention) { + public double getSteadyStatePower(Network network, ScalingConvention scalingConvention) { throw new PowsyblException("getCurrentPower should not be used on UpDownScalable, only on other types of Scalable"); } } diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java index 18526216d54..66095ca1f2c 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/UpDownScalableTest.java @@ -91,7 +91,7 @@ void checkErrorOnGetCurrentPower() { Scalable upDownScalable = Scalable.upDown(upScalable, downScalable); // Error raised - PowsyblException e0 = assertThrows(PowsyblException.class, () -> upDownScalable.getOngoingPower(testNetwork, Scalable.ScalingConvention.LOAD)); + PowsyblException e0 = assertThrows(PowsyblException.class, () -> upDownScalable.getSteadyStatePower(testNetwork, Scalable.ScalingConvention.LOAD)); assertEquals("getCurrentPower should not be used on UpDownScalable, only on other types of Scalable", e0.getMessage()); } } From 922a004847a588061661dc27c75f8f2a6960bdb0 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 18 Sep 2023 13:46:01 +0200 Subject: [PATCH 17/18] Javadoc corrected Signed-off-by: Nicolas Rol --- .../iidm/modification/scalable/ScalingParameters.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java index b1e3a775704..b40087f294f 100644 --- a/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java +++ b/iidm/iidm-modification/src/main/java/com/powsybl/iidm/modification/scalable/ScalingParameters.java @@ -167,11 +167,11 @@ public ScalingParameters setScalingType(ScalingType scalingType) { } /** - * @return an enum representing the priority of the scaling. It can be either VOLUME (the scaling will distribute the - * power asked as much as possible by iterating if elements get saturated, even if it means not respecting potential - * percentages), VENTILATION (the scaling will respect the percentages even if it means not scaling all what is - * asked), or ONESHOT (the scaling will distribute the power asked as is, in one iteration even if elements get - * saturated and even if it means not respecting potential percentages). + * @return an enum representing the priority of the scaling. It can be either RESPECT_OF_VOLUME_ASKED (the scaling + * will distribute the power asked as much as possible by iterating if elements get saturated, even if it means not + * respecting potential percentages), RESPECT_OF_DISTRIBUTION (the scaling will respect the percentages even if it + * means not scaling all what is asked), or ONESHOT (the scaling will distribute the power asked as is, in one + * iteration even if elements get saturated and even if it means not respecting potential percentages). */ public Priority getPriority() { return priority; From 375f11394524d619c1d259d8d7185deb1c042684 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Tue, 19 Sep 2023 10:34:23 +0200 Subject: [PATCH 18/18] Header correction Signed-off-by: Nicolas Rol --- .../modification/scalable/ProportionalScalableTest.java | 3 ++- .../iidm/modification/scalable/StackScalableTest.java | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java index 1567ccd5b3d..6e950d6a56a 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/ProportionalScalableTest.java @@ -1,8 +1,9 @@ /** - * Copyright (c) 2017, RTE (http://www.rte-france.com) + * Copyright (c) 2023, 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/. + * SPDX-License-Identifier: MPL-2.0 */ package com.powsybl.iidm.modification.scalable; diff --git a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java index afa34649e39..12b47bdb42f 100644 --- a/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java +++ b/iidm/iidm-modification/src/test/java/com/powsybl/iidm/modification/scalable/StackScalableTest.java @@ -1,6 +1,9 @@ -/* - * Copyright (c) 2023. , 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/. +/** + * Copyright (c) 2023, 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/. + * SPDX-License-Identifier: MPL-2.0 */ package com.powsybl.iidm.modification.scalable;