Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fast restart for active power target change #1085

Merged
merged 9 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/main/java/com/powsybl/openloadflow/NetworkCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.powsybl.openloadflow.network.impl.AbstractLfGenerator;
import com.powsybl.openloadflow.network.impl.LfLegBranch;
import com.powsybl.openloadflow.network.util.PreviousValueVoltageInitializer;
import com.powsybl.openloadflow.util.PerUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -156,6 +157,16 @@ private CacheUpdateResult onInjectionUpdate(Injection<?> injection, BiFunction<A
return CacheUpdateResult.elementNotFound();
}

private static CacheUpdateResult updateLfGeneratorTargetP(String id, double oldValue, double newValue, AcLoadFlowContext context, LfBus lfBus) {
double valueShift = newValue - oldValue;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a question: why do you need this temporary "valueShift" ?

LfGenerator lfGenerator = lfBus.getNetwork().getGeneratorById(id);
double newTargetP = lfGenerator.getInitialTargetP() + valueShift / PerUnit.SB;
lfGenerator.setTargetP(newTargetP);
lfGenerator.setInitialTargetP(newTargetP);
lfGenerator.reApplyActivePowerControlChecks(context.getParameters().getNetworkParameters(), null);
return CacheUpdateResult.elementUpdated(context);
}

private CacheUpdateResult onGeneratorUpdate(Generator generator, String attribute, Object oldValue, Object newValue) {
return onInjectionUpdate(generator, (context, lfBus) -> {
if (attribute.equals("targetV")) {
Expand All @@ -174,6 +185,17 @@ private CacheUpdateResult onGeneratorUpdate(Generator generator, String attribut
}
context.getNetwork().validate(LoadFlowModel.AC, null);
return CacheUpdateResult.elementUpdated(context);
} else if (attribute.equals("targetP")) {
return updateLfGeneratorTargetP(generator.getId(), (double) oldValue, (double) newValue, context, lfBus);
}
return CacheUpdateResult.unsupportedUpdate();
});
}

