diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java index 1cb6b55078..c035c85c34 100644 --- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java +++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java @@ -19,9 +19,7 @@ import com.powsybl.openloadflow.ac.ReactiveLimitsOuterLoop; import com.powsybl.openloadflow.ac.VoltageMagnitudeInitializer; import com.powsybl.openloadflow.ac.equations.AcEquationSystemCreationParameters; -import com.powsybl.openloadflow.ac.nr.DefaultNewtonRaphsonStoppingCriteria; -import com.powsybl.openloadflow.ac.nr.NewtonRaphsonParameters; -import com.powsybl.openloadflow.ac.nr.StateVectorScalingMode; +import com.powsybl.openloadflow.ac.nr.*; import com.powsybl.openloadflow.ac.outerloop.AcLoadFlowParameters; import com.powsybl.openloadflow.ac.outerloop.OuterLoop; import com.powsybl.openloadflow.dc.DcLoadFlowParameters; @@ -63,6 +61,23 @@ public class OpenLoadFlowParameters extends AbstractExtension> List getEnumPossibleValues(Class e new Parameter(DEBUG_DIR_PARAM_NAME, ParameterType.STRING, "Directory to dump debug files", LfNetworkParameters.DEBUG_DIR_DEFAULT_VALUE, Collections.emptyList(), ParameterScope.TECHNICAL), 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) + new Parameter(REACTIVE_LIMITS_MAX_SWITCH_PQ_PV_PARAM_NAME, ParameterType.INTEGER, "Reactive limits maximum Pq Pv switch", ReactiveLimitsOuterLoop.MAX_SWITCH_PQ_PV), + 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), + new Parameter(MAX_ANGLE_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum angle for per equation stopping criteria", MAX_ANGLE_MISMATCH_DEFAULT_VALUE), + new Parameter(MAX_RATIO_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum ratio for per equation stopping criteria", MAX_RATIO_MISMATCH_DEFAULT_VALUE), + new Parameter(MAX_SUSCEPTANCE_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Maximum susceptance for per equation stopping criteria", MAX_SUSCEPTANCE_MISMATCH_DEFAULT_VALUE) ); public enum VoltageInitModeOverride { @@ -208,6 +244,20 @@ public enum LowImpedanceBranchMode { private double plausibleActivePowerLimit = LfNetworkParameters.PLAUSIBLE_ACTIVE_POWER_LIMIT_DEFAULT_VALUE; + private NewtonRaphsonStoppingCriteriaType newtonRaphsonStoppingCriteriaType = NEWTONRAPHSON_STOPPING_CRITERIA_TYPE_DEFAULT_VALUE; + + private double maxActivePowerMismatch = MAX_ACTIVE_POWER_MISMATCH_DEFAULT_VALUE; + + private double maxReactivePowerMismatch = MAX_REACTIVE_POWER_MISMATCH_DEFAULT_VALUE; + + private double maxVoltageMismatch = MAX_VOLTAGE_MISMATCH_DEFAULT_VALUE; + + private double maxAngleMismatch = MAX_ANGLE_MISMATCH_DEFAULT_VALUE; + + private double maxRatioMismatch = MAX_RATIO_MISMATCH_DEFAULT_VALUE; + + private double maxSusceptanceMismatch = MAX_SUSCEPTANCE_MISMATCH_DEFAULT_VALUE; + private double slackBusPMaxMismatch = SLACK_BUS_P_MAX_MISMATCH_DEFAULT_VALUE; private boolean voltagePerReactivePowerControl = VOLTAGE_PER_REACTIVE_POWER_CONTROL_DEFAULT_VALUE; @@ -381,6 +431,87 @@ public OpenLoadFlowParameters setNewtonRaphsonConvEpsPerEq(double newtonRaphsonC return this; } + public NewtonRaphsonStoppingCriteriaType getNewtonRaphsonStoppingCriteriaType() { + return newtonRaphsonStoppingCriteriaType; + } + + public OpenLoadFlowParameters setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType newtonRaphsonStoppingCriteriaType) { + this.newtonRaphsonStoppingCriteriaType = Objects.requireNonNull(newtonRaphsonStoppingCriteriaType); + return this; + } + + public double getMaxActivePowerMismatch() { + return maxActivePowerMismatch; + } + + public OpenLoadFlowParameters setMaxActivePowerMismatch(double maxActivePowerMismatch) { + if (maxActivePowerMismatch <= 0) { + throw new PowsyblException("maxActivePowerMismatch must be greater to 0"); + } + this.maxActivePowerMismatch = maxActivePowerMismatch; + return this; + } + + public double getMaxReactivePowerMismatch() { + return maxReactivePowerMismatch; + } + + public OpenLoadFlowParameters setMaxReactivePowerMismatch(double maxReactivePowerMismatch) { + if (maxReactivePowerMismatch <= 0) { + throw new PowsyblException("maxReactivePowerMismatch must be greater to 0"); + } + this.maxReactivePowerMismatch = maxReactivePowerMismatch; + return this; + } + + public double getMaxVoltageMismatch() { + return maxVoltageMismatch; + } + + public OpenLoadFlowParameters setMaxVoltageMismatch(double maxVoltageMismatch) { + if (maxVoltageMismatch <= 0) { + throw new PowsyblException("maxVoltageMismatch must be greater to 0"); + } + this.maxVoltageMismatch = maxVoltageMismatch; + return this; + } + + public double getMaxAngleMismatch() { + return maxAngleMismatch; + } + + public OpenLoadFlowParameters setMaxAngleMismatch(double maxAngleMismatch) { + if (maxAngleMismatch <= 0) { + throw new PowsyblException("maxAngleMismatch must be greater to 0"); + } + this.maxAngleMismatch = maxAngleMismatch; + return this; + } + + public double getMaxRatioMismatch() { + return maxRatioMismatch; + } + + public OpenLoadFlowParameters setMaxRatioMismatch(double maxRatioMismatch) { + if (maxRatioMismatch <= 0) { + throw new PowsyblException("maxRatioMismatch must be greater to 0"); + } + this.maxRatioMismatch = maxRatioMismatch; + return this; + } + + public double getMaxSusceptanceMismatch() { + return maxSusceptanceMismatch; + } + + public OpenLoadFlowParameters setMaxSusceptanceMismatch(double maxSusceptanceMismatch) { + if (maxSusceptanceMismatch <= 0) { + throw new PowsyblException("maxSusceptanceMismatch must be greater to 0"); + } + this.maxSusceptanceMismatch = maxSusceptanceMismatch; + return this; + } + public VoltageInitModeOverride getVoltageInitModeOverride() { return voltageInitModeOverride; } @@ -569,6 +700,13 @@ public static OpenLoadFlowParameters load(PlatformConfig platformConfig) { ) .setLoadPowerFactorConstant(config.getBooleanProperty(LOAD_POWER_FACTOR_CONSTANT_PARAM_NAME, LOAD_POWER_FACTOR_CONSTANT_DEFAULT_VALUE)) .setPlausibleActivePowerLimit(config.getDoubleProperty(PLAUSIBLE_ACTIVE_POWER_LIMIT_PARAM_NAME, LfNetworkParameters.PLAUSIBLE_ACTIVE_POWER_LIMIT_DEFAULT_VALUE)) + .setNewtonRaphsonStoppingCriteriaType(config.getEnumProperty(NEWTONRAPHSON_STOPPING_CRITERIA_TYPE_PARAM_NAME, NewtonRaphsonStoppingCriteriaType.class, NEWTONRAPHSON_STOPPING_CRITERIA_TYPE_DEFAULT_VALUE)) + .setMaxActivePowerMismatch(config.getDoubleProperty(MAX_ACTIVE_POWER_MISMATCH_PARAM_NAME, MAX_ACTIVE_POWER_MISMATCH_DEFAULT_VALUE)) + .setMaxReactivePowerMismatch(config.getDoubleProperty(MAX_REACTIVE_POWER_MISMATCH_PARAM_NAME, MAX_REACTIVE_POWER_MISMATCH_DEFAULT_VALUE)) + .setMaxVoltageMismatch(config.getDoubleProperty(MAX_VOLTAGE_MISMATCH_PARAM_NAME, MAX_VOLTAGE_MISMATCH_DEFAULT_VALUE)) + .setMaxAngleMismatch(config.getDoubleProperty(MAX_ANGLE_MISMATCH_PARAM_NAME, MAX_ANGLE_MISMATCH_DEFAULT_VALUE)) + .setMaxRatioMismatch(config.getDoubleProperty(MAX_RATIO_MISMATCH_PARAM_NAME, MAX_RATIO_MISMATCH_DEFAULT_VALUE)) + .setMaxSusceptanceMismatch(config.getDoubleProperty(MAX_SUSCEPTANCE_MISMATCH_PARAM_NAME, MAX_SUSCEPTANCE_MISMATCH_DEFAULT_VALUE)) .setSlackBusPMaxMismatch(config.getDoubleProperty(SLACK_BUS_P_MAX_MISMATCH_NAME, SLACK_BUS_P_MAX_MISMATCH_DEFAULT_VALUE)) .setVoltagePerReactivePowerControl(config.getBooleanProperty(VOLTAGE_PER_REACTIVE_POWER_CONTROL_NAME, VOLTAGE_PER_REACTIVE_POWER_CONTROL_DEFAULT_VALUE)) .setReactivePowerRemoteControl(config.getBooleanProperty(REACTIVE_POWER_REMOTE_CONTROL_PARAM_NAME, REACTIVE_POWER_REMOTE_CONTROL_DEFAULT_VALUE)) @@ -615,6 +753,20 @@ public OpenLoadFlowParameters update(Map properties) { .ifPresent(prop -> this.setLoadPowerFactorConstant(Boolean.parseBoolean(prop))); Optional.ofNullable(properties.get(PLAUSIBLE_ACTIVE_POWER_LIMIT_PARAM_NAME)) .ifPresent(prop -> this.setPlausibleActivePowerLimit(Double.parseDouble(prop))); + Optional.ofNullable(properties.get(NEWTONRAPHSON_STOPPING_CRITERIA_TYPE_PARAM_NAME)) + .ifPresent(prop -> this.setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.valueOf(prop))); + Optional.ofNullable(properties.get(MAX_ACTIVE_POWER_MISMATCH_PARAM_NAME)) + .ifPresent(prop -> this.setMaxActivePowerMismatch(Double.parseDouble(prop))); + Optional.ofNullable(properties.get(MAX_REACTIVE_POWER_MISMATCH_PARAM_NAME)) + .ifPresent(prop -> this.setMaxReactivePowerMismatch(Double.parseDouble(prop))); + Optional.ofNullable(properties.get(MAX_VOLTAGE_MISMATCH_PARAM_NAME)) + .ifPresent(prop -> this.setMaxVoltageMismatch(Double.parseDouble(prop))); + Optional.ofNullable(properties.get(MAX_ANGLE_MISMATCH_PARAM_NAME)) + .ifPresent(prop -> this.setMaxAngleMismatch(Double.parseDouble(prop))); + Optional.ofNullable(properties.get(MAX_RATIO_MISMATCH_PARAM_NAME)) + .ifPresent(prop -> this.setMaxRatioMismatch(Double.parseDouble(prop))); + Optional.ofNullable(properties.get(MAX_SUSCEPTANCE_MISMATCH_PARAM_NAME)) + .ifPresent(prop -> this.setMaxSusceptanceMismatch(Double.parseDouble(prop))); Optional.ofNullable(properties.get(SLACK_BUS_P_MAX_MISMATCH_NAME)) .ifPresent(prop -> this.setSlackBusPMaxMismatch(Double.parseDouble(prop))); Optional.ofNullable(properties.get(VOLTAGE_PER_REACTIVE_POWER_CONTROL_NAME)) @@ -674,7 +826,14 @@ public String toString() { ", lowImpedanceBranchMode=" + lowImpedanceBranchMode + ", loadPowerFactorConstant=" + loadPowerFactorConstant + ", plausibleActivePowerLimit=" + plausibleActivePowerLimit + + ", newtonRaphsonStoppingCriteriaType=" + newtonRaphsonStoppingCriteriaType + ", slackBusPMaxMismatch=" + slackBusPMaxMismatch + + ", maxActivePowerMismatch=" + maxActivePowerMismatch + + ", maxReactivePowerMismatch=" + maxReactivePowerMismatch + + ", maxVoltageMismatch=" + maxVoltageMismatch + + ", maxAngleMismatch=" + maxAngleMismatch + + ", maxRatioMismatch=" + maxRatioMismatch + + ", maxSusceptanceMismatch=" + maxSusceptanceMismatch + ", voltagePerReactivePowerControl=" + voltagePerReactivePowerControl + ", reactivePowerRemoteControl=" + reactivePowerRemoteControl + ", maxIteration=" + maxIteration + @@ -856,6 +1015,20 @@ public static AcLoadFlowParameters createAcParameters(Network network, LoadFlowP return acParameters; } + private static NewtonRaphsonStoppingCriteria createNewtonRaphsonStoppingCriteria(OpenLoadFlowParameters parametersExt) { + switch (parametersExt.getNewtonRaphsonStoppingCriteriaType()) { + case UNIFORM_CRITERIA: + return new DefaultNewtonRaphsonStoppingCriteria(parametersExt.getNewtonRaphsonConvEpsPerEq()); + case PER_EQUATION_TYPE_CRITERIA: + return new PerEquationTypeStoppingCriteria(parametersExt.getMaxActivePowerMismatch(), + parametersExt.getMaxReactivePowerMismatch(), parametersExt.getMaxVoltageMismatch(), + parametersExt.getMaxAngleMismatch(), parametersExt.getMaxRatioMismatch(), + parametersExt.getMaxSusceptanceMismatch()); + default: + throw new PowsyblException("Unknown Newton Raphson stopping criteria type: " + parametersExt.getNewtonRaphsonStoppingCriteriaType()); + } + } + public static AcLoadFlowParameters createAcParameters(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt, MatrixFactory matrixFactory, GraphConnectivityFactory connectivityFactory, boolean breakers, boolean forceA1Var) { @@ -868,7 +1041,7 @@ public static AcLoadFlowParameters createAcParameters(LoadFlowParameters paramet VoltageInitializer voltageInitializer = getExtendedVoltageInitializer(parameters, parametersExt, networkParameters, matrixFactory); var newtonRaphsonParameters = new NewtonRaphsonParameters() - .setStoppingCriteria(new DefaultNewtonRaphsonStoppingCriteria(parametersExt.getNewtonRaphsonConvEpsPerEq())) + .setStoppingCriteria(createNewtonRaphsonStoppingCriteria(parametersExt)) .setMaxIteration(parametersExt.getMaxIteration()) .setMinRealisticVoltage(parametersExt.getMinRealisticVoltage()) .setMaxRealisticVoltage(parametersExt.getMaxRealisticVoltage()) diff --git a/src/main/java/com/powsybl/openloadflow/ac/nr/DefaultNewtonRaphsonStoppingCriteria.java b/src/main/java/com/powsybl/openloadflow/ac/nr/DefaultNewtonRaphsonStoppingCriteria.java index 4e6781d750..4bb6fe11e0 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/nr/DefaultNewtonRaphsonStoppingCriteria.java +++ b/src/main/java/com/powsybl/openloadflow/ac/nr/DefaultNewtonRaphsonStoppingCriteria.java @@ -6,6 +6,9 @@ */ package com.powsybl.openloadflow.ac.nr; +import com.powsybl.openloadflow.ac.equations.AcEquationType; +import com.powsybl.openloadflow.ac.equations.AcVariableType; +import com.powsybl.openloadflow.equations.EquationSystem; import com.powsybl.openloadflow.equations.Vectors; import net.jafama.FastMath; @@ -30,7 +33,7 @@ public DefaultNewtonRaphsonStoppingCriteria(double convEpsPerEq) { } @Override - public TestResult test(double[] fx) { + public TestResult test(double[] fx, EquationSystem equationSystem) { // calculate norm L2 of equations mismatch vector double norm = Vectors.norm2(fx); boolean stop = norm < FastMath.sqrt(convEpsPerEq * convEpsPerEq * fx.length); diff --git a/src/main/java/com/powsybl/openloadflow/ac/nr/LineSearchStateVectorScaling.java b/src/main/java/com/powsybl/openloadflow/ac/nr/LineSearchStateVectorScaling.java index 222a590e63..e3dac03933 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/nr/LineSearchStateVectorScaling.java +++ b/src/main/java/com/powsybl/openloadflow/ac/nr/LineSearchStateVectorScaling.java @@ -49,11 +49,12 @@ public void apply(double[] dx, EquationSystem eq } @Override - public NewtonRaphsonStoppingCriteria.TestResult applyAfter(StateVector stateVector, + public NewtonRaphsonStoppingCriteria.TestResult applyAfter(EquationSystem equationSystem, EquationVector equationVector, TargetVector targetVector, NewtonRaphsonStoppingCriteria stoppingCriteria, NewtonRaphsonStoppingCriteria.TestResult testResult) { + StateVector stateVector = equationSystem.getStateVector(); if (lastTestResult != null) { double stepSize = 1; NewtonRaphsonStoppingCriteria.TestResult currentTestResult = testResult; @@ -78,7 +79,7 @@ public NewtonRaphsonStoppingCriteria.TestResult applyAfter(StateVector stateVect equationVector.minus(targetVector); // and recompute new norm - currentTestResult = stoppingCriteria.test(equationVector.getArray()); + currentTestResult = stoppingCriteria.test(equationVector.getArray(), equationSystem); iteration++; } diff --git a/src/main/java/com/powsybl/openloadflow/ac/nr/MaxVoltageChangeStateVectorScaling.java b/src/main/java/com/powsybl/openloadflow/ac/nr/MaxVoltageChangeStateVectorScaling.java index c1f10cf946..baa763c0c5 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/nr/MaxVoltageChangeStateVectorScaling.java +++ b/src/main/java/com/powsybl/openloadflow/ac/nr/MaxVoltageChangeStateVectorScaling.java @@ -12,7 +12,6 @@ import com.powsybl.openloadflow.ac.equations.AcVariableType; import com.powsybl.openloadflow.equations.EquationSystem; import com.powsybl.openloadflow.equations.EquationVector; -import com.powsybl.openloadflow.equations.StateVector; import com.powsybl.openloadflow.equations.TargetVector; import com.powsybl.openloadflow.equations.Vectors; import org.slf4j.Logger; @@ -80,7 +79,7 @@ public void apply(double[] dx, EquationSystem eq } @Override - public NewtonRaphsonStoppingCriteria.TestResult applyAfter(StateVector stateVector, + public NewtonRaphsonStoppingCriteria.TestResult applyAfter(EquationSystem equationSystem, EquationVector equationVector, TargetVector targetVector, NewtonRaphsonStoppingCriteria stoppingCriteria, diff --git a/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphson.java b/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphson.java index 04b652d06e..7d91165fa8 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphson.java +++ b/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphson.java @@ -96,9 +96,9 @@ private NewtonRaphsonStatus runIteration(StateVectorScaling svScaling) { } // test stopping criteria and log norm(fx) - NewtonRaphsonStoppingCriteria.TestResult testResult = parameters.getStoppingCriteria().test(equationVector.getArray()); + NewtonRaphsonStoppingCriteria.TestResult testResult = parameters.getStoppingCriteria().test(equationVector.getArray(), equationSystem); - testResult = svScaling.applyAfter(equationSystem.getStateVector(), equationVector, targetVector, + testResult = svScaling.applyAfter(equationSystem, equationVector, targetVector, parameters.getStoppingCriteria(), testResult); LOGGER.debug("|f(x)|={}", testResult.getNorm()); @@ -214,7 +214,7 @@ public NewtonRaphsonResult run(VoltageInitializer voltageInitializer) { Vectors.minus(equationVector.getArray(), targetVector.getArray()); - NewtonRaphsonStoppingCriteria.TestResult initialTestResult = parameters.getStoppingCriteria().test(equationVector.getArray()); + NewtonRaphsonStoppingCriteria.TestResult initialTestResult = parameters.getStoppingCriteria().test(equationVector.getArray(), equationSystem); LOGGER.debug("|f(x0)|={}", initialTestResult.getNorm()); StateVectorScaling svScaling = StateVectorScaling.fromMode(parameters.getStateVectorScalingMode(), initialTestResult); diff --git a/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphsonStoppingCriteria.java b/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphsonStoppingCriteria.java index 1da72b77d4..15d9c5e435 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphsonStoppingCriteria.java +++ b/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphsonStoppingCriteria.java @@ -6,6 +6,10 @@ */ package com.powsybl.openloadflow.ac.nr; +import com.powsybl.openloadflow.ac.equations.AcEquationType; +import com.powsybl.openloadflow.ac.equations.AcVariableType; +import com.powsybl.openloadflow.equations.EquationSystem; + /** * @author Geoffroy Jamgotchian */ @@ -31,5 +35,5 @@ public double getNorm() { } } - TestResult test(double[] fx); + TestResult test(double[] fx, EquationSystem equationSystem); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphsonStoppingCriteriaType.java b/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphsonStoppingCriteriaType.java new file mode 100644 index 0000000000..5a0cee54db --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphsonStoppingCriteriaType.java @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2023, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.openloadflow.ac.nr; + +/** + * @author Alexandre Le Jean + */ +public enum NewtonRaphsonStoppingCriteriaType { + UNIFORM_CRITERIA, + PER_EQUATION_TYPE_CRITERIA +} diff --git a/src/main/java/com/powsybl/openloadflow/ac/nr/NoneStateVectorScaling.java b/src/main/java/com/powsybl/openloadflow/ac/nr/NoneStateVectorScaling.java index 98285e69f5..d07883e363 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/nr/NoneStateVectorScaling.java +++ b/src/main/java/com/powsybl/openloadflow/ac/nr/NoneStateVectorScaling.java @@ -11,7 +11,6 @@ import com.powsybl.openloadflow.ac.equations.AcVariableType; import com.powsybl.openloadflow.equations.EquationSystem; import com.powsybl.openloadflow.equations.EquationVector; -import com.powsybl.openloadflow.equations.StateVector; import com.powsybl.openloadflow.equations.TargetVector; /** @@ -30,7 +29,7 @@ public void apply(double[] dx, EquationSystem eq } @Override - public NewtonRaphsonStoppingCriteria.TestResult applyAfter(StateVector stateVector, + public NewtonRaphsonStoppingCriteria.TestResult applyAfter(EquationSystem equationSystem, EquationVector equationVector, TargetVector targetVector, NewtonRaphsonStoppingCriteria stoppingCriteria, diff --git a/src/main/java/com/powsybl/openloadflow/ac/nr/PerEquationTypeStoppingCriteria.java b/src/main/java/com/powsybl/openloadflow/ac/nr/PerEquationTypeStoppingCriteria.java new file mode 100644 index 0000000000..8549896e61 --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/ac/nr/PerEquationTypeStoppingCriteria.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2023, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.openloadflow.ac.nr; + +import com.powsybl.commons.PowsyblException; +import com.powsybl.openloadflow.ac.equations.AcEquationType; +import com.powsybl.openloadflow.ac.equations.AcVariableType; +import com.powsybl.openloadflow.equations.EquationSystem; +import com.powsybl.openloadflow.equations.Vectors; +import com.powsybl.openloadflow.util.PerUnit; + +/** + * @author Alexandre Le Jean + */ +public class PerEquationTypeStoppingCriteria implements NewtonRaphsonStoppingCriteria { + + private final double maxDefaultAngleMismatch; + + private final double maxDefaultRatioMismatch; + + private final double maxDefaultSusceptanceMismatch; + + private final double maxActivePowerMismatch; + + private final double maxReactivePowerMismatch; + + private final double maxVoltageMismatch; + + public PerEquationTypeStoppingCriteria(double maxActivePowerMismatch, + double maxReactivePowerMismatch, double maxVoltageMismatch, + double maxDefaultAngleMismatch, double maxDefaultRatioMismatch, + double maxDefaultSusceptanceMismatch) { + this.maxActivePowerMismatch = maxActivePowerMismatch; + this.maxReactivePowerMismatch = maxReactivePowerMismatch; + this.maxVoltageMismatch = maxVoltageMismatch; + this.maxDefaultAngleMismatch = maxDefaultAngleMismatch; + this.maxDefaultRatioMismatch = maxDefaultRatioMismatch; + this.maxDefaultSusceptanceMismatch = maxDefaultSusceptanceMismatch; + } + + private double computeNorm(double[] fx) { + return Vectors.norm2(fx); + } + + private boolean computeStop(double[] fx, EquationSystem equationSystem) { + for (var eq : equationSystem.getIndex().getSortedEquationsToSolve()) { + var type = eq.getType(); + var idx = eq.getColumn(); + switch (type) { + case BRANCH_TARGET_P: + case BUS_TARGET_P: + case DUMMY_TARGET_P: + if (Math.abs(fx[idx]) * PerUnit.SB >= maxActivePowerMismatch) { + return false; + } + break; + case BRANCH_TARGET_Q: + case BUS_TARGET_Q: + case DISTR_Q: + case DUMMY_TARGET_Q: + if (Math.abs(fx[idx]) * PerUnit.SB >= maxReactivePowerMismatch) { + return false; + } + break; + case BUS_TARGET_V: + case BUS_TARGET_V_WITH_SLOPE: + case ZERO_V: + if (Math.abs(fx[idx]) >= maxVoltageMismatch) { + return false; + } + break; + case BRANCH_TARGET_RHO1: + case DISTR_RHO: + if (Math.abs(fx[idx]) >= maxDefaultRatioMismatch) { + return false; + } + break; + case DISTR_SHUNT_B: + case SHUNT_TARGET_B: + if (Math.abs(fx[idx]) >= maxDefaultSusceptanceMismatch) { + return false; + } + break; + case BUS_TARGET_PHI: + case ZERO_PHI: + case BRANCH_TARGET_ALPHA1: + if (Math.abs(fx[idx]) >= maxDefaultAngleMismatch) { + return false; + } + break; + default: + throw new PowsyblException("Unknown equation term"); + } + } + return true; + } + + @Override + public TestResult test(double[] fx, EquationSystem equationSystem) { + return new TestResult(computeStop(fx, equationSystem), computeNorm(fx)); + } +} diff --git a/src/main/java/com/powsybl/openloadflow/ac/nr/StateVectorScaling.java b/src/main/java/com/powsybl/openloadflow/ac/nr/StateVectorScaling.java index 0b4f332209..431e360242 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/nr/StateVectorScaling.java +++ b/src/main/java/com/powsybl/openloadflow/ac/nr/StateVectorScaling.java @@ -11,7 +11,6 @@ import com.powsybl.openloadflow.ac.equations.AcVariableType; import com.powsybl.openloadflow.equations.EquationSystem; import com.powsybl.openloadflow.equations.EquationVector; -import com.powsybl.openloadflow.equations.StateVector; import com.powsybl.openloadflow.equations.TargetVector; import java.util.Objects; @@ -48,7 +47,7 @@ static StateVectorScaling fromMode(StateVectorScalingMode mode, NewtonRaphsonSto /** * Apply scaling to state vector after equation mismatches and norm have been calculated. */ - NewtonRaphsonStoppingCriteria.TestResult applyAfter(StateVector stateVector, + NewtonRaphsonStoppingCriteria.TestResult applyAfter(EquationSystem equationSystem, EquationVector equationVector, TargetVector targetVector, NewtonRaphsonStoppingCriteria stoppingCriteria, diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java index 49b3b73547..fdceb61e37 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java @@ -8,6 +8,7 @@ import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; +import com.powsybl.commons.PowsyblException; import com.powsybl.commons.config.InMemoryPlatformConfig; import com.powsybl.commons.config.MapModuleConfig; import com.powsybl.commons.config.PlatformConfig; @@ -115,6 +116,22 @@ void testInvalidOpenLoadflowConfig() { assertEquals("No enum constant com.powsybl.openloadflow.network.SlackBusSelectionMode.Invalid", exception.getMessage()); } + @Test + void testInvalidOpenLoadflowConfigNewtonRaphson() { + MapModuleConfig olfModuleConfig = platformConfig.createModuleConfig("open-loadflow-default-parameters"); + olfModuleConfig.setStringProperty("newtonRaphsonStoppingCriteriaType", "Invalid"); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> LoadFlowParameters.load(platformConfig)); + assertEquals("No enum constant com.powsybl.openloadflow.ac.nr.NewtonRaphsonStoppingCriteriaType.Invalid", exception.getMessage()); + + OpenLoadFlowParameters openLoadFlowParameters = OpenLoadFlowParameters.create(new LoadFlowParameters()); + assertThrows(PowsyblException.class, () -> openLoadFlowParameters.setMaxAngleMismatch(-1)); + assertThrows(PowsyblException.class, () -> openLoadFlowParameters.setMaxVoltageMismatch(-1)); + assertThrows(PowsyblException.class, () -> openLoadFlowParameters.setMaxRatioMismatch(-1)); + assertThrows(PowsyblException.class, () -> openLoadFlowParameters.setMaxActivePowerMismatch(-1)); + assertThrows(PowsyblException.class, () -> openLoadFlowParameters.setMaxReactivePowerMismatch(-1)); + } + @Test void testFirstSlackBusSelector() throws IOException { Path cfgDir = Files.createDirectory(fileSystem.getPath("config")); diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java index 305e56671e..0f231bc0dc 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java @@ -85,7 +85,7 @@ void testGetExtendedVoltageInitializer() { @Test void specificParametersTest() { OpenLoadFlowProvider provider = new OpenLoadFlowProvider(); - assertEquals(30, provider.getSpecificParameters().size()); + assertEquals(37, provider.getSpecificParameters().size()); LoadFlowParameters parameters = new LoadFlowParameters(); provider.loadSpecificParameters(Collections.emptyMap()) diff --git a/src/test/java/com/powsybl/openloadflow/ac/nr/NewtonRaphsonStoppingCriteriaTest.java b/src/test/java/com/powsybl/openloadflow/ac/nr/NewtonRaphsonStoppingCriteriaTest.java new file mode 100644 index 0000000000..23150b2c32 --- /dev/null +++ b/src/test/java/com/powsybl/openloadflow/ac/nr/NewtonRaphsonStoppingCriteriaTest.java @@ -0,0 +1,167 @@ +/** + * Copyright (c) 2023, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.openloadflow.ac.nr; + +import com.powsybl.iidm.network.Network; +import com.powsybl.loadflow.LoadFlow; +import com.powsybl.loadflow.LoadFlowParameters; +import com.powsybl.loadflow.LoadFlowResult; +import com.powsybl.math.matrix.DenseMatrixFactory; +import com.powsybl.openloadflow.OpenLoadFlowParameters; +import com.powsybl.openloadflow.OpenLoadFlowProvider; +import com.powsybl.openloadflow.network.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Alexandre Le Jean + */ +class NewtonRaphsonStoppingCriteriaTest { + + private Network network; + private LoadFlow.Runner loadFlowRunner; + private LoadFlowParameters parameters; + + @BeforeEach + void setUp() { + network = BoundaryFactory.create(); + loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(new DenseMatrixFactory())); + parameters = new LoadFlowParameters(); + } + + @Test + void testDefaultUniformCriteria() { + OpenLoadFlowParameters.create(parameters) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.UNIFORM_CRITERIA); + LoadFlowResult result = loadFlowRunner.run(network, parameters); + assertTrue(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus()); + assertEquals(2, result.getComponentResults().get(0).getIterationCount()); + } + + @Test + void testConvergedUniformCriteria() { + OpenLoadFlowParameters.create(parameters) + .setNewtonRaphsonConvEpsPerEq(0.1) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.UNIFORM_CRITERIA); + LoadFlowResult result = loadFlowRunner.run(network, parameters); + assertTrue(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus()); + assertEquals(1, result.getComponentResults().get(0).getIterationCount()); + } + + @Test + void testDefaultPerEquationCriteria() { + OpenLoadFlowParameters.create(parameters) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA); + LoadFlowResult result = loadFlowRunner.run(network, parameters); + assertTrue(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus()); + assertEquals(2, result.getComponentResults().get(0).getIterationCount()); + } + + @Test + void testVoltageConvergedPerEquationCriteria() { + OpenLoadFlowParameters.create(parameters) + .setMaxVoltageMismatch(1) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA); + LoadFlowResult result = loadFlowRunner.run(network, parameters); + assertTrue(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus()); + assertEquals(2, result.getComponentResults().get(0).getIterationCount()); + } + + @Test + void testActivePowerConvergedPerEquationCriteria() { + OpenLoadFlowParameters.create(parameters) + .setMaxActivePowerMismatch(0.038) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA); + LoadFlowResult result = loadFlowRunner.run(network, parameters); + assertTrue(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus()); + assertEquals(2, result.getComponentResults().get(0).getIterationCount()); + } + + @Test + void testActivePowerMaxIterationPerEquationCriteria() { + OpenLoadFlowParameters.create(parameters) + .setMaxActivePowerMismatch(1E-15) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA); + LoadFlowResult result = loadFlowRunner.run(network, parameters); + assertFalse(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.MAX_ITERATION_REACHED, result.getComponentResults().get(0).getStatus()); + } + + @Test + void testReactivePowerConvergedPerEquationCriteria() { + OpenLoadFlowParameters.create(parameters) + .setMaxReactivePowerMismatch(1E-11) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA); + LoadFlowResult result = loadFlowRunner.run(network, parameters); + assertTrue(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus()); + assertEquals(5, result.getComponentResults().get(0).getIterationCount()); + } + + @Test + void testReactivePowerMaxIterationPerEquationCriteria() { + OpenLoadFlowParameters.create(parameters) + .setMaxReactivePowerMismatch(1E-15) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA); + LoadFlowResult result = loadFlowRunner.run(network, parameters); + assertFalse(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.MAX_ITERATION_REACHED, result.getComponentResults().get(0).getStatus()); + } + + @Test + void testAngleConvergedPerEquationCriteria() { + OpenLoadFlowParameters.create(parameters) + .setMaxAngleMismatch(1E-22) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA); + LoadFlowResult result = loadFlowRunner.run(network, parameters); + assertTrue(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus()); + assertEquals(3, result.getComponentResults().get(0).getIterationCount()); + + OpenLoadFlowParameters.create(parameters) + .setMaxAngleMismatch(1E-30) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA); + result = loadFlowRunner.run(network, parameters); + assertTrue(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus()); + assertEquals(4, result.getComponentResults().get(0).getIterationCount()); + } + + @Test + void testRatioMaxIterationPerEquationCriteria() { + network = VoltageControlNetworkFactory.createWithTransformerSharedRemoteControl(); + OpenLoadFlowParameters.create(parameters) + .setTransformerVoltageControlMode(OpenLoadFlowParameters.TransformerVoltageControlMode.WITH_GENERATOR_VOLTAGE_CONTROL) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA); + parameters.setTransformerVoltageControlOn(true); + LoadFlowResult result = loadFlowRunner.run(network, parameters); + assertTrue(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus()); + assertEquals(4, result.getComponentResults().get(0).getIterationCount()); + } + + @Test + void testSusceptanceMaxIterationPerEquationCriteria() { + network = ShuntNetworkFactory.createWithTwoShuntCompensators(); + OpenLoadFlowParameters.create(parameters) + .setShuntVoltageControlMode(OpenLoadFlowParameters.ShuntVoltageControlMode.INCREMENTAL_VOLTAGE_CONTROL) + .setNewtonRaphsonStoppingCriteriaType(NewtonRaphsonStoppingCriteriaType.PER_EQUATION_TYPE_CRITERIA); + parameters.setShuntCompensatorVoltageControlOn(true); + LoadFlowResult result = loadFlowRunner.run(network, parameters); + assertTrue(result.isOk()); + assertEquals(LoadFlowResult.ComponentResult.Status.CONVERGED, result.getComponentResults().get(0).getStatus()); + assertEquals(4, result.getComponentResults().get(0).getIterationCount()); + } +} diff --git a/src/test/resources/debug-parameters.json b/src/test/resources/debug-parameters.json index 5b3c19fc52..129bc8fb3c 100644 --- a/src/test/resources/debug-parameters.json +++ b/src/test/resources/debug-parameters.json @@ -25,6 +25,13 @@ "lowImpedanceBranchMode" : "REPLACE_BY_ZERO_IMPEDANCE_LINE", "loadPowerFactorConstant" : false, "plausibleActivePowerLimit" : 5000.0, + "newtonRaphsonStoppingCriteriaType" : "UNIFORM_CRITERIA", + "maxActivePowerMismatch" : 0.01, + "maxReactivePowerMismatch" : 0.01, + "maxVoltageMismatch" : 1.0E-4, + "maxAngleMismatch" : 1.0E-5, + "maxRatioMismatch" : 1.0E-5, + "maxSusceptanceMismatch" : 1.0E-4, "slackBusPMaxMismatch" : 1.0, "voltagePerReactivePowerControl" : false, "maxIteration" : 30,