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

Reduce irrealistic voltage created by remote voltage control #1135

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
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
7 changes: 5 additions & 2 deletions docs/loadflow/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,11 @@ 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 Newton-Raphson 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.
For any component where a bus voltage is, after the ReactiveLimits outerloop has run, solved outside these per-unit
thresholds, the component solution is deemed unrealistic and its solution status is flagged as failed.

The ReactiveLimits outerloop uses these values as a criteria to block P-only nodes to PQ.

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

**reactiveRangeCheckMode**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ protected static Optional<AcOuterLoop> createReactiveLimitsOuterLoop(LoadFlowPar
case UNIFORM_CRITERIA -> parametersExt.getNewtonRaphsonConvEpsPerEq();
case PER_EQUATION_TYPE_CRITERIA -> parametersExt.getMaxReactivePowerMismatch() / PerUnit.SB;
};
return Optional.of(new ReactiveLimitsOuterLoop(parametersExt.getReactiveLimitsMaxPqPvSwitch(), effectiveMaxReactivePowerMismatch));
return Optional.of(new ReactiveLimitsOuterLoop(parametersExt.getReactiveLimitsMaxPqPvSwitch(),
effectiveMaxReactivePowerMismatch,
parametersExt.getMinRealisticVoltage(),
parametersExt.getMaxRealisticVoltage()));
}
return Optional.empty();
}
Expand Down
36 changes: 32 additions & 4 deletions src/main/java/com/powsybl/openloadflow/ac/AcloadFlowEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ private static class RunningContext {
private final MutableInt nrTotalIterations = new MutableInt();

private OuterLoopResult lastOuterLoopResult = OuterLoopResult.stable();

private AcOuterLoop lastUnrealisticStateFixingLoop;
}

private void runOuterLoop(AcOuterLoop outerLoop, AcOuterLoopContext outerLoopContext, AcSolver solver, RunningContext runningContext) {
private void runOuterLoop(AcOuterLoop outerLoop, AcOuterLoopContext outerLoopContext, AcSolver solver, RunningContext runningContext, boolean canCheckUnrealistic) {
ReportNode olReportNode = Reports.createOuterLoopReporter(outerLoopContext.getNetwork().getReportNode(), outerLoop.getName());

// for each outer loop re-run solver until stabilization
Expand Down Expand Up @@ -95,7 +97,7 @@ private void runOuterLoop(AcOuterLoop outerLoop, AcOuterLoopContext outerLoopCon
}

// if not yet stable, restart solver
runningContext.lastSolverResult = solver.run(new PreviousValueVoltageInitializer(), reportNode);
runningContext.lastSolverResult = solver.run(new PreviousValueVoltageInitializer(), reportNode, canCheckUnrealistic);

runningContext.nrTotalIterations.add(runningContext.lastSolverResult.getIterations());
runningContext.outerLoopTotalIterations++;
Expand All @@ -106,6 +108,16 @@ private void runOuterLoop(AcOuterLoop outerLoop, AcOuterLoopContext outerLoopCon
&& runningContext.lastSolverResult.getStatus() == AcSolverStatus.CONVERGED
&& runningContext.outerLoopTotalIterations < context.getParameters().getMaxOuterLoopIterations());

if (!canCheckUnrealistic && runningContext.lastUnrealisticStateFixingLoop == outerLoop && runningContext.lastSolverResult.getStatus() == AcSolverStatus.CONVERGED) {
SylvestreSakti marked this conversation as resolved.
Show resolved Hide resolved
// This is time to check the unrealistic state and create a report if needed
boolean isStateUnrealistic = solver.isStateUnrealisticForSolver(context.getNetwork().getReportNode());
if (isStateUnrealistic) {
runningContext.lastSolverResult = new AcSolverResult(AcSolverStatus.UNREALISTIC_STATE,
runningContext.lastSolverResult.getIterations(),
runningContext.lastSolverResult.getSlackBusActivePowerMismatch());
}
}

if (outerLoopResult.status() != OuterLoopStatus.STABLE) {
Reports.reportUnsuccessfulOuterLoop(olReportNode, outerLoopResult.status().name());
}
Expand Down Expand Up @@ -166,8 +178,17 @@ public AcLoadFlowResult run() {
context.getNetwork().getNumCC(),
context.getNetwork().getNumSC());
}

runningContext.lastUnrealisticStateFixingLoop = outerLoopsAndContexts.stream()
.map(Pair::getLeft)
.filter(AcOuterLoop::canFixUnrealisticState)
.reduce((first, second) -> second).orElse(null);

// Don't check unrealistic voltage yet if an outer loop can fix them
boolean canCheckUnrealisticStates = runningContext.lastUnrealisticStateFixingLoop == null;

// initial solver run
runningContext.lastSolverResult = solver.run(voltageInitializer, reportNode);
runningContext.lastSolverResult = solver.run(voltageInitializer, reportNode, canCheckUnrealisticStates);

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

Expand All @@ -177,11 +198,18 @@ public AcLoadFlowResult run() {
// re-run all outer loops until solver failed or no more solver iterations are needed
int oldNrTotalIterations;
do {
// Restore the flag before each outerloop iteration
canCheckUnrealisticStates = runningContext.lastUnrealisticStateFixingLoop == null;

oldNrTotalIterations = runningContext.nrTotalIterations.getValue();

// outer loops are nested: innermost loop first in the list, outermost loop last
for (var outerLoopAndContext : outerLoopsAndContexts) {
runOuterLoop(outerLoopAndContext.getLeft(), outerLoopAndContext.getRight(), solver, runningContext);
runOuterLoop(outerLoopAndContext.getLeft(), outerLoopAndContext.getRight(), solver, runningContext, canCheckUnrealisticStates);

if (outerLoopAndContext.getLeft() == runningContext.lastUnrealisticStateFixingLoop) {
canCheckUnrealisticStates = true;
}

// continue with next outer loop only if:
// - last solver run succeed,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,13 @@
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
*/
public interface AcOuterLoop extends OuterLoop<AcVariableType, AcEquationType, AcLoadFlowParameters, AcLoadFlowContext, AcOuterLoopContext> {

/**
* Returns true if the outerloop can fix unrealistic states. For an outerloop returning True, unrealistic states should not interrupt
* the solving process before this outerloop is stabilized.
*/
default boolean canFixUnrealisticState() {
return false;
}

}
Loading
Loading