Skip to content

Commit

Permalink
Option to ignore active power limits in slack distribution on generat…
Browse files Browse the repository at this point in the history
…ors (#869)

Signed-off-by: Damien Jeandemange <[email protected]>
  • Loading branch information
jeandemanged authored Oct 3, 2023
1 parent f0ba6c1 commit 04b52b2
Show file tree
Hide file tree
Showing 18 changed files with 147 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ protected AbstractAcOuterLoopConfig() {

protected static Optional<AcOuterLoop> createDistributedSlackOuterLoop(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) {
if (parameters.isDistributedSlack()) {
ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(parameters.getBalanceType(), parametersExt.isLoadPowerFactorConstant());
ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(parameters.getBalanceType(), parametersExt.isLoadPowerFactorConstant(), parametersExt.isUseActiveLimits());
return Optional.of(new DistributedSlackOuterLoop(activePowerDistribution, parametersExt.isThrowsExceptionInCaseOfSlackDistributionFailure(), parametersExt.getSlackBusPMaxMismatch()));
}
return Optional.empty();
Expand Down
38 changes: 29 additions & 9 deletions src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ public class OpenLoadFlowParameters extends AbstractExtension<LoadFlowParameters

static final String OUTER_LOOP_NAMES_PARAM_NAME = "outerLoopNames";

public static final String USE_ACTIVE_LIMITS_PARAM_NAME = "useActiveLimits";

private static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> enumClass) {
return EnumSet.allOf(enumClass).stream().map(Enum::name).collect(Collectors.toList());
}
Expand Down Expand Up @@ -230,7 +232,7 @@ private static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> e
new Parameter(INCREMENTAL_TRANSFORMER_VOLTAGE_CONTROL_OUTER_LOOP_MAX_TAP_SHIFT_PARAM_NAME, ParameterType.INTEGER, "Incremental transformer voltage control maximum tap shift per outer loop", IncrementalTransformerVoltageControlOuterLoop.DEFAULT_MAX_TAP_SHIFT),
new Parameter(SECONDARY_VOLTAGE_CONTROL_PARAM_NAME, ParameterType.BOOLEAN, "Secondary voltage control simulation", LfNetworkParameters.SECONDARY_VOLTAGE_CONTROL_DEFAULT_VALUE),
new Parameter(REACTIVE_LIMITS_MAX_SWITCH_PQ_PV_PARAM_NAME, ParameterType.INTEGER, "Reactive limits maximum Pq Pv switch", ReactiveLimitsOuterLoop.MAX_SWITCH_PQ_PV_DEFAULT_VALUE),
new Parameter(NEWTONRAPHSON_STOPPING_CRITERIA_TYPE_PARAM_NAME, ParameterType.STRING, "Newton raphson stopping criteria type", NEWTONRAPHSON_STOPPING_CRITERIA_TYPE_DEFAULT_VALUE.name(), getEnumPossibleValues(NewtonRaphsonStoppingCriteriaType.class)),
new Parameter(NEWTONRAPHSON_STOPPING_CRITERIA_TYPE_PARAM_NAME, ParameterType.STRING, "Newton-Raphson stopping criteria type", NEWTONRAPHSON_STOPPING_CRITERIA_TYPE_DEFAULT_VALUE.name(), getEnumPossibleValues(NewtonRaphsonStoppingCriteriaType.class)),
new Parameter(MAX_ACTIVE_POWER_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum active power for per equation stopping criteria", MAX_ACTIVE_POWER_MISMATCH_DEFAULT_VALUE),
new Parameter(MAX_REACTIVE_POWER_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum reactive power for per equation stopping criteria", MAX_REACTIVE_POWER_MISMATCH_DEFAULT_VALUE),
new Parameter(MAX_VOLTAGE_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum voltage for per equation stopping criteria", MAX_VOLTAGE_MISMATCH_DEFAULT_VALUE),
Expand All @@ -240,12 +242,13 @@ private static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> e
new Parameter(PHASE_SHIFTER_CONTROL_MODE_PARAM_NAME, ParameterType.STRING, "Phase shifter control mode", PHASE_SHIFTER_CONTROL_MODE_DEFAULT_VALUE.name(), getEnumPossibleValues(PhaseShifterControlMode.class)),
new Parameter(ALWAYS_UPDATE_NETWORK_PARAM_NAME, ParameterType.BOOLEAN, "Update network even if Newton-Raphson algorithm has diverged", NewtonRaphsonParameters.ALWAYS_UPDATE_NETWORK_DEFAULT_VALUE),
new Parameter(MOST_MESHED_SLACK_BUS_SELECTOR_MAX_NOMINAL_VOLTAGE_PERCENTILE_PARAM_NAME, ParameterType.DOUBLE, "In case of most meshed slack bus selection, the max nominal voltage percentile", MostMeshedSlackBusSelector.MAX_NOMINAL_VOLTAGE_PERCENTILE_DEFAULT_VALUE), new Parameter(REPORTED_FEATURES_PARAM_NAME, ParameterType.STRING_LIST, "List of extra reported features to be added to report", null, getEnumPossibleValues(ReportedFeatures.class)),
new Parameter(SLACK_BUS_COUNTRY_FILTER_PARAM_NAME, ParameterType.STRING_LIST, "Slac bus selection country filter (no filtering if empty)", new ArrayList<>(LfNetworkParameters.SLACK_BUS_COUNTRY_FILTER_DEFAULT_VALUE)),
new Parameter(SLACK_BUS_COUNTRY_FILTER_PARAM_NAME, ParameterType.STRING_LIST, "Slack bus selection country filter (no filtering if empty)", new ArrayList<>(LfNetworkParameters.SLACK_BUS_COUNTRY_FILTER_DEFAULT_VALUE)),
new Parameter(ACTIONABLE_SWITCHES_IDS_PARAM_NAME, ParameterType.STRING_LIST, "List of actionable switches IDs (used with fast restart)", new ArrayList<>(ACTIONABLE_SWITCH_IDS_DEFAULT_VALUE)),
new Parameter(ASYMMETRICAL_PARAM_NAME, ParameterType.BOOLEAN, "Asymmetrical calculation", LfNetworkParameters.ASYMMETRICAL_DEFAULT_VALUE),
new Parameter(MIN_NOMINAL_VOLTAGE_TARGET_VOLTAGE_CHECK_PARAM_NAME, ParameterType.DOUBLE, "Min nominal voltage for target voltage check", LfNetworkParameters.MIN_NOMINAL_VOLTAGE_TARGET_VOLTAGE_CHECK_DEFAULT_VALUE),
new Parameter(REACTIVE_POWER_DISPATCH_MODE_PARAM_NAME, ParameterType.STRING, "Generators reactive power from bus dispatch mode", REACTIVE_POWER_DISPATCH_MODE_DEFAULT_VALUE.name(), getEnumPossibleValues(ReactivePowerDispatchMode.class)),
new Parameter(OUTER_LOOP_NAMES_PARAM_NAME, ParameterType.STRING_LIST, "Ordered explicit list of outer loop names, supported outer loops are " + String.join(", ", ExplicitAcOuterLoopConfig.NAMES), OUTER_LOOP_NAMES_DEFAULT_VALUE)
new Parameter(OUTER_LOOP_NAMES_PARAM_NAME, ParameterType.STRING_LIST, "Ordered explicit list of outer loop names, supported outer loops are " + String.join(", ", ExplicitAcOuterLoopConfig.NAMES), OUTER_LOOP_NAMES_DEFAULT_VALUE),
new Parameter(USE_ACTIVE_LIMITS_PARAM_NAME, ParameterType.BOOLEAN, "Use active power limits in slack distribution", LfNetworkParameters.USE_ACTIVE_LIMITS_DEFAULT_VALUE)
);

public enum VoltageInitModeOverride {
Expand Down Expand Up @@ -381,6 +384,8 @@ public enum ReactiveRangeCheckMode {

private List<String> outerLoopNames = OUTER_LOOP_NAMES_DEFAULT_VALUE;

private boolean useActiveLimits = LfNetworkParameters.USE_ACTIVE_LIMITS_DEFAULT_VALUE;

@Override
public String getName() {
return "open-load-flow-parameters";
Expand Down Expand Up @@ -526,7 +531,7 @@ public double getMaxActivePowerMismatch() {

public OpenLoadFlowParameters setMaxActivePowerMismatch(double maxActivePowerMismatch) {
if (maxActivePowerMismatch <= 0) {
throw new PowsyblException("maxActivePowerMismatch must be greater to 0");
throw new PowsyblException("maxActivePowerMismatch must be greater than 0");
}
this.maxActivePowerMismatch = maxActivePowerMismatch;
return this;
Expand All @@ -538,7 +543,7 @@ public double getMaxReactivePowerMismatch() {

public OpenLoadFlowParameters setMaxReactivePowerMismatch(double maxReactivePowerMismatch) {
if (maxReactivePowerMismatch <= 0) {
throw new PowsyblException("maxReactivePowerMismatch must be greater to 0");
throw new PowsyblException("maxReactivePowerMismatch must be greater than 0");
}
this.maxReactivePowerMismatch = maxReactivePowerMismatch;
return this;
Expand All @@ -550,7 +555,7 @@ public double getMaxVoltageMismatch() {

public OpenLoadFlowParameters setMaxVoltageMismatch(double maxVoltageMismatch) {
if (maxVoltageMismatch <= 0) {
throw new PowsyblException("maxVoltageMismatch must be greater to 0");
throw new PowsyblException("maxVoltageMismatch must be greater than 0");
}
this.maxVoltageMismatch = maxVoltageMismatch;
return this;
Expand All @@ -562,7 +567,7 @@ public double getMaxAngleMismatch() {

public OpenLoadFlowParameters setMaxAngleMismatch(double maxAngleMismatch) {
if (maxAngleMismatch <= 0) {
throw new PowsyblException("maxAngleMismatch must be greater to 0");
throw new PowsyblException("maxAngleMismatch must be greater than 0");
}
this.maxAngleMismatch = maxAngleMismatch;
return this;
Expand All @@ -574,7 +579,7 @@ public double getMaxRatioMismatch() {

public OpenLoadFlowParameters setMaxRatioMismatch(double maxRatioMismatch) {
if (maxRatioMismatch <= 0) {
throw new PowsyblException("maxRatioMismatch must be greater to 0");
throw new PowsyblException("maxRatioMismatch must be greater than 0");
}
this.maxRatioMismatch = maxRatioMismatch;
return this;
Expand All @@ -586,7 +591,7 @@ public double getMaxSusceptanceMismatch() {

public OpenLoadFlowParameters setMaxSusceptanceMismatch(double maxSusceptanceMismatch) {
if (maxSusceptanceMismatch <= 0) {
throw new PowsyblException("maxSusceptanceMismatch must be greater to 0");
throw new PowsyblException("maxSusceptanceMismatch must be greater than 0");
}
this.maxSusceptanceMismatch = maxSusceptanceMismatch;
return this;
Expand Down Expand Up @@ -730,6 +735,15 @@ public OpenLoadFlowParameters setSecondaryVoltageControl(boolean secondaryVoltag
return this;
}

public boolean isUseActiveLimits() {
return useActiveLimits;
}

public OpenLoadFlowParameters setUseActiveLimits(boolean useActiveLimits) {
this.useActiveLimits = useActiveLimits;
return this;
}

public String getDebugDir() {
return debugDir;
}
Expand Down Expand Up @@ -909,6 +923,7 @@ public static OpenLoadFlowParameters load(PlatformConfig platformConfig) {
.setMinNominalVoltageTargetVoltageCheck(config.getDoubleProperty(MIN_NOMINAL_VOLTAGE_TARGET_VOLTAGE_CHECK_PARAM_NAME, LfNetworkParameters.MIN_NOMINAL_VOLTAGE_TARGET_VOLTAGE_CHECK_DEFAULT_VALUE))
.setReactivePowerDispatchMode(config.getEnumProperty(REACTIVE_POWER_DISPATCH_MODE_PARAM_NAME, ReactivePowerDispatchMode.class, REACTIVE_POWER_DISPATCH_MODE_DEFAULT_VALUE))
.setOuterLoopNames(config.getStringListProperty(OUTER_LOOP_NAMES_PARAM_NAME, OUTER_LOOP_NAMES_DEFAULT_VALUE))
.setUseActiveLimits(config.getBooleanProperty(USE_ACTIVE_LIMITS_PARAM_NAME, LfNetworkParameters.USE_ACTIVE_LIMITS_DEFAULT_VALUE))
);
return parameters;
}
Expand Down Expand Up @@ -1019,6 +1034,8 @@ public OpenLoadFlowParameters update(Map<String, String> properties) {
.ifPresent(prop -> this.setReactivePowerDispatchMode(ReactivePowerDispatchMode.valueOf(prop)));
Optional.ofNullable(properties.get(OUTER_LOOP_NAMES_PARAM_NAME))
.ifPresent(prop -> this.setOuterLoopNames(parseStringListProp(prop)));
Optional.ofNullable(properties.get(USE_ACTIVE_LIMITS_PARAM_NAME))
.ifPresent(prop -> this.setUseActiveLimits(Boolean.parseBoolean(prop)));
return this;
}

Expand Down Expand Up @@ -1071,6 +1088,7 @@ public Map<String, Object> toMap() {
map.put(MIN_NOMINAL_VOLTAGE_TARGET_VOLTAGE_CHECK_PARAM_NAME, minNominalVoltageTargetVoltageCheck);
map.put(REACTIVE_POWER_DISPATCH_MODE_PARAM_NAME, reactivePowerDispatchMode);
map.put(OUTER_LOOP_NAMES_PARAM_NAME, outerLoopNames);
map.put(USE_ACTIVE_LIMITS_PARAM_NAME, useActiveLimits);
return map;
}

Expand Down Expand Up @@ -1168,6 +1186,7 @@ static LfNetworkParameters getNetworkParameters(LoadFlowParameters parameters, O
.setTwtSplitShuntAdmittance(parameters.isTwtSplitShuntAdmittance())
.setBreakers(breakers)
.setPlausibleActivePowerLimit(parametersExt.getPlausibleActivePowerLimit())
.setUseActiveLimits(parametersExt.isUseActiveLimits())
.setComputeMainConnectedComponentOnly(parameters.getConnectedComponentMode() == LoadFlowParameters.ConnectedComponentMode.MAIN)
.setCountriesToBalance(parameters.getCountriesToBalance())
.setDistributedOnConformLoad(parameters.isDistributedSlack() && parameters.getBalanceType() == LoadFlowParameters.BalanceType.PROPORTIONAL_TO_CONFORM_LOAD)
Expand Down Expand Up @@ -1286,6 +1305,7 @@ public static DcLoadFlowParameters createDcParameters(LoadFlowParameters paramet
.setTwtSplitShuntAdmittance(false)
.setBreakers(false)
.setPlausibleActivePowerLimit(parametersExt.getPlausibleActivePowerLimit())
.setUseActiveLimits(parametersExt.isUseActiveLimits())
.setComputeMainConnectedComponentOnly(parameters.getConnectedComponentMode() == LoadFlowParameters.ConnectedComponentMode.MAIN)
.setCountriesToBalance(parameters.getCountriesToBalance())
.setDistributedOnConformLoad(parameters.isDistributedSlack() && parameters.getBalanceType() == LoadFlowParameters.BalanceType.PROPORTIONAL_TO_CONFORM_LOAD)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ public DcLoadFlowContext getContext() {
return context;
}

public static void distributeSlack(Collection<LfBus> buses, LoadFlowParameters.BalanceType balanceType) {
public static void distributeSlack(Collection<LfBus> buses, LoadFlowParameters.BalanceType balanceType, boolean useActiveLimits) {
double mismatch = getActivePowerMismatch(buses);
ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(balanceType, false);
ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(balanceType, false, useActiveLimits);
activePowerDistribution.run(buses, mismatch);
}

Expand Down Expand Up @@ -173,7 +173,7 @@ public DcLoadFlowResult run() {
initStateVector(network, equationSystem, new UniformValueVoltageInitializer());

if (parameters.isDistributedSlack()) {
distributeSlack(network.getBuses(), parameters.getBalanceType());
distributeSlack(network.getBuses(), parameters.getBalanceType(), parameters.getNetworkParameters().isUseActiveLimits());
}

// we need to copy the target array because JacobianMatrix.solveTransposed take as an input the second member
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ public void apply(LfNetworkParameters networkParameters) {
if (!generator.isDisabled()) {
generator.setTargetP(generator.getTargetP() + generatorChange.getDeltaTargetP());
if (!AbstractLfGenerator.checkActivePowerControl(generator.getId(), generator.getTargetP(), generator.getMinP(), generator.getMaxP(),
networkParameters.getPlausibleActivePowerLimit(), null)) {
networkParameters.getPlausibleActivePowerLimit(), networkParameters.isUseActiveLimits(), null)) {
generator.setParticipating(false);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class LfNetworkParameters {

public static final double PLAUSIBLE_ACTIVE_POWER_LIMIT_DEFAULT_VALUE = 5000;

public static final boolean USE_ACTIVE_LIMITS_DEFAULT_VALUE = true;

/**
* Minimal and maximal plausible target V in p.u
*/
Expand Down Expand Up @@ -63,6 +65,8 @@ public class LfNetworkParameters {

private double plausibleActivePowerLimit = PLAUSIBLE_ACTIVE_POWER_LIMIT_DEFAULT_VALUE;

private boolean useActiveLimits = USE_ACTIVE_LIMITS_DEFAULT_VALUE;

private boolean computeMainConnectedComponentOnly = true;

private Set<Country> countriesToBalance = Collections.emptySet();
Expand Down Expand Up @@ -209,6 +213,15 @@ public LfNetworkParameters setPlausibleActivePowerLimit(double plausibleActivePo
return this;
}

public boolean isUseActiveLimits() {
return useActiveLimits;
}

public LfNetworkParameters setUseActiveLimits(boolean useActiveLimits) {
this.useActiveLimits = useActiveLimits;
return this;
}

public boolean isComputeMainConnectedComponentOnly() {
return computeMainConnectedComponentOnly;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,40 +301,47 @@ public void setParticipating(boolean participating) {
}

public static boolean checkActivePowerControl(String generatorId, double targetP, double minP, double maxP, double plausibleActivePowerLimit,
LfNetworkLoadingReport report) {
boolean useActiveLimits, LfNetworkLoadingReport report) {
boolean participating = true;
if (Math.abs(targetP) < POWER_EPSILON_SI) {
LOGGER.trace("Discard generator '{}' from active power control because targetP ({}) equals 0",
LOGGER.trace("Discard generator '{}' from active power control because targetP ({} MW) equals 0",
generatorId, targetP);
if (report != null) {
report.generatorsDiscardedFromActivePowerControlBecauseTargetEqualsToZero++;
}
participating = false;
}
if (maxP > plausibleActivePowerLimit) {
// note that we still want this check applied even if active power limits are not to be enforced,
// e.g. in case of distribution modes proportional to maxP or remaining margin, we don't want to introduce crazy high participation
// factors for fictitious elements.
LOGGER.trace("Discard generator '{}' from active power control because maxP ({} MW) > plausibleLimit ({} MW)",
generatorId, maxP, plausibleActivePowerLimit);
if (report != null) {
report.generatorsDiscardedFromActivePowerControlBecauseMaxPNotPlausible++;
}
participating = false;
}
if (!useActiveLimits) {
// if active power limits are not to be enforced, we can skip the rest of the checks
return participating;
}
if (targetP > maxP) {
LOGGER.trace("Discard generator '{}' from active power control because targetP ({}) > maxP ({})",
LOGGER.trace("Discard generator '{}' from active power control because targetP ({} MW) > maxP ({} MW)",
generatorId, targetP, maxP);
if (report != null) {
report.generatorsDiscardedFromActivePowerControlBecauseTargetPGreaterThanMaxP++;
}
participating = false;
}
if (targetP < minP) {
LOGGER.trace("Discard generator '{}' from active power control because targetP ({}) < minP ({})",
LOGGER.trace("Discard generator '{}' from active power control because targetP ({} MW) < minP ({} MW)",
generatorId, targetP, minP);
if (report != null) {
report.generatorsDiscardedFromActivePowerControlBecauseTargetPLowerThanMinP++;
}
participating = false;
}
if (maxP > plausibleActivePowerLimit) {
LOGGER.trace("Discard generator '{}' from active power control because maxP ({}) > {}} MW",
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)",
generatorId, maxP, minP);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private LfBatteryImpl(Battery battery, LfNetwork network, LfNetworkParameters pa
}

if (!checkActivePowerControl(getId(), battery.getTargetP(), battery.getMinP(), battery.getMaxP(),
parameters.getPlausibleActivePowerLimit(), report)) {
parameters.getPlausibleActivePowerLimit(), parameters.isUseActiveLimits(), report)) {
participating = false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ private LfGeneratorImpl(Generator generator, LfNetwork network, LfNetworkParamet
}

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

Expand Down
Loading

0 comments on commit 04b52b2

Please sign in to comment.