private CacheUpdateResult onBatteryUpdate(Battery battery, String attribute, Object oldValue, Object newValue) {
return onInjectionUpdate(battery, (context, lfBus) -> {
if (attribute.equals("targetP")) {
return updateLfGeneratorTargetP(battery.getId(), (double) oldValue, (double) newValue, context, lfBus);
}
return CacheUpdateResult.unsupportedUpdate();
});
Expand Down Expand Up @@ -277,9 +299,14 @@ public void onUpdate(Identifiable identifiable, String attribute, String variant
default -> {
if (identifiable.getType() == IdentifiableType.GENERATOR) {
Generator generator = (Generator) identifiable;
if (attribute.equals("targetV")) {
if (attribute.equals("targetV") || attribute.equals("targetP")) {
result = onGeneratorUpdate(generator, attribute, oldValue, newValue);
}
} else if (identifiable.getType() == IdentifiableType.BATTERY) {
Battery battery = (Battery) identifiable;
if (attribute.equals("targetP")) {
result = onBatteryUpdate(battery, attribute, oldValue, newValue);
}
} else if (identifiable.getType() == IdentifiableType.SHUNT_COMPENSATOR) {
ShuntCompensator shunt = (ShuntCompensator) identifiable;
if (attribute.equals("sectionCount")) {
Expand Down
6 changes: 1 addition & 5 deletions src/main/java/com/powsybl/openloadflow/network/LfAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.Terminal;
import com.powsybl.openloadflow.graph.GraphConnectivity;
import com.powsybl.openloadflow.network.impl.AbstractLfGenerator;
import com.powsybl.openloadflow.network.impl.LfLegBranch;
import com.powsybl.openloadflow.network.impl.LfShuntImpl;
import com.powsybl.openloadflow.network.impl.Networks;
Expand Down Expand Up @@ -335,10 +334,7 @@ private void applyGeneratorChange(LfNetworkParameters networkParameters) {
double newTargetP = generatorChange.isRelative() ? generator.getTargetP() + generatorChange.activePowerValue() : generatorChange.activePowerValue();
generator.setTargetP(newTargetP);
generator.setInitialTargetP(newTargetP);
if (!AbstractLfGenerator.checkActivePowerControl(generator.getId(), generator.getTargetP(), generator.getMaxP(), generator.getMinTargetP(), generator.getMaxTargetP(),
networkParameters.getPlausibleActivePowerLimit(), networkParameters.isUseActiveLimits(), null)) {
generator.setParticipating(false);
}
generator.reApplyActivePowerControlChecks(networkParameters, null);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package com.powsybl.openloadflow.network;

import com.powsybl.iidm.network.TwoSides;
import com.powsybl.openloadflow.network.impl.LfNetworkLoadingReport;

import java.util.OptionalDouble;

Expand Down Expand Up @@ -143,4 +144,6 @@ default boolean isDisabled() {
LfAsymGenerator getAsym();

void setAsym(LfAsymGenerator asym);

void reApplyActivePowerControlChecks(LfNetworkParameters parameters, LfNetworkLoadingReport report);
}
Original file line number Diff line number Diff line change
Expand Up @@ -456,4 +456,9 @@ public boolean isReference() {
public void setReference(boolean reference) {
this.reference = reference;
}

@Override
public void reApplyActivePowerControlChecks(LfNetworkParameters parameters, LfNetworkLoadingReport report) {
// nothing to do
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public final class LfBatteryImpl extends AbstractLfGenerator {

private final Ref<Battery> batteryRef;

private boolean initialParticipating;

private boolean participating;

private final double droop;
Expand All @@ -39,7 +41,8 @@ private LfBatteryImpl(Battery battery, LfNetwork network, LfNetworkParameters pa
super(network, battery.getTargetP() / PerUnit.SB);
this.batteryRef = Ref.create(battery, parameters.isCacheEnabled());
var apcHelper = ActivePowerControlHelper.create(battery, battery.getMinP(), battery.getMaxP());
participating = apcHelper.participating();
initialParticipating = apcHelper.participating();
participating = initialParticipating;
participationFactor = apcHelper.participationFactor();
droop = apcHelper.droop();
minTargetP = apcHelper.minTargetP();
Expand Down Expand Up @@ -131,4 +134,14 @@ public void updateState(LfNetworkStateUpdateParameters parameters) {
.setP(-targetP * PerUnit.SB)
.setQ(Double.isNaN(calculatedQ) ? -getTargetQ() * PerUnit.SB : -calculatedQ * PerUnit.SB);
}

@Override
public void reApplyActivePowerControlChecks(LfNetworkParameters parameters, LfNetworkLoadingReport report) {
participating = initialParticipating;
var battery = getBattery();
if (!checkActivePowerControl(battery.getId(), targetP * PerUnit.SB, battery.getMaxP(), minTargetP, maxTargetP,
parameters.getPlausibleActivePowerLimit(), parameters.isUseActiveLimits(), report)) {
participating = false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public final class LfGeneratorImpl extends AbstractLfGenerator {

private final Ref<Generator> generatorRef;

private final boolean initialParticipating;

private boolean participating;

private final double droop;
Expand All @@ -53,7 +55,8 @@ private LfGeneratorImpl(Generator generator, LfNetwork network, LfNetworkParamet
// we force voltage control of generators tagged as condensers or tagged as fictitious if the dedicated mode is activated.
forceVoltageControl = generator.isCondenser() || generator.isFictitious() && parameters.getFictitiousGeneratorVoltageControlCheckMode() == OpenLoadFlowParameters.FictitiousGeneratorVoltageControlCheckMode.FORCED;
var apcHelper = ActivePowerControlHelper.create(generator, generator.getMinP(), generator.getMaxP());
participating = apcHelper.participating();
initialParticipating = apcHelper.participating();
participating = initialParticipating;
participationFactor = apcHelper.participationFactor();
droop = apcHelper.droop();
minTargetP = apcHelper.minTargetP();
Expand Down Expand Up @@ -87,6 +90,16 @@ private LfGeneratorImpl(Generator generator, LfNetwork network, LfNetworkParamet
}
}

@Override
public void reApplyActivePowerControlChecks(LfNetworkParameters parameters, LfNetworkLoadingReport report) {
participating = initialParticipating;
var generator = getGenerator();
if (!checkActivePowerControl(generator.getId(), targetP * PerUnit.SB, generator.getMaxP(), minTargetP, maxTargetP,
parameters.getPlausibleActivePowerLimit(), parameters.isUseActiveLimits(), report)) {
participating = false;
}
}

private static void createAsym(Generator generator, LfGeneratorImpl lfGenerator) {
var extension = generator.getExtension(GeneratorFortescue.class);
if (extension != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,78 @@ void testTargetV() {
assertEquals(0, result.getComponentResults().get(0).getIterationCount());
}

@Test
void testGeneratorTargetP() {
var network = DistributedSlackNetworkFactory.create();
var g1 = network.getGenerator("g1");
var g2 = network.getGenerator("g2");
var g3 = network.getGenerator("g3");
var g4 = network.getGenerator("g4");
// align active power control of the 3 generators to have understandable results
g1.setMaxP(300);
g2.setMaxP(300);
g3.setMaxP(300);
g4.setMaxP(300);
g1.getExtension(ActivePowerControl.class).setDroop(1);
g2.getExtension(ActivePowerControl.class).setDroop(1);
g3.getExtension(ActivePowerControl.class).setDroop(1);
g4.getExtension(ActivePowerControl.class).setDroop(1);

var result = loadFlowRunner.run(network, parameters);
assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus());
assertEquals(3, result.getComponentResults().get(0).getIterationCount());
// mismatch 120 -> + 30 each
assertActivePowerEquals(-130.0, g1.getTerminal()); // 100 -> 130
assertActivePowerEquals(-230.0, g2.getTerminal()); // 200 -> 230
assertActivePowerEquals(-120.0, g3.getTerminal()); // 90 -> 120
assertActivePowerEquals(-120.0, g4.getTerminal()); // 90 -> 120

g1.setTargetP(120); // 100 -> 120
assertNotNull(NetworkCache.INSTANCE.findEntry(network).orElseThrow().getContexts()); // check cache has not been invalidated

result = loadFlowRunner.run(network, parameters);
assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus());
assertEquals(2, result.getComponentResults().get(0).getIterationCount());
// mismatch 100 -> + 25 each
assertActivePowerEquals(-145.0, g1.getTerminal()); // 120 -> 125
assertActivePowerEquals(-225.0, g2.getTerminal()); // 220 -> 225
assertActivePowerEquals(-115.0, g3.getTerminal()); // 90 -> 115
assertActivePowerEquals(-115.0, g4.getTerminal()); // 90 -> 115

// check that if target_p > map_p the generator is discarded from active power control
g1.setTargetP(310);
result = loadFlowRunner.run(network, parameters);
assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus());
assertEquals(2, result.getComponentResults().get(0).getIterationCount());
// mismatch 90 -> + 60 each
assertActivePowerEquals(-310.0, g1.getTerminal()); // unchanged
assertActivePowerEquals(-170.0, g2.getTerminal()); // 200 -> 170
assertActivePowerEquals(-60.0, g3.getTerminal()); // 90 -> 60
assertActivePowerEquals(-60.0, g4.getTerminal()); // 90 -> 60
}

@Test
void testBatteryTargetP() {
var network = DistributedSlackNetworkFactory.createWithBattery();
var b1 = network.getBattery("bat1");
var b2 = network.getBattery("bat2");

var result = loadFlowRunner.run(network, parameters);
assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus());
assertEquals(3, result.getComponentResults().get(0).getIterationCount());
assertActivePowerEquals(-2.0, b1.getTerminal());
assertActivePowerEquals(2.983, b2.getTerminal());

b1.setTargetP(4);
assertNotNull(NetworkCache.INSTANCE.findEntry(network).orElseThrow().getContexts()); // check cache has not been invalidated

result = loadFlowRunner.run(network, parameters);
assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus());
assertEquals(2, result.getComponentResults().get(0).getIterationCount());
assertActivePowerEquals(-4.0, b1.getTerminal());
assertActivePowerEquals(3.016, b2.getTerminal());
}

@Test
void testParameterChange() {
var network = EurostagFactory.fix(EurostagTutorialExample1Factory.create());
Expand Down