ProportionalScalableTest.java
/**
* 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;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.report.PowsyblCoreReportResourceBundle;
import com.powsybl.commons.test.PowsyblCoreTestReportResourceBundle;
import com.powsybl.commons.report.ReportNode;
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 java.util.Set;
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.RESPECT_OF_DISTRIBUTION;
import static com.powsybl.iidm.modification.scalable.ScalingParameters.Priority.RESPECT_OF_VOLUME_ASKED;
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;
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 = 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);
// reset();
}
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 testOnInjections() {
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Injection<?>> 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, RESPECT_OF_VOLUME_ASKED, true, DELTA_P);
proportionalScalable = Scalable.proportional(injectionsList, PROPORTIONAL_TO_P0);
variationDone = proportionalScalable.scale(network, 100.0, scalingParametersProportional);
scalingReport(reportNode,
"loads and dangling lines",
PROPORTIONAL_TO_P0.name(),
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);
assertEquals(80 * (1.0 + 100 / 230.0), network.getLoad("l2").getP0(), 1e-5);
assertEquals(50.0 * (1.0 + 100 / 230.0), network.getDanglingLine("dl1").getP0(), 1e-5);
reset();
// Regular distribution
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(reportNode,
"loads and dangling lines",
UNIFORM_DISTRIBUTION.name(),
scalingParametersUniform.getScalingType(),
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.getDanglingLine("dl1").getP0(), 1e-5);
reset();
}
@Test
void testOnGenerator() {
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Generator> 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
proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_TARGETP);
variationDone = proportionalScalable.scale(network, 100.0, scalingParameters);
scalingReport(reportNode,
"generators",
PROPORTIONAL_TO_TARGETP.name(),
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);
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
proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_PMAX);
variationDone = proportionalScalable.scale(network, 100.0, scalingParameters);
scalingReport(reportNode,
"generators",
PROPORTIONAL_TO_PMAX.name(),
scalingParameters.getScalingType(),
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();
// Proportional to the available P
proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_DIFF_PMAX_TARGETP);
variationDone = proportionalScalable.scale(network, 100.0, scalingParameters);
scalingReport(reportNode,
"generators",
PROPORTIONAL_TO_DIFF_PMAX_TARGETP.name(),
scalingParameters.getScalingType(),
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();
// Uniform distribution
proportionalScalable = Scalable.proportional(generatorList, UNIFORM_DISTRIBUTION);
variationDone = proportionalScalable.scale(network, 100.0, scalingParameters);
scalingReport(reportNode,
"generators",
UNIFORM_DISTRIBUTION.name(),
scalingParameters.getScalingType(),
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();
}
@Test
void testScaleOnGeneratorsUsedPower() {
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Generator> 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
proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_DIFF_TARGETP_PMIN);
variationDone = proportionalScalable.scale(network, 100.0, scalingParameters);
assertEquals(100.0, variationDone, 1e-5);
scalingReport(reportNode,
"generators",
PROPORTIONAL_TO_DIFF_TARGETP_PMIN.name(),
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);
assertEquals(30.0 + 10.0 * 100 / 130.0, network.getGenerator("g3").getTargetP(), 1e-5);
reset();
}
@Test
void testScaleOnGeneratorsWithTargetPScalingType() {
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Generator> 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(reportNode,
"generators",
PROPORTIONAL_TO_TARGETP.name(),
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);
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 testScaleOnLoadsWithTargetPScalingType() {
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Load> 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(reportNode,
"loads",
PROPORTIONAL_TO_P0.name(),
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() {
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Generator> 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 Target P
proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_TARGETP);
variationDone = proportionalScalable.scale(network, 200.0, scalingParameters);
scalingReport(reportNode,
"generators",
PROPORTIONAL_TO_TARGETP.name(),
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);
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 testScaleOnLoadsVentilationPriority() {
List<Load> 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 Target P
proportionalScalable = Scalable.proportional(loadList, PROPORTIONAL_TO_P0);
// Error raised
PowsyblException e0 = assertThrows(PowsyblException.class, () -> proportionalScalable.scale(network, 100.0, scalingParameters));
assertEquals("RESPECT_OF_DISTRIBUTION mode can only be used with a Generator, not class com.powsybl.iidm.network.impl.LoadImpl", e0.getMessage());
reset();
}
@Test
void testScaleOnGeneratorsWithWrongParametersTargetP() {
List<DanglingLine> danglinglineList = Collections.singletonList(network.getDanglingLine("dl1"));
List<Load> loadList = Collections.singletonList(network.getLoad("l1"));
List<Battery> 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());
// 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 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 testScaleOnGeneratorsWithWrongParametersMaxP() {
List<DanglingLine> danglinglineList = Collections.singletonList(network.getDanglingLine("dl1"));
List<Load> loadList = Collections.singletonList(network.getLoad("l1"));
List<Battery> 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());
// 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<DanglingLine> danglinglineList = Collections.singletonList(network.getDanglingLine("dl1"));
List<Load> loadList = Collections.singletonList(network.getLoad("l1"));
List<Battery> 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 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<Generator> generatorList = Collections.singletonList(network.getGenerator("g1"));
List<Battery> 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
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);
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Generator> 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
proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_TARGETP);
variationDone = proportionalScalable.scale(network, 100.0, scalingParameters);
scalingReport(reportNode,
"generators",
PROPORTIONAL_TO_TARGETP.name(),
scalingParameters.getScalingType(),
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
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());
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Generator> 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
proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_DIFF_TARGETP_PMIN);
variationDone = proportionalScalable.scale(network, 100.0, scalingParameters);
scalingReport(reportNode,
"generators",
PROPORTIONAL_TO_DIFF_TARGETP_PMIN.name(),
scalingParameters.getScalingType(),
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
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());
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Generator> 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
proportionalScalable = Scalable.proportional(generatorList, PROPORTIONAL_TO_DIFF_TARGETP_PMIN);
variationDone = proportionalScalable.scale(network, 100.0, scalingParameters);
scalingReport(reportNode,
"generators",
PROPORTIONAL_TO_DIFF_TARGETP_PMIN.name(),
scalingParameters.getScalingType(),
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
void testScaleOnLoadsP0AtZero() {
// Modification of the network
network.getLoad("l1").setP0(0.0);
network.getLoad("l2").setP0(0.0);
network.getLoad("l3").setP0(0.0);
List<Load> 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, 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<Generator> 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("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<Load> 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("RESPECT_OF_DISTRIBUTION mode can only be used with a Generator, not class com.powsybl.iidm.network.impl.LoadImpl", e1.getMessage());
}
@Test
void testMaxValueBoundsScalingUpGenConvention() {
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Injection<?>> injectionsList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getDanglingLine("dl1"));
ProportionalScalable proportionalScalable;
double variationDone;
double initialValue = injectionsList.stream().mapToDouble(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("Unexpected injection type");
}
}).sum();
double maxValue = initialValue + 75.0;
// Proportional to P0
ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.GENERATOR,
true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P);
proportionalScalable = Scalable.proportional(injectionsList, PROPORTIONAL_TO_P0, -Double.MAX_VALUE, maxValue);
variationDone = proportionalScalable.scale(network, 100.0, scalingParametersProportional);
scalingReport(reportNode,
"loads and dangling lines",
PROPORTIONAL_TO_P0.name(),
scalingParametersProportional.getScalingType(),
100.0, variationDone);
assertEquals(75, variationDone, 1e-5);
assertEquals(100.0 * (1.0 - 75 / 230.0), network.getLoad("l1").getP0(), 1e-5);
assertEquals(80 * (1.0 - 75 / 230.0), network.getLoad("l2").getP0(), 1e-5);
assertEquals(50.0 * (1.0 - 75 / 230.0), network.getDanglingLine("dl1").getP0(), 1e-5);
reset();
}
@Test
void testMaxValueBoundsScalingDownLoadConvention() {
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Injection<?>> injectionsList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getDanglingLine("dl1"));
ProportionalScalable proportionalScalable;
double variationDone;
double initialValue = injectionsList.stream().mapToDouble(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("Unexpected injection type");
}
}).sum();
double maxValue = initialValue + 75.0;
// Proportional to P0
ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD,
true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P);
proportionalScalable = Scalable.proportional(injectionsList, PROPORTIONAL_TO_P0, -Double.MAX_VALUE, maxValue);
variationDone = proportionalScalable.scale(network, -100.0, scalingParametersProportional);
scalingReport(reportNode,
"loads and dangling lines",
PROPORTIONAL_TO_P0.name(),
scalingParametersProportional.getScalingType(),
-100.0, variationDone);
assertEquals(-75, variationDone, 1e-5);
assertEquals(100.0 * (1.0 - 75 / 230.0), network.getLoad("l1").getP0(), 1e-5);
assertEquals(80 * (1.0 - 75 / 230.0), network.getLoad("l2").getP0(), 1e-5);
assertEquals(50.0 * (1.0 - 75 / 230.0), network.getDanglingLine("dl1").getP0(), 1e-5);
reset();
}
@Test
void testMinValueBoundsScalingDownGenConvention() {
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Injection<?>> injectionsList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getDanglingLine("dl1"));
ProportionalScalable proportionalScalable;
double variationDone;
double initialValue = injectionsList.stream().mapToDouble(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("Unexpected injection type");
}
}).sum();
double minValue = initialValue - 75.0;
// Proportional to P0
ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.GENERATOR,
true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P);
proportionalScalable = Scalable.proportional(injectionsList, PROPORTIONAL_TO_P0, minValue, Double.MAX_VALUE);
variationDone = proportionalScalable.scale(network, -100.0, scalingParametersProportional);
scalingReport(reportNode,
"loads and dangling lines",
PROPORTIONAL_TO_P0.name(),
scalingParametersProportional.getScalingType(),
-100.0, variationDone);
assertEquals(-75, variationDone, 1e-5);
assertEquals(100.0 * (1.0 + 75 / 230.0), network.getLoad("l1").getP0(), 1e-5);
assertEquals(80 * (1.0 + 75 / 230.0), network.getLoad("l2").getP0(), 1e-5);
assertEquals(50.0 * (1.0 + 75 / 230.0), network.getDanglingLine("dl1").getP0(), 1e-5);
reset();
}
@Test
void testMinValueBoundsScalingUpLoadConvention() {
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Injection<?>> injectionsList = Arrays.asList(network.getLoad("l1"), network.getLoad("l2"), network.getDanglingLine("dl1"));
ProportionalScalable proportionalScalable;
double variationDone;
double initialValue = injectionsList.stream().mapToDouble(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("Unexpected injection type");
}
}).sum();
double minValue = initialValue - 75.0;
// Proportional to P0
ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD,
true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P);
proportionalScalable = Scalable.proportional(injectionsList, PROPORTIONAL_TO_P0, minValue, Double.MAX_VALUE);
variationDone = proportionalScalable.scale(network, 100.0, scalingParametersProportional);
scalingReport(reportNode,
"loads and dangling lines",
PROPORTIONAL_TO_P0.name(),
scalingParametersProportional.getScalingType(),
100.0, variationDone);
assertEquals(75, variationDone, 1e-5);
assertEquals(100.0 * (1.0 + 75 / 230.0), network.getLoad("l1").getP0(), 1e-5);
assertEquals(80 * (1.0 + 75 / 230.0), network.getLoad("l2").getP0(), 1e-5);
assertEquals(50.0 * (1.0 + 75 / 230.0), network.getDanglingLine("dl1").getP0(), 1e-5);
reset();
}
@Test
void testDisableInjections() {
ReportNode reportNode = ReportNode.newRootReportNode()
.withResourceBundles(PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME, PowsyblCoreReportResourceBundle.BASE_NAME)
.withMessageTemplate("scaling")
.build();
List<Injection<?>> injectionsList = Arrays.asList(
network.getGenerator("g1"), network.getGenerator("g2"),
network.getLoad("l1"), network.getLoad("l2"),
network.getDanglingLine("dl1"));
ProportionalScalable proportionalScalable;
double variationDone;
// Uniform with scalables on l1, g1 and dl1 disabled
ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.GENERATOR,
true, true, RESPECT_OF_VOLUME_ASKED, true, DELTA_P);
scalingParametersProportional.setIgnoredInjectionIds(Set.of("l1", "g1", "dl1"));
proportionalScalable = Scalable.proportional(injectionsList, UNIFORM_DISTRIBUTION);
double volumeAsked = 70.;
variationDone = proportionalScalable.scale(network, volumeAsked, scalingParametersProportional);
scalingReport(reportNode,
"generators, loads and dangling lines",
UNIFORM_DISTRIBUTION.name(),
scalingParametersProportional.getScalingType(),
volumeAsked, variationDone);
assertEquals(volumeAsked, variationDone, 1e-5);
assertEquals(100.0, network.getLoad("l1").getP0(), 1e-5);
assertEquals(80 - volumeAsked / 2, network.getLoad("l2").getP0(), 1e-5);
assertEquals(80.0, network.getGenerator("g1").getTargetP(), 1e-5);
assertEquals(50 + volumeAsked / 2, network.getGenerator("g2").getTargetP(), 1e-5);
assertEquals(50.0, network.getDanglingLine("dl1").getP0(), 1e-5);
reset();
}
@Test
void testSmallPercentageAndAskingEpsilonMoreThanAvailable() {
Load load1 = network.getLoad("l1");
Load load2 = network.getLoad("l2");
load1.setP0(100. - 1e-5);
load2.setP0(1e-5);
ProportionalScalable proportionalScalable = Scalable.proportional(List.of(load1, load2), PROPORTIONAL_TO_P0);
double volumeAsked = -100. - 0.01; // only -100 can be achieved due to load scalable 0 MW min limit
ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD,
true, false, RESPECT_OF_VOLUME_ASKED, true, DELTA_P);
double variationDone = proportionalScalable.scale(network, volumeAsked, scalingParametersProportional);
assertEquals(-100., variationDone, 1e-5);
assertEquals(0.0, load1.getP0()); // a perfect 0.
assertEquals(0.0, load2.getP0()); // a perfect 0.
}
@Test
void testSmallPercentageOnDiscardedScalable() {
Load load1 = network.getLoad("l1");
Load load2 = network.getLoad("l2");
Load load3 = network.getLoad("l3");
load1.setP0(100.);
load2.setP0(100.);
load3.setP0(100.);
Scalable scalable1 = Scalable.onLoad(load1.getId());
Scalable scalable2 = Scalable.onLoad(load2.getId());
Scalable scalable3 = Scalable.onLoad(load3.getId());
ProportionalScalable proportionalScalable = Scalable.proportional(List.of(100 - 2e-5, 1e-5, 1e-5), List.of(scalable1, scalable2, scalable3));
ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD,
true, false, RESPECT_OF_VOLUME_ASKED, true, DELTA_P);
scalingParametersProportional.setIgnoredInjectionIds(Set.of("l2", "l3"));
double volumeAsked = -100.15; // 100 MW should be done by load1 alone and nothing by ignored load2 and load3
double variationDone = proportionalScalable.scale(network, volumeAsked, scalingParametersProportional);
assertEquals(-100., variationDone, 1e-5);
assertEquals(0.0, load1.getP0()); // a perfect 0.
assertEquals(100.0, load2.getP0()); // load 2 should not move
assertEquals(100.0, load3.getP0()); // load 3 should not move
}
@Test
void testSmallPercentageReNormalized() {
Load load1 = network.getLoad("l1");
Load load2 = network.getLoad("l2");
Load load3 = network.getLoad("l3");
load1.setP0(100.);
load2.setP0(100.);
load3.setP0(100.);
Scalable scalable1 = Scalable.onLoad(load1.getId(), 99., Double.MAX_VALUE);
Scalable scalable2 = Scalable.onLoad(load2.getId());
Scalable scalable3 = Scalable.onLoad(load3.getId());
ProportionalScalable proportionalScalable = Scalable.proportional(List.of(100 - 2e-5, 1e-5, 1e-5), List.of(scalable1, scalable2, scalable3));
double volumeAsked = -100;
ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD,
true, false, RESPECT_OF_VOLUME_ASKED, true, DELTA_P);
double variationDone = proportionalScalable.scale(network, volumeAsked, scalingParametersProportional);
assertEquals(-100., variationDone, 1e-5);
assertEquals(99.0, load1.getP0(), 1e-5); // at limit
assertEquals(50.5, load2.getP0());
assertEquals(50.5, load3.getP0());
}
@Test
void testSmallPercentageReNormalized2() {
Load load1 = network.getLoad("l1");
Load load2 = network.getLoad("l2");
Load load3 = network.getLoad("l3");
load1.setP0(0.);
load2.setP0(100.);
load3.setP0(100.);
Scalable scalable1 = Scalable.onLoad(load1.getId(), 99., Double.MAX_VALUE);
Scalable scalable2 = Scalable.onLoad(load2.getId());
Scalable scalable3 = Scalable.onLoad(load3.getId());
ProportionalScalable proportionalScalable = Scalable.proportional(List.of(100 - 2e-5, 1e-5, 1e-5), List.of(scalable1, scalable2, scalable3));
double volumeAsked = -100;
ScalingParameters scalingParametersProportional = new ScalingParameters(Scalable.ScalingConvention.LOAD,
true, false, RESPECT_OF_VOLUME_ASKED, true, DELTA_P);
double variationDone = proportionalScalable.scale(network, volumeAsked, scalingParametersProportional);
assertEquals(-100., variationDone, 1e-5);
assertEquals(0.0, load1.getP0());
assertEquals(50., load2.getP0());
assertEquals(50., load3.getP0());
}
}