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

Remedial action: partial support of GeneratorAction #704

Merged
merged 36 commits into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2b95392
Prepares GeneratorAction
jlbouchot Jan 16, 2023
7ee42f5
Adds missing abstract functions
jlbouchot Jan 16, 2023
b148b98
Improves implementation after clarification of the problem
jlbouchot Jan 16, 2023
722d464
Includes PerUnits and relativity of power in action creation
jlbouchot Jan 19, 2023
d44274f
Continues with unit testing of GeneratorAction
jlbouchot Jan 26, 2023
1e72184
Corrects formatting prior to rebase
jlbouchot Jan 26, 2023
9049560
Rebase onto main
jlbouchot Jan 26, 2023
4245cc9
Improves code coverage GeneratorUpdate
jlbouchot Jan 27, 2023
860ef3f
Updates GeneratorUpdates tests
jlbouchot Jan 27, 2023
d760cac
Removes code smells
jlbouchot Jan 27, 2023
b6f6d64
Develops more unit tests for GeneratorAction
jlbouchot Feb 3, 2023
61a3c18
Cleans code and update typos
jlbouchot Feb 16, 2023
6354e91
Wraps up unit tests -- still needs cleaning
jlbouchot Feb 17, 2023
63fac8b
Last commit prior to divergence
jlbouchot Feb 17, 2023
b7cc951
Simplifies model GeneratorUpdate
jlbouchot Feb 17, 2023
55aa31e
Clears some code smells
jlbouchot Feb 17, 2023
6e4b70b
Merge branch 'main' into feature/GeneratorAction
annetill Feb 20, 2023
4d7bda2
Merge branch 'main' into feature/GeneratorAction
annetill Feb 21, 2023
ca6d041
Working UT and checked P range
jlbouchot Feb 24, 2023
942d0dc
Adds signatures
jlbouchot Feb 24, 2023
182b9bd
Merge branch 'main' into feature/GeneratorAction
annetill Feb 27, 2023
c0a3e71
Removes useless empty characters
jlbouchot Feb 27, 2023
caab5d6
Review.
annetill Feb 27, 2023
fe6b529
Merge branch 'feature/GeneratorAction' of https://github.com/powsybl/…
annetill Feb 27, 2023
2dbe5aa
Clean.
annetill Feb 27, 2023
963837b
Support of absolute targetP.
annetill Feb 28, 2023
16d39c6
Support of generator in contingency.
annetill Mar 1, 2023
6c3bfb8
Merge branch 'main' into feature/GeneratorAction
annetill Mar 7, 2023
fc4a6d6
Fix merge.
annetill Mar 7, 2023
7dd9d3b
Adapt tests after merge.
annetill Mar 7, 2023
4557f76
Refactor
geofjamg Mar 7, 2023
38baa7c
Refactor
geofjamg Mar 7, 2023
226d2a9
Refactor
geofjamg Mar 7, 2023
1ad8e6f
Wip
geofjamg Mar 7, 2023
392a096
Merge branch 'main' into feature/GeneratorAction
geofjamg Mar 7, 2023
698a404
Wip
geofjamg Mar 7, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class BusDcState extends ElementState<LfBus> {
private final double loadTargetP;
private final Map<String, Double> generatorsTargetP;
private final Map<String, Boolean> participatingGenerators;
private final Map<String, Boolean> disablingStatusGenerators;
private final double absVariableLoadTargetP;
private final Map<String, Boolean> loadsDisablingStatus;

Expand All @@ -25,6 +26,7 @@ public BusDcState(LfBus bus) {
this.loadTargetP = bus.getLoadTargetP();
this.generatorsTargetP = bus.getGenerators().stream().collect(Collectors.toMap(LfGenerator::getId, LfGenerator::getTargetP));
this.participatingGenerators = bus.getGenerators().stream().collect(Collectors.toMap(LfGenerator::getId, LfGenerator::isParticipating));
this.disablingStatusGenerators = bus.getGenerators().stream().collect(Collectors.toMap(LfGenerator::getId, LfGenerator::isDisabled));
this.absVariableLoadTargetP = bus.getAggregatedLoads().getAbsVariableLoadTargetP();
this.loadsDisablingStatus = bus.getAggregatedLoads().getLoadsDisablingStatus();
}
Expand All @@ -35,6 +37,7 @@ public void restore() {
element.setLoadTargetP(loadTargetP);
element.getGenerators().forEach(g -> g.setTargetP(generatorsTargetP.get(g.getId())));
element.getGenerators().forEach(g -> g.setParticipating(participatingGenerators.get(g.getId())));
element.getGenerators().forEach(g -> g.setDisabled(disablingStatusGenerators.get(g.getId())));
element.getAggregatedLoads().setAbsVariableLoadTargetP(absVariableLoadTargetP);
element.getAggregatedLoads().setLoadsDisablingStatus(loadsDisablingStatus);
}
Expand Down
78 changes: 69 additions & 9 deletions src/main/java/com/powsybl/openloadflow/network/LfAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
import com.powsybl.iidm.network.Load;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.Terminal;
import com.powsybl.loadflow.LoadFlowParameters;
import com.powsybl.openloadflow.graph.GraphConnectivity;
import com.powsybl.openloadflow.network.impl.AbstractLfGenerator;
import com.powsybl.openloadflow.network.impl.Networks;
import com.powsybl.openloadflow.util.PerUnit;
import com.powsybl.security.action.*;
Expand All @@ -20,6 +20,7 @@

/**
* @author Anne Tilloy <anne.tilloy at rte-france.com>
* @author Jean-Luc Bouchot (Artelys) <jlbouchot at gmail.com>
*/
public final class LfAction {

Expand Down Expand Up @@ -65,6 +66,26 @@ private LoadShift(LfBus bus, String loadId, PowerShift powerShift) {
}
}

public static final class GeneratorChange {

private final LfGenerator generator;

private final double deltaTargetP;

private GeneratorChange(LfGenerator generator, double deltaTargetP) {
this.generator = generator;
this.deltaTargetP = deltaTargetP;
}

public LfGenerator getGenerator() {
return generator;
}

public double getDeltaTargetP() {
return deltaTargetP;
}
}

private final String id;

private final LfBranch disabledBranch; // switch to open
Expand All @@ -75,13 +96,16 @@ private LoadShift(LfBus bus, String loadId, PowerShift powerShift) {

private final LoadShift loadShift;

private final GeneratorChange generatorChange;

private LfAction(String id, LfBranch disabledBranch, LfBranch enabledBranch, TapPositionChange tapPositionChange,
LoadShift loadShift) {
LoadShift loadShift, GeneratorChange generatorChange) {
this.id = Objects.requireNonNull(id);
this.disabledBranch = disabledBranch;
this.enabledBranch = enabledBranch;
this.tapPositionChange = tapPositionChange;
this.loadShift = loadShift;
this.generatorChange = generatorChange;
}

public static Optional<LfAction> create(Action action, LfNetwork lfNetwork, Network network, boolean breakers) {
Expand All @@ -100,6 +124,9 @@ public static Optional<LfAction> create(Action action, LfNetwork lfNetwork, Netw
case LoadAction.NAME:
return create((LoadAction) action, lfNetwork, network, breakers);

case GeneratorAction.NAME:
return create((GeneratorAction) action, lfNetwork);

default:
throw new UnsupportedOperationException("Unsupported action type: " + action.getType());
}
Expand All @@ -124,7 +151,7 @@ private static Optional<LfAction> create(LoadAction action, LfNetwork lfNetwork,
// In case of a power shift, we suppose that the shift on a load P0 is exactly the same on the variable active power
// of P0 that could be described in a LoadDetail extension.
PowerShift powerShift = new PowerShift(activePowerShift / PerUnit.SB, activePowerShift / PerUnit.SB, reactivePowerShift / PerUnit.SB);
return Optional.of(new LfAction(action.getId(), null, null, null, new LoadShift(lfBus, load.getId(), powerShift)));
return Optional.of(new LfAction(action.getId(), null, null, null, new LoadShift(lfBus, load.getId(), powerShift), null));
}
return Optional.empty(); // could be in another component or in contingency.
}
Expand All @@ -136,7 +163,7 @@ private static Optional<LfAction> create(PhaseTapChangerTapPositionAction action
throw new UnsupportedOperationException("Phase tap changer tap connection action: only one tap in the branch {" + action.getTransformerId() + "}");
} else {
var tapPositionChange = new TapPositionChange(branch, action.getTapPosition(), action.isRelativeValue());
return Optional.of(new LfAction(action.getId(), null, null, tapPositionChange, null));
return Optional.of(new LfAction(action.getId(), null, null, tapPositionChange, null, null));
}
}
return Optional.empty(); // could be in another component
Expand All @@ -146,7 +173,7 @@ private static Optional<LfAction> create(LineConnectionAction action, LfNetwork
LfBranch branch = lfNetwork.getBranchById(action.getLineId());
if (branch != null) {
if (action.isOpenSide1() && action.isOpenSide2()) {
return Optional.of(new LfAction(action.getId(), branch, null, null, null));
return Optional.of(new LfAction(action.getId(), branch, null, null, null, null));
} else {
throw new UnsupportedOperationException("Line connection action: only open line at both sides is supported yet.");
}
Expand All @@ -164,11 +191,32 @@ private static Optional<LfAction> create(SwitchAction action, LfNetwork lfNetwor
} else {
enabledBranch = branch;
}
return Optional.of(new LfAction(action.getId(), disabledBranch, enabledBranch, null, null));
return Optional.of(new LfAction(action.getId(), disabledBranch, enabledBranch, null, null, null));
}
return Optional.empty(); // could be in another component
}

private static Optional<LfAction> create(GeneratorAction action, LfNetwork lfNetwork) {
LfGenerator generator = lfNetwork.getGeneratorById(action.getGeneratorId());
if (generator != null) {
Optional<Double> activePowerValue = action.getActivePowerValue();
Optional<Boolean> relativeValue = action.isActivePowerRelativeValue();
if (relativeValue.isPresent() && activePowerValue.isPresent()) {
double deltaTargetP;
if (relativeValue.get().equals(Boolean.TRUE)) {
deltaTargetP = activePowerValue.get() / PerUnit.SB;
} else {
deltaTargetP = activePowerValue.get() / PerUnit.SB - generator.getInitialTargetP();
}
var generatorChange = new GeneratorChange(generator, deltaTargetP);
return Optional.of(new LfAction(action.getId(), null, null, null, null, generatorChange));
} else {
throw new UnsupportedOperationException("Generator action: configuration not supported yet.");
}
}
return Optional.empty();
}

public String getId() {
return id;
}
Expand All @@ -181,7 +229,7 @@ public LfBranch getEnabledBranch() {
return enabledBranch;
}

public static void apply(List<LfAction> actions, LfNetwork network, LfContingency contingency, LoadFlowParameters.BalanceType balanceType) {
public static void apply(List<LfAction> actions, LfNetwork network, LfContingency contingency, LfNetworkParameters networkParameters) {
Objects.requireNonNull(actions);
Objects.requireNonNull(network);

Expand All @@ -190,7 +238,7 @@ public static void apply(List<LfAction> actions, LfNetwork network, LfContingenc

// then process remaining changes of actions
for (LfAction action : actions) {
action.apply(balanceType);
action.apply(networkParameters);
}
}

Expand Down Expand Up @@ -243,14 +291,15 @@ public void updateConnectivity(GraphConnectivity<LfBus, LfBranch> connectivity)
}
}

public void apply(LoadFlowParameters.BalanceType balanceType) {
public void apply(LfNetworkParameters networkParameters) {
if (tapPositionChange != null) {
LfBranch branch = tapPositionChange.getBranch();
int tapPosition = branch.getPiModel().getTapPosition();
int value = tapPositionChange.getValue();
int newTapPosition = tapPositionChange.isRelative() ? tapPosition + value : value;
branch.getPiModel().setTapPosition(newTapPosition);
}

if (loadShift != null) {
LfBus bus = loadShift.bus;
String loadId = loadShift.loadId;
Expand All @@ -262,5 +311,16 @@ public void apply(LoadFlowParameters.BalanceType balanceType) {
+ Math.signum(shift.getActive()) * Math.abs(shift.getVariableActive()) * PerUnit.SB);
}
}

if (generatorChange != null) {
LfGenerator generator = generatorChange.getGenerator();
if (!generator.isDisabled()) {
generator.setTargetP(generator.getTargetP() + generatorChange.getDeltaTargetP());
if (!AbstractLfGenerator.checkActivePowerControl(generator.getId(), generator.getTargetP(), generator.getMinP(), generator.getMaxP(),
networkParameters.getPlausibleActivePowerLimit(), null)) {
generator.setParticipating(false);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ public void apply(LoadFlowParameters.BalanceType balanceType) {
LfBus bus = generator.getBus();
generatorBuses.add(bus);
generator.setParticipating(false);
generator.setDisabled(true);
if (generator.getGeneratorControlType() != LfGenerator.GeneratorControlType.OFF) {
generator.setGeneratorControlType(LfGenerator.GeneratorControlType.OFF);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ enum ReactiveRangeMode {

double getTargetQ();

double getInitialTargetP();

double getTargetP();

void setTargetP(double targetP);
Expand Down Expand Up @@ -92,4 +94,10 @@ default void setSlope(double slope) {
ControlledSide getControlledBranchSide();

double getRemoteTargetQ();

default boolean isDisabled() {
return false;
}

void setDisabled(boolean disabled);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public abstract class AbstractLfGenerator extends AbstractPropertyBag implements

protected final LfNetwork network;

protected double initialTargetP;

protected double targetP;

protected LfBus bus;
Expand All @@ -48,9 +50,12 @@ public abstract class AbstractLfGenerator extends AbstractPropertyBag implements

protected double remoteTargetQ = Double.NaN;

private boolean disabled;

protected AbstractLfGenerator(LfNetwork network, double targetP) {
this.network = Objects.requireNonNull(network);
this.targetP = targetP;
this.initialTargetP = targetP;
}

@Override
Expand All @@ -71,6 +76,11 @@ public boolean isFictitious() {
return false;
}

@Override
public double getInitialTargetP() {
return initialTargetP / PerUnit.SB;
}

@Override
public double getTargetP() {
return targetP / PerUnit.SB;
Expand Down Expand Up @@ -302,37 +312,47 @@ public void setParticipating(boolean participating) {
// nothing to do
}

protected boolean checkActivePowerControl(double targetP, double minP, double maxP, LfNetworkParameters parameters,
LfNetworkLoadingReport report) {
public static boolean checkActivePowerControl(String generatorId, double targetP, double minP, double maxP, double plausibleActivePowerLimit,
LfNetworkLoadingReport report) {
boolean participating = true;
if (Math.abs(targetP) < POWER_EPSILON_SI) {
LOGGER.trace("Discard generator '{}' from active power control because targetP ({}) equals 0",
getId(), targetP);
report.generatorsDiscardedFromActivePowerControlBecauseTargetEqualsToZero++;
generatorId, targetP);
if (report != null) {
report.generatorsDiscardedFromActivePowerControlBecauseTargetEqualsToZero++;
}
participating = false;
}
if (targetP > maxP) {
LOGGER.trace("Discard generator '{}' from active power control because targetP ({}) > maxP ({})",
getId(), targetP, maxP);
report.generatorsDiscardedFromActivePowerControlBecauseTargetPGreaterThanMaxP++;
generatorId, targetP, maxP);
if (report != null) {
report.generatorsDiscardedFromActivePowerControlBecauseTargetPGreaterThanMaxP++;
}
participating = false;
}
if (targetP < minP && minP > 0) {
LOGGER.trace("Discard generator '{}' from active power control because targetP ({}) < minP ({})",
getId(), targetP, minP);
report.generatorsDiscardedFromActivePowerControlBecauseTargetPLowerThanMinP++;
generatorId, targetP, minP);
if (report != null) {
report.generatorsDiscardedFromActivePowerControlBecauseTargetPLowerThanMinP++;
}
participating = false;
}
if (maxP > parameters.getPlausibleActivePowerLimit()) {
if (maxP > plausibleActivePowerLimit) {
LOGGER.trace("Discard generator '{}' from active power control because maxP ({}) > {}} MW",
getId(), maxP, parameters.getPlausibleActivePowerLimit());
report.generatorsDiscardedFromActivePowerControlBecauseMaxPNotPlausible++;
generatorId, maxP, plausibleActivePowerLimit);
if (report != null) {
report.generatorsDiscardedFromActivePowerControlBecauseMaxPNotPlausible++;
}
participating = false;
}
if ((maxP - minP) < POWER_EPSILON_SI) {
LOGGER.trace("Discard generator '{}' from active power control because maxP ({} MW) equals minP ({} MW)",
getId(), maxP, minP);
report.generatorsDiscardedFromActivePowerControlBecauseMaxPEqualsMinP++;
generatorId, maxP, minP);
if (report != null) {
report.generatorsDiscardedFromActivePowerControlBecauseMaxPEqualsMinP++;
}
participating = false;
}
return participating;
Expand All @@ -342,4 +362,14 @@ protected boolean checkActivePowerControl(double targetP, double minP, double ma
public String toString() {
return getId();
}

@Override
public boolean isDisabled() {
return disabled;
}

@Override
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ private LfBatteryImpl(Battery battery, LfNetwork network, LfNetworkParameters pa
}
}

if (!checkActivePowerControl(battery.getTargetP(), battery.getMinP(), battery.getMaxP(), parameters, report)) {
if (!checkActivePowerControl(getId(), battery.getTargetP(), battery.getMinP(), battery.getMaxP(),
parameters.getPlausibleActivePowerLimit(), report)) {
participating = false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ private LfGeneratorImpl(Generator generator, LfNetwork network, LfNetworkParamet
this.generatorRef = Ref.create(generator, parameters.isCacheEnabled());
participating = true;
droop = DEFAULT_DROOP;

// get participation factor and droop from extension
ActivePowerControl<Generator> activePowerControl = generator.getExtension(ActivePowerControl.class);
if (activePowerControl != null) {
Expand All @@ -49,7 +50,8 @@ private LfGeneratorImpl(Generator generator, LfNetwork network, LfNetworkParamet
}
}

if (!checkActivePowerControl(generator.getTargetP(), generator.getMinP(), generator.getMaxP(), parameters, report)) {
if (!checkActivePowerControl(generator.getId(), generator.getTargetP(), generator.getMinP(), generator.getMaxP(),
parameters.getPlausibleActivePowerLimit(), report)) {
participating = false;
}

Expand Down
Loading