Skip to content

Add parameter to define min nominal voltage for unrealistic state check #1217

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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
26 changes: 21 additions & 5 deletions docs/loadflow/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,9 @@ The default values are `0.8` and `1.2` and they must be greater or equal to `0`.
**minRealisticVoltage** and **maxRealisticVoltage**
These parameters are used to identify if the AC Solver has converged to an unrealistic state.

For any component where a bus voltage is solved outside these per-unit
thresholds, the component solution is deemed unrealistic and its solution status is flagged as failed.
If there is any bus in a voltage level higher than 'minNominalVoltageUnrealisticStateCheck', with
a computed voltage outside these per-unit thresholds, the component solution is deemed unrealistic and
its solution status is flagged as failed.

If `voltageRemoteControlRobustMode` is set to true, the check of unrealistic voltage is done after the
ReactiveLimits outerloop has been used. In addition, the ReactiveLimits outerloop uses these values as a
Expand All @@ -321,6 +322,19 @@ their reactive diagram.

The default values are `0.5` and `2.0` and they must be greater or equal to `0`.

**minNominalVoltageUnrealisticStateCheck**
Copy link
Member

Choose a reason for hiding this comment

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

Probably subjective, but I find this name minNominalVoltageUnrealisticStateCheck difficult to correlate with the 2 others parameters minRealisticVoltage & maxRealisticVoltage, proposing to have RealisticVoltage part in all 3 parameters, e.g.:

  • minRealisticVoltage
  • maxRealisticVoltage
  • minNominalVoltageRealisticVoltageCheck

which would also be consistent with existing minNominalVoltageTargetVoltageCheck (also in kV)

This parameter defines the minimal nominal voltage, in kV, for which a bus oustide of **minRealisticVoltage**
and **maxRealisticVoltage** will stop the simulation.

Unrealistic voltage, especially in high voltage substations, may trigger automates or other dangerous phenomenons,
with a potentially large impact to the system, that a static simulator may not take correctly into account. In this case,
the result of the simulation should not be used without special caution.

The default value is '0' for compatibility reasons.

An example of configuration that provides good level of simulation trust as well as resilience to local observability issues
would be 0.8 and 1.2 for **minRealisticVoltage** and **maxRealisticVoltage** and 100 for **minNominalVoltageUnrealisticStateCheck**
Comment on lines +329 to +336
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Unrealistic voltage, especially in high voltage substations, may trigger automates or other dangerous phenomenons,
with a potentially large impact to the system, that a static simulator may not take correctly into account. In this case,
the result of the simulation should not be used without special caution.
The default value is '0' for compatibility reasons.
An example of configuration that provides good level of simulation trust as well as resilience to local observability issues
would be 0.8 and 1.2 for **minRealisticVoltage** and **maxRealisticVoltage** and 100 for **minNominalVoltageUnrealisticStateCheck**
Unrealistic voltages -particularly in high-voltage substations- can trigger automated protections or other hazardous phenomena, potentially causing significant impacts to the system. Steady-state simulation may not accurately account for these effects. Therefore, results obtained under such conditions should be interpreted with caution.
A configuration that offers both reliable simulation results and resilience to local observability issues could, for example, use 0.8 and 1.2 p.u. for **minRealisticVoltage** and **maxRealisticVoltage**, respectively, and 100 kV for **minNominalVoltageUnrealisticStateCheck**.
The default value is 0 kV.


**reactiveRangeCheckMode**
Open Load Flow discards voltage control for generators with a too small reactive power range, because in practice a too
small reactive power ranger means limited to zero voltage control capability.
Expand Down Expand Up @@ -387,9 +401,11 @@ Allows to ignore active power limits during calculations. Active power limits ar
Disables voltage control for generators with `targetP` outside the interval [`minP`, `maxP`]. The default value is `false`.

**minNominalVoltageTargetVoltageCheck**
This parameter defines the minimal nominal voltage to check the target of voltage control in per-unit.
The default value is `20 kV`, meaning that under the controlled buses of voltage levels under this value are ignored from the check.
It must be greater or equal to `0 kV`.
This parameter defines the minimal nominal voltage, in kV, for which the plausible voltage target checks are applied.

Above this voltage level, voltage targets that are, in pu, outside 'minPlausibleTargetVoltage' - 'maxPlausibleTargetVoltage' are ignored.

The default value is `20 kV`. It must be greater or equal to `0 kV`.

**reactivePowerDispatchMode**
This parameter defines how reactive power is split among generators with controls (voltage or reactive power).
Expand Down
25 changes: 23 additions & 2 deletions src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ public enum FictitiousGeneratorVoltageControlCheckMode {

public static final String MAX_REALISTIC_VOLTAGE_PARAM_NAME = "maxRealisticVoltage";

public static final String MIN_NOMINAL_VOLTAGE_UNREALISTIC_STATE_CHECK_PARAM_NAME = "minNominalVoltageUnrealisticStateCheck";

public static final String MIN_NOMINAL_VOLTAGE_TARGET_VOLTAGE_CHECK_PARAM_NAME = "minNominalVoltageTargetVoltageCheck";

public static final String REACTIVE_RANGE_CHECK_MODE_PARAM_NAME = "reactiveRangeCheckMode";
Expand Down Expand Up @@ -388,6 +390,7 @@ public static List<Object> getAcSolverTypePossibleValues() {
new Parameter(MAX_PLAUSIBLE_TARGET_VOLTAGE_PARAM_NAME, ParameterType.DOUBLE, "Max plausible target voltage", LfNetworkParameters.MAX_PLAUSIBLE_TARGET_VOLTAGE_DEFAULT_VALUE, ParameterScope.FUNCTIONAL, VOLTAGE_CONTROLS_CATEGORY_KEY),
new Parameter(MIN_REALISTIC_VOLTAGE_PARAM_NAME, ParameterType.DOUBLE, "Min realistic voltage", AcLoadFlowParameters.DEFAULT_MIN_REALISTIC_VOLTAGE, ParameterScope.FUNCTIONAL, VOLTAGE_CONTROLS_CATEGORY_KEY),
new Parameter(MAX_REALISTIC_VOLTAGE_PARAM_NAME, ParameterType.DOUBLE, "Max realistic voltage", AcLoadFlowParameters.DEFAULT_MAX_REALISTIC_VOLTAGE, ParameterScope.FUNCTIONAL, VOLTAGE_CONTROLS_CATEGORY_KEY),
new Parameter(MIN_NOMINAL_VOLTAGE_UNREALISTIC_STATE_CHECK_PARAM_NAME, ParameterType.DOUBLE, "Min nominal voltage unrealistic state check", AcLoadFlowParameters.DEFAULT_MIN_NOMINAL_VOLTAGE_UNREALISTIC_STATE_CHECK, ParameterScope.FUNCTIONAL, VOLTAGE_CONTROLS_CATEGORY_KEY),
new Parameter(REACTIVE_RANGE_CHECK_MODE_PARAM_NAME, ParameterType.STRING, "Reactive range check mode", LfNetworkParameters.REACTIVE_RANGE_CHECK_MODE_DEFAULT_VALUE.name(), getEnumPossibleValues(ReactiveRangeCheckMode.class), ParameterScope.FUNCTIONAL, GENERATOR_VOLTAGE_CONTROL_CATEGORY_KEY),
new Parameter(LOW_IMPEDANCE_THRESHOLD_PARAM_NAME, ParameterType.DOUBLE, "Low impedance threshold in per unit", LfNetworkParameters.LOW_IMPEDANCE_THRESHOLD_DEFAULT_VALUE, ParameterScope.FUNCTIONAL, MODEL_CATEGORY_KEY),
new Parameter(NETWORK_CACHE_ENABLED_PARAM_NAME, ParameterType.BOOLEAN, "Network cache enabled", LfNetworkParameters.CACHE_ENABLED_DEFAULT_VALUE, ParameterScope.FUNCTIONAL, FAST_RESTART_CATEGORY_KEY),
Expand Down Expand Up @@ -536,6 +539,8 @@ public enum LowImpedanceBranchMode {

private double maxRealisticVoltage = AcLoadFlowParameters.DEFAULT_MAX_REALISTIC_VOLTAGE;

private double minNominalVoltageUnrealisticStateCheck = AcLoadFlowParameters.DEFAULT_MIN_NOMINAL_VOLTAGE_UNREALISTIC_STATE_CHECK;

private double lowImpedanceThreshold = LfNetworkParameters.LOW_IMPEDANCE_THRESHOLD_DEFAULT_VALUE;

public enum ReactiveRangeCheckMode {
Expand Down Expand Up @@ -957,6 +962,15 @@ public OpenLoadFlowParameters setMaxRealisticVoltage(double maxRealisticVoltage)
return this;
}

public double getMinNominalVoltageUnrealisticStateCheck() {
return minNominalVoltageUnrealisticStateCheck;
}

public OpenLoadFlowParameters setMinNominalVoltageUnrealisticStateCheck(double minNominalVoltageUnrealisticStateCheck) {
this.minNominalVoltageUnrealisticStateCheck = minNominalVoltageUnrealisticStateCheck;
return this;
}

public ReactiveRangeCheckMode getReactiveRangeCheckMode() {
return reactiveRangeCheckMode;
}
Expand Down Expand Up @@ -1441,6 +1455,7 @@ public OpenLoadFlowParameters update(PlatformConfig platformConfig) {
config.getOptionalDoubleProperty(MAX_PLAUSIBLE_TARGET_VOLTAGE_PARAM_NAME).ifPresent(this::setMaxPlausibleTargetVoltage);
config.getOptionalDoubleProperty(MIN_REALISTIC_VOLTAGE_PARAM_NAME).ifPresent(this::setMinRealisticVoltage);
config.getOptionalDoubleProperty(MAX_REALISTIC_VOLTAGE_PARAM_NAME).ifPresent(this::setMaxRealisticVoltage);
config.getOptionalDoubleProperty(MIN_NOMINAL_VOLTAGE_UNREALISTIC_STATE_CHECK_PARAM_NAME).ifPresent(this::setMinNominalVoltageUnrealisticStateCheck);
config.getOptionalEnumProperty(REACTIVE_RANGE_CHECK_MODE_PARAM_NAME, ReactiveRangeCheckMode.class)
.ifPresent(this::setReactiveRangeCheckMode);
config.getOptionalDoubleProperty(LOW_IMPEDANCE_THRESHOLD_PARAM_NAME).ifPresent(this::setLowImpedanceThreshold);
Expand Down Expand Up @@ -1565,6 +1580,8 @@ public OpenLoadFlowParameters update(Map<String, String> properties) {
.ifPresent(prop -> this.setMinRealisticVoltage(Double.parseDouble(prop)));
Optional.ofNullable(properties.get(MAX_REALISTIC_VOLTAGE_PARAM_NAME))
.ifPresent(prop -> this.setMaxRealisticVoltage(Double.parseDouble(prop)));
Optional.ofNullable(properties.get(MIN_NOMINAL_VOLTAGE_UNREALISTIC_STATE_CHECK_PARAM_NAME))
.ifPresent(prop -> this.setMinNominalVoltageUnrealisticStateCheck(Double.parseDouble(prop)));
Optional.ofNullable(properties.get(REACTIVE_RANGE_CHECK_MODE_PARAM_NAME))
.ifPresent(prop -> this.setReactiveRangeCheckMode(ReactiveRangeCheckMode.valueOf(prop)));
Optional.ofNullable(properties.get(LOW_IMPEDANCE_THRESHOLD_PARAM_NAME))
Expand Down Expand Up @@ -1693,6 +1710,7 @@ public Map<String, Object> toMap() {
map.put(MAX_PLAUSIBLE_TARGET_VOLTAGE_PARAM_NAME, maxPlausibleTargetVoltage);
map.put(MIN_REALISTIC_VOLTAGE_PARAM_NAME, minRealisticVoltage);
map.put(MAX_REALISTIC_VOLTAGE_PARAM_NAME, maxRealisticVoltage);
map.put(MIN_NOMINAL_VOLTAGE_UNREALISTIC_STATE_CHECK_PARAM_NAME, minNominalVoltageUnrealisticStateCheck);
map.put(REACTIVE_RANGE_CHECK_MODE_PARAM_NAME, reactiveRangeCheckMode);
map.put(LOW_IMPEDANCE_THRESHOLD_PARAM_NAME, lowImpedanceThreshold);
map.put(NETWORK_CACHE_ENABLED_PARAM_NAME, networkCacheEnabled);
Expand Down Expand Up @@ -1958,7 +1976,8 @@ public static AcLoadFlowParameters createAcParameters(LoadFlowParameters paramet
.setSolverFactory(solverFactory, parameters)
.setVoltageRemoteControlRobustMode(parametersExt.isVoltageRemoteControlRobustMode())
.setMinRealisticVoltage(parametersExt.minRealisticVoltage)
.setMaxRealisticVoltage(parametersExt.maxRealisticVoltage);
.setMaxRealisticVoltage(parametersExt.maxRealisticVoltage)
.setMinNominalVoltageUnrealisticStateCheck(parametersExt.getMinNominalVoltageUnrealisticStateCheck());
}

public static DcLoadFlowParameters createDcParameters(Network network, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt,
Expand Down Expand Up @@ -2138,7 +2157,8 @@ public static boolean equals(LoadFlowParameters parameters1, LoadFlowParameters
extension1.getAreaInterchangePMaxMismatch() == extension2.getAreaInterchangePMaxMismatch() &&
extension1.isVoltageRemoteControlRobustMode() == extension2.isVoltageRemoteControlRobustMode() &&
extension1.isForceTargetQInReactiveLimits() == extension2.isForceTargetQInReactiveLimits() &&
extension1.isDisableInconsistentVoltageControls() == extension2.isDisableInconsistentVoltageControls();
extension1.isDisableInconsistentVoltageControls() == extension2.isDisableInconsistentVoltageControls() &&
extension1.getMinNominalVoltageUnrealisticStateCheck() == extension2.getMinNominalVoltageUnrealisticStateCheck();
}

public static LoadFlowParameters clone(LoadFlowParameters parameters) {
Expand Down Expand Up @@ -2185,6 +2205,7 @@ public static LoadFlowParameters clone(LoadFlowParameters parameters) {
.setMaxPlausibleTargetVoltage(extension.getMaxPlausibleTargetVoltage())
.setMinRealisticVoltage(extension.getMinRealisticVoltage())
.setMaxRealisticVoltage(extension.getMaxRealisticVoltage())
.setMinNominalVoltageUnrealisticStateCheck(extension.getMinNominalVoltageUnrealisticStateCheck())
.setReactiveRangeCheckMode(extension.getReactiveRangeCheckMode())
.setLowImpedanceThreshold(extension.getLowImpedanceThreshold())
.setNetworkCacheEnabled(extension.isNetworkCacheEnabled())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class AcLoadFlowParameters extends AbstractLoadFlowParameters<AcLoadFlowP

public static final double DEFAULT_MIN_REALISTIC_VOLTAGE = 0.5;
public static final double DEFAULT_MAX_REALISTIC_VOLTAGE = 2;
public static final double DEFAULT_MIN_NOMINAL_VOLTAGE_UNREALISTIC_STATE_CHECK = 0;

private AcEquationSystemCreationParameters equationSystemCreationParameters = new AcEquationSystemCreationParameters();

Expand All @@ -53,6 +54,8 @@ public class AcLoadFlowParameters extends AbstractLoadFlowParameters<AcLoadFlowP

private double maxRealisticVoltage = DEFAULT_MAX_REALISTIC_VOLTAGE;

private double minNominalVoltageUnrealisticStateCheck = DEFAULT_MIN_NOMINAL_VOLTAGE_UNREALISTIC_STATE_CHECK;

public AcEquationSystemCreationParameters getEquationSystemCreationParameters() {
return equationSystemCreationParameters;
}
Expand Down Expand Up @@ -148,6 +151,15 @@ public AcLoadFlowParameters setMaxRealisticVoltage(double maxRealisticVoltage) {
return this;
}

public double getMinNominalVoltageUnrealisticStateCheck() {
return minNominalVoltageUnrealisticStateCheck;
}

public AcLoadFlowParameters setMinNominalVoltageUnrealisticStateCheck(double minNominalVoltageUnrealisticStateCheck) {
this.minNominalVoltageUnrealisticStateCheck = minNominalVoltageUnrealisticStateCheck;
return this;
}

@Override
public String toString() {
return "AcLoadFlowParameters(" +
Expand All @@ -165,6 +177,7 @@ public String toString() {
", voltageRemoteControlRobustMode=" + voltageRemoteControlRobustMode +
", minRealisticVoltage=" + minRealisticVoltage +
", maxRealisticVoltage=" + maxRealisticVoltage +
", minNominalVoltageUnrealisticStateCheck=" + minNominalVoltageUnrealisticStateCheck +
')';
}
}
22 changes: 15 additions & 7 deletions src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ private void runOuterLoop(AcOuterLoop outerLoop, AcOuterLoopContext outerLoopCon
}

// if not yet stable, restart solver
runningContext.lastSolverResult = runAcSolverAndCheckRealisticState(solver, new PreviousValueVoltageInitializer(), reportNode, checkUnrealistic);
runningContext.lastSolverResult = runAcSolverAndCheckRealisticState(solver, new PreviousValueVoltageInitializer(), reportNode, checkUnrealistic,
outerLoopContext.getLoadFlowContext().getParameters());

runningContext.nrTotalIterations.add(runningContext.lastSolverResult.getIterations());
runningContext.outerLoopTotalIterations++;
Expand All @@ -108,8 +109,11 @@ private void runOuterLoop(AcOuterLoop outerLoop, AcOuterLoopContext outerLoopCon
&& runningContext.outerLoopTotalIterations < context.getParameters().getMaxOuterLoopIterations());

if (!checkUnrealistic && runningContext.lastUnrealisticStateFixingLoop == outerLoop && runningContext.lastSolverResult.getStatus() == AcSolverStatus.CONVERGED) {

// This is time to check the unrealistic state and create a report if needed
boolean isStateUnrealistic = isStateUnrealistic(context.getNetwork().getReportNode());
boolean isStateUnrealistic = isStateUnrealistic(context.getNetwork().getReportNode(),
outerLoopContext.getLoadFlowContext().getParameters().getMinNominalVoltageUnrealisticStateCheck());

if (isStateUnrealistic) {
runningContext.lastSolverResult = new AcSolverResult(AcSolverStatus.UNREALISTIC_STATE,
runningContext.lastSolverResult.getIterations(),
Expand All @@ -122,7 +126,8 @@ private void runOuterLoop(AcOuterLoop outerLoop, AcOuterLoopContext outerLoopCon
}
}

private boolean isStateUnrealistic(ReportNode reportNode) {
private boolean isStateUnrealistic(ReportNode reportNode, double minNominalVoltageUnrealisticStateCheck) {

EquationSystem<AcVariableType, AcEquationType> equationSystem = context.getEquationSystem();
AcLoadFlowParameters parameters = context.getParameters();
LfNetwork network = context.getNetwork();
Expand All @@ -131,7 +136,10 @@ private boolean isStateUnrealistic(ReportNode reportNode) {
if (v.getType() == AcVariableType.BUS_V && !network.getBus(v.getElementNum()).isFictitious()) {
double value = equationSystem.getStateVector().get(v.getRow());
if (value < parameters.getMinRealisticVoltage() || value > parameters.getMaxRealisticVoltage()) {
busesOutOfNormalVoltageRange.put(network.getBus(v.getElementNum()).getId(), value);
// only consider unrealistic if nominal voltage high enough
if (network.getBus(v.getElementNum()).getNominalV() >= minNominalVoltageUnrealisticStateCheck) {
busesOutOfNormalVoltageRange.put(network.getBus(v.getElementNum()).getId(), value);
}
}
}
}
Expand All @@ -150,10 +158,10 @@ private boolean isStateUnrealistic(ReportNode reportNode) {
}

private AcSolverResult runAcSolverAndCheckRealisticState(AcSolver solver, VoltageInitializer voltageInitializer,
ReportNode reportNode, boolean checkUnrealistic) {
ReportNode reportNode, boolean checkUnrealistic, AcLoadFlowParameters parameters) {
AcSolverResult result = solver.run(voltageInitializer, reportNode);

if (checkUnrealistic && result.getStatus() == AcSolverStatus.CONVERGED && isStateUnrealistic(reportNode)) {
if (checkUnrealistic && result.getStatus() == AcSolverStatus.CONVERGED && isStateUnrealistic(reportNode, parameters.getMinNominalVoltageUnrealisticStateCheck())) {
result = new AcSolverResult(AcSolverStatus.UNREALISTIC_STATE, result.getIterations(), result.getSlackBusActivePowerMismatch());
}

Expand Down Expand Up @@ -230,7 +238,7 @@ public AcLoadFlowResult run() {
boolean checkUnrealisticStates = runningContext.lastUnrealisticStateFixingLoop == null;

// initial solver run
runningContext.lastSolverResult = runAcSolverAndCheckRealisticState(solver, voltageInitializer, reportNode, checkUnrealisticStates);
runningContext.lastSolverResult = runAcSolverAndCheckRealisticState(solver, voltageInitializer, reportNode, checkUnrealisticStates, context.getParameters());

runningContext.nrTotalIterations.add(runningContext.lastSolverResult.getIterations());

Expand Down
Loading