Skip to content

Commit

Permalink
Support of new BalanceType PROPORTIONAL_TO_GENERATION_PARTICIPATION_F…
Browse files Browse the repository at this point in the history
…ACTOR and PROPORTIONAL_TO_GENERATION_REMAINING_MARGIN (#702)

Signed-off-by: Caio Luke <caio.luke@artelys.com>
Co-authored-by: Anne Tilloy <anne.tilloy@rte-france.com>
Co-authored-by: Damien Jeandemange <damien.jeandemange@artelys.com>
  • Loading branch information
3 people authored and geofjamg committed Jan 31, 2023
1 parent e19a065 commit e1ff879
Show file tree
Hide file tree
Showing 8 changed files with 234 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ default double getDroop() {
return 0;
}

default double getParticipationFactor() {
return 0;
}

double getCalculatedQ();

void setCalculatedQ(double calculatedQ);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public final class LfBatteryImpl extends AbstractLfGenerator {

private double droop;

private double participationFactor;

private LfBatteryImpl(Battery battery, LfNetwork network, LfNetworkParameters parameters, LfNetworkLoadingReport report) {
super(network, battery.getTargetP());
this.batteryRef = new Ref<>(battery);
Expand All @@ -35,10 +37,13 @@ private LfBatteryImpl(Battery battery, LfNetwork network, LfNetworkParameters pa
// get participation factor from extension
ActivePowerControl<Battery> activePowerControl = battery.getExtension(ActivePowerControl.class);
if (activePowerControl != null) {
participating = activePowerControl.isParticipate() && activePowerControl.getDroop() != 0;
if (activePowerControl.getDroop() != 0) {
participating = activePowerControl.isParticipate();
if (!Double.isNaN(activePowerControl.getDroop())) {
droop = activePowerControl.getDroop();
}
if (activePowerControl.getParticipationFactor() > 0) {
participationFactor = activePowerControl.getParticipationFactor();
}
}

if (!checkActivePowerControl(battery.getTargetP(), battery.getMinP(), battery.getMaxP(), parameters, report)) {
Expand Down Expand Up @@ -98,6 +103,11 @@ public double getDroop() {
return droop;
}

@Override
public double getParticipationFactor() {
return participationFactor;
}

@Override
public void updateState() {
var battery = getBattery();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,23 @@ public final class LfGeneratorImpl extends AbstractLfGenerator {

private double droop;

private double participationFactor;

private LfGeneratorImpl(Generator generator, LfNetwork network, LfNetworkParameters parameters, LfNetworkLoadingReport report) {
super(network, generator.getTargetP());
this.generatorRef = new Ref<>(generator);
participating = true;
droop = DEFAULT_DROOP;
// get participation factor from extension
// get participation factor and droop from extension
ActivePowerControl<Generator> activePowerControl = generator.getExtension(ActivePowerControl.class);
if (activePowerControl != null) {
boolean withDroop = !Double.isNaN(activePowerControl.getDroop()) && activePowerControl.getDroop() != 0;
participating = activePowerControl.isParticipate() && withDroop;
if (withDroop) {
participating = activePowerControl.isParticipate();
if (!Double.isNaN(activePowerControl.getDroop())) {
droop = activePowerControl.getDroop();
}
if (activePowerControl.getParticipationFactor() > 0) {
participationFactor = activePowerControl.getParticipationFactor();
}
}

if (!checkActivePowerControl(generator.getTargetP(), generator.getMinP(), generator.getMaxP(), parameters, report)) {
Expand Down Expand Up @@ -127,6 +131,11 @@ public double getDroop() {
return droop;
}

@Override
public double getParticipationFactor() {
return participationFactor;
}

@Override
public void updateState() {
var generator = getGenerator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ public static Step getStep(LoadFlowParameters.BalanceType balanceType, boolean l
case PROPORTIONAL_TO_GENERATION_P:
step = new GenerationActivePowerDistributionStep(GenerationActivePowerDistributionStep.ParticipationType.TARGET);
break;
case PROPORTIONAL_TO_GENERATION_PARTICIPATION_FACTOR:
step = new GenerationActivePowerDistributionStep(GenerationActivePowerDistributionStep.ParticipationType.PARTICIPATION_FACTOR);
break;
case PROPORTIONAL_TO_GENERATION_REMAINING_MARGIN:
step = new GenerationActivePowerDistributionStep(GenerationActivePowerDistributionStep.ParticipationType.REMAINING_MARGIN);
break;
default:
throw new UnsupportedOperationException("Unknown balance type mode: " + balanceType);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/**
* Copyright (c) 2019, RTE (http://www.rte-france.com)
* Copyright (c) 2023, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/)
* 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/.
Expand All @@ -19,17 +20,20 @@

/**
* @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
* @author Caio Luke <caio.luke at artelys.com>
*/
public class GenerationActivePowerDistributionStep implements ActivePowerDistribution.Step {

private static final Logger LOGGER = LoggerFactory.getLogger(GenerationActivePowerDistributionStep.class);

public enum ParticipationType {
MAX,
TARGET
TARGET,
PARTICIPATION_FACTOR,
REMAINING_MARGIN
}

private ParticipationType participationType;
private final ParticipationType participationType;

public GenerationActivePowerDistributionStep(ParticipationType pParticipationType) {
this.participationType = pParticipationType;
Expand All @@ -45,7 +49,7 @@ public List<ParticipatingElement> getParticipatingElements(Collection<LfBus> bus
return buses.stream()
.filter(bus -> bus.isParticipating() && !bus.isDisabled() && !bus.isFictitious())
.flatMap(bus -> bus.getGenerators().stream())
.filter(generator -> generator.isParticipating() && getParticipationFactor(generator) != 0)
.filter(generator -> isParticipating(generator) && getParticipationFactor(generator) != 0)
.map(generator -> new ParticipatingElement(generator, getParticipationFactor(generator)))
.collect(Collectors.toList());
}
Expand Down Expand Up @@ -105,17 +109,39 @@ public double run(List<ParticipatingElement> participatingElements, int iteratio
}

private double getParticipationFactor(LfGenerator generator) {
double factor;
switch (participationType) {
case MAX:
factor = generator.getMaxP() / generator.getDroop();
break;
return generator.getMaxP() / generator.getDroop();
case TARGET:
factor = Math.abs(generator.getTargetP());
break;
return Math.abs(generator.getTargetP());
case PARTICIPATION_FACTOR:
return generator.getParticipationFactor();
case REMAINING_MARGIN:
return Math.max(0.0, generator.getMaxP() - generator.getTargetP());
default:
throw new UnsupportedOperationException("Unknown balance type mode: " + participationType);
}
}

private boolean isParticipating(LfGenerator generator) {
// check first if generator is set to be participating
if (!generator.isParticipating()) {
return false;
}
// then depending on participation type, a generator may be found to not participate
switch (participationType) {
case MAX:
return generator.getDroop() != 0;
case PARTICIPATION_FACTOR:
return generator.getParticipationFactor() > 0;
case TARGET:
case REMAINING_MARGIN:
// nothing more to do here: the check whether TargetP is within Pmin-Pmax range
// was already made in AbstractLfGenerator#checkActivePowerControl
// whose result is reflected in generator.isParticipating()
return true;
default:
throw new UnsupportedOperationException("Unknown balance type mode: " + participationType);
}
return factor;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/**
* Copyright (c) 2019, RTE (http://www.rte-france.com)
* Copyright (c) 2023, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/)
* 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/.
Expand Down Expand Up @@ -30,6 +31,7 @@

/**
* @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
* @author Caio Luke <caio.luke at artelys.com>
*/
class DistributedSlackOnGenerationTest {

Expand All @@ -49,6 +51,7 @@ void setUp() {
g3 = network.getGenerator("g3");
g4 = network.getGenerator("g4");
loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(new DenseMatrixFactory()));
// Note that in core, default balance type is proportional to generation Pmax
parameters = new LoadFlowParameters().setUseReactiveLimits(false)
.setDistributedSlack(true);
OpenLoadFlowParameters.create(parameters)
Expand Down Expand Up @@ -79,7 +82,7 @@ void test() {
}

@Test
void testProportionalToGenerationPBalanceType() {
void testProportionalToP() {
// decrease g1 max limit power, so that distributed slack algo reach the g1 max
g1.setMaxP(105);
parameters.setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_P);
Expand All @@ -92,6 +95,59 @@ void testProportionalToGenerationPBalanceType() {
assertActivePowerEquals(-117.236, g4.getTerminal());
}

@Test
@SuppressWarnings("unchecked")
void testProportionalToParticipationFactor() {
// decrease g1 max limit power, so that distributed slack algo reach the g1 max
g1.setMaxP(100);

// set participationFactor
// g1 NaN participationFactor should be discarded
g1.getExtension(ActivePowerControl.class).setParticipationFactor(Double.NaN);
g2.getExtension(ActivePowerControl.class).setParticipationFactor(3.0);
g3.getExtension(ActivePowerControl.class).setParticipationFactor(1.0);
g4.getExtension(ActivePowerControl.class).setParticipationFactor(-4.0); // Should be discarded

parameters.setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_PARTICIPATION_FACTOR);
LoadFlowResult result = loadFlowRunner.run(network, parameters);

assertTrue(result.isOk());
assertActivePowerEquals(-100, g1.getTerminal());
assertActivePowerEquals(-290, g2.getTerminal());
assertActivePowerEquals(-120, g3.getTerminal());
assertActivePowerEquals(-90, g4.getTerminal());
}

@Test
void testProportionalToRemainingMargin() {
// decrease g1 max limit power, so that distributed slack algo reach the g1 max
g1.setMaxP(105);

parameters.setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_REMAINING_MARGIN);
LoadFlowResult result = loadFlowRunner.run(network, parameters);

assertTrue(result.isOk());
assertActivePowerEquals(-102.667, g1.getTerminal());
assertActivePowerEquals(-253.333, g2.getTerminal());
assertActivePowerEquals(-122.0, g3.getTerminal());
assertActivePowerEquals(-122.0, g4.getTerminal());
}

@Test
void testProportionalToRemainingMarginPmaxBelowTargetP() {
// decrease g1 max limit power below target P
g1.setMaxP(90);

parameters.setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_REMAINING_MARGIN);
LoadFlowResult result = loadFlowRunner.run(network, parameters);

assertTrue(result.isOk());
assertActivePowerEquals(-100.0, g1.getTerminal());
assertActivePowerEquals(-254.545, g2.getTerminal());
assertActivePowerEquals(-122.727, g3.getTerminal());
assertActivePowerEquals(-122.727, g4.getTerminal());
}

@Test
void maxTest() {
// decrease g1 max limit power, so that distributed slack algo reach the g1 max
Expand Down Expand Up @@ -159,7 +215,6 @@ void generatorWithMaxPEqualsToMinP() {

@Test
void nonParticipatingBus() {

//B1 and B2 are located in germany the rest is in france
Substation b1s = network.getSubstation("b1_s");
b1s.setCountry(Country.GE);
Expand Down Expand Up @@ -197,4 +252,64 @@ void generatorWithTargetPLowerThanMinP() {
assertThrows(CompletionException.class, () -> loadFlowRunner.run(network, parameters),
"Failed to distribute slack bus active power mismatch, 504.9476825313616 MW remains");
}

@Test
@SuppressWarnings("unchecked")
void notParticipatingTest() {
g1.getExtension(ActivePowerControl.class).setParticipate(false);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isOk());
assertActivePowerEquals(-100, g1.getTerminal());
assertActivePowerEquals(-251.428, g2.getTerminal());
assertActivePowerEquals(-107.142, g3.getTerminal());
assertActivePowerEquals(-141.428, g4.getTerminal());
}

@Test
void batteryTest() {
Network network = DistributedSlackNetworkFactory.createWithBattery();
Generator g1 = network.getGenerator("g1");
Generator g2 = network.getGenerator("g2");
Generator g3 = network.getGenerator("g3");
Generator g4 = network.getGenerator("g4");
Battery bat1 = network.getBattery("bat1");
Battery bat2 = network.getBattery("bat2");
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isOk());
assertEquals(1, result.getComponentResults().size());
assertEquals(123, result.getComponentResults().get(0).getDistributedActivePower(), LoadFlowAssert.DELTA_POWER);
assertActivePowerEquals(-115.122, g1.getTerminal());
assertActivePowerEquals(-245.368, g2.getTerminal());
assertActivePowerEquals(-105.123, g3.getTerminal());
assertActivePowerEquals(-135.369, g4.getTerminal());
assertActivePowerEquals(-2, bat1.getTerminal());
assertActivePowerEquals(2.983, bat2.getTerminal());
}

@Test
@SuppressWarnings("unchecked")
void batteryTestProportionalToParticipationFactor() {
Network network = DistributedSlackNetworkFactory.createWithBattery();
Generator g1 = network.getGenerator("g1");
Generator g2 = network.getGenerator("g2");
Generator g3 = network.getGenerator("g3");
Generator g4 = network.getGenerator("g4");
Battery bat1 = network.getBattery("bat1");
Battery bat2 = network.getBattery("bat2");
g1.getExtension(ActivePowerControl.class).setParticipationFactor(Double.NaN);
g2.getExtension(ActivePowerControl.class).setParticipationFactor(3.0);
g3.getExtension(ActivePowerControl.class).setParticipationFactor(1.0);
g4.getExtension(ActivePowerControl.class).setParticipationFactor(-4.0); // Should be discarded
parameters.setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_PARTICIPATION_FACTOR);
LoadFlowResult result = loadFlowRunner.run(network, parameters);
assertTrue(result.isOk());
assertEquals(1, result.getComponentResults().size());
assertEquals(123, result.getComponentResults().get(0).getDistributedActivePower(), LoadFlowAssert.DELTA_POWER);
assertActivePowerEquals(-100, g1.getTerminal());
assertActivePowerEquals(-288.5, g2.getTerminal());
assertActivePowerEquals(-119.5, g3.getTerminal());
assertActivePowerEquals(-90, g4.getTerminal());
assertActivePowerEquals(-2, bat1.getTerminal());
assertActivePowerEquals(0, bat2.getTerminal());
}
}
Loading

0 comments on commit e1ff879

Please sign in to comment.