From cd7e28dbd4e028495909dca8e2c1966f652de82e Mon Sep 17 00:00:00 2001 From: phiedw Date: Fri, 23 Feb 2024 15:12:42 +0100 Subject: [PATCH] Fix scalable null sum (#136) when sum of percentages of a scalable is zero, set all percentages to same value --------- Signed-off-by: Philippe Edwards --- .../GlskPointScalableConverter.java | 11 +++- .../GlskPointScalableConverterTest.java | 23 +++++++ ...lskB43ParticipationFactorGskLskZeroSum.xml | 65 +++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 glsk/glsk-document-cim/src/test/resources/GlskB43ParticipationFactorGskLskZeroSum.xml diff --git a/glsk/glsk-document-api/src/main/java/com/powsybl/glsk/api/util/converters/GlskPointScalableConverter.java b/glsk/glsk-document-api/src/main/java/com/powsybl/glsk/api/util/converters/GlskPointScalableConverter.java index 9ec80eb3..c3922951 100644 --- a/glsk/glsk-document-api/src/main/java/com/powsybl/glsk/api/util/converters/GlskPointScalableConverter.java +++ b/glsk/glsk-document-api/src/main/java/com/powsybl/glsk/api/util/converters/GlskPointScalableConverter.java @@ -81,10 +81,17 @@ public static Scalable convert(Network network, List shiftKeys) { throw new GlskException("In convert glskShiftKey business type not supported"); } Double percentageSum = percentages.stream().mapToDouble(Double::doubleValue).sum(); - shiftKeyPercentages.add(percentageSum); // each scalable needs to have a sum of percentages equal to 100% - List normalizedPercentages = percentages.stream().map(p -> p * 100 / percentageSum).toList(); + List normalizedPercentages; + if (Math.abs(percentageSum) >= 1e-6) { + Double finalPercentageSum = percentageSum; + normalizedPercentages = percentages.stream().map(p -> p * 100. / finalPercentageSum).toList(); + } else { + normalizedPercentages = percentages.stream().map(p -> 100. / percentages.size()).toList(); + percentageSum = 0.; + } + shiftKeyPercentages.add(percentageSum); // the limit of the scalables is the power they can reach, not how much they can be scaled by Double currentPower = scalables.stream().mapToDouble(scalable -> scalable.getSteadyStatePower(network, 1, Scalable.ScalingConvention.GENERATOR)).sum(); shiftKeyScalables.add(Scalable.proportional(normalizedPercentages, scalables, -Double.MAX_VALUE, currentPower + glskShiftKey.getMaximumShift())); diff --git a/glsk/glsk-document-cim/src/test/java/com/powsybl/glsk/api/util/converters/GlskPointScalableConverterTest.java b/glsk/glsk-document-cim/src/test/java/com/powsybl/glsk/api/util/converters/GlskPointScalableConverterTest.java index f180812b..125135fc 100644 --- a/glsk/glsk-document-cim/src/test/java/com/powsybl/glsk/api/util/converters/GlskPointScalableConverterTest.java +++ b/glsk/glsk-document-cim/src/test/java/com/powsybl/glsk/api/util/converters/GlskPointScalableConverterTest.java @@ -257,4 +257,27 @@ void testConvertGlskPointToScalableB43GskLskWithDanglingLines() { assertEquals(840., testNetwork.getLoad("FFR1AA1 _load").getP0(), DOUBLE_TOLERANCE); // 0.4 * 0.4 = 16 % assertEquals(760., testNetwork.getDanglingLine("BBE2AA1 XNODE_1B 1").getP0(), DOUBLE_TOLERANCE); // 0.4 * 0.6 = 24 % } + + @Test + void testNullPercentageSum() { + GlskPoint glsk = CimGlskDocument.importGlsk(getResourceAsStream("/GlskB43ParticipationFactorGskLskZeroSum.xml")).getGlskPoints().get(0); + Scalable scalable = GlskPointScalableConverter.convert(testNetwork, glsk); + + assertNotNull(scalable); + assertEquals(2000., testNetwork.getGenerator("FFR1AA1 _generator").getTargetP(), DOUBLE_TOLERANCE); + assertEquals(2000., testNetwork.getGenerator("FFR2AA1 _generator").getTargetP(), DOUBLE_TOLERANCE); + assertEquals(3000., testNetwork.getGenerator("FFR3AA1 _generator").getTargetP(), DOUBLE_TOLERANCE); + assertEquals(1000., testNetwork.getLoad("FFR1AA1 _load").getP0(), DOUBLE_TOLERANCE); + assertEquals(3500., testNetwork.getLoad("FFR2AA1 _load").getP0(), DOUBLE_TOLERANCE); + assertEquals(1500., testNetwork.getLoad("FFR3AA1 _load").getP0(), DOUBLE_TOLERANCE); + + double done = scalable.scale(testNetwork, 500.); + assertEquals(500., done, DOUBLE_TOLERANCE); + assertEquals(2350., testNetwork.getGenerator("FFR1AA1 _generator").getTargetP(), DOUBLE_TOLERANCE); // 0.7 * 1.0 = 70 % + assertEquals(2150., testNetwork.getGenerator("FFR2AA1 _generator").getTargetP(), DOUBLE_TOLERANCE); // 0.3 * 1.0 = 30 % + assertEquals(3000., testNetwork.getGenerator("FFR3AA1 _generator").getTargetP(), DOUBLE_TOLERANCE); // untouched + assertEquals(1000., testNetwork.getLoad("FFR1AA1 _load").getP0(), DOUBLE_TOLERANCE); // 0.0 * 0.0 = 0 % + assertEquals(3500., testNetwork.getLoad("FFR2AA1 _load").getP0(), DOUBLE_TOLERANCE); // 0.0 * 0.0 = 0 % + assertEquals(1500., testNetwork.getLoad("FFR3AA1 _load").getP0(), DOUBLE_TOLERANCE); // untouched + } } diff --git a/glsk/glsk-document-cim/src/test/resources/GlskB43ParticipationFactorGskLskZeroSum.xml b/glsk/glsk-document-cim/src/test/resources/GlskB43ParticipationFactorGskLskZeroSum.xml new file mode 100644 index 00000000..fe83e0a1 --- /dev/null +++ b/glsk/glsk-document-cim/src/test/resources/GlskB43ParticipationFactorGskLskZeroSum.xml @@ -0,0 +1,65 @@ + + + 49V000000000017G-20180829-F717 + 1 + B22 + A49 + 49V000000000017G + A36 + 10XDE-RWENET---W + A04 + 2018-10-02T12:21:00Z + + A42 + + + 2018-08-28T22:00Z + 2018-08-29T22:00Z + + 10YDOM-REGION-1V + + GLSK_B43_participation_factor + 10YFR-RTE------C + A03 + + + 2018-08-28T22:00Z + 2018-08-29T22:00Z + + PT60M + + 1 + + B43 + A04 + 1.0 + + FFR1AA1 _generator + FFR1AA1 _generator + 0.7 + + + FFR2AA1 _generator + FFR2AA1 _generator + 0.3 + + + + B43 + A05 + 0.0 + + FFR1AA1 _load + FFR1AA1 _load + 0.0 + + + FFR2AA1 _load + FFR2AA1 _load + 0.0 + + + + + + \ No newline at end of file