From 91d0a01e365730ebd8497c93358ec13d2812d5a1 Mon Sep 17 00:00:00 2001 From: p-arvy Date: Wed, 7 Aug 2024 11:59:56 +0200 Subject: [PATCH 01/10] Remove DCOPF from optimization process and use DCLF instead Signed-off-by: p-arvy --- open-reac/pom.xml | 11 +- .../com/powsybl/openreac/OpenReacRunner.java | 76 ++++- .../parameters/input/OpenReacParameters.java | 11 + .../src/main/resources/openreac/acopf.mod | 2 + .../src/main/resources/openreac/acopf.run | 14 +- .../src/main/resources/openreac/dcopf.mod | 130 ++++----- .../src/main/resources/openreac/dcopf.run | 272 +++++++++--------- .../main/resources/openreac/reactiveopf.run | 10 +- .../resources/openreac/reactiveopfoutput.run | 8 +- 9 files changed, 310 insertions(+), 224 deletions(-) diff --git a/open-reac/pom.xml b/open-reac/pom.xml index 1c8b4a8a..da5fbc37 100644 --- a/open-reac/pom.xml +++ b/open-reac/pom.xml @@ -101,6 +101,11 @@ com.powsybl powsybl-loadflow-api + + com.powsybl + powsybl-open-loadflow + ${powsybl-open-loadflow.version} + org.junit.jupiter @@ -148,11 +153,5 @@ powsybl-ieee-cdf-converter test - - com.powsybl - powsybl-open-loadflow - ${powsybl-open-loadflow.version} - test - diff --git a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java index e41ec893..6e47a498 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java +++ b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java @@ -10,23 +10,35 @@ import com.powsybl.ampl.executor.AmplModel; import com.powsybl.ampl.executor.AmplModelRunner; import com.powsybl.ampl.executor.AmplResults; +import com.powsybl.commons.PowsyblException; import com.powsybl.commons.report.ReportNode; import com.powsybl.computation.ComputationManager; import com.powsybl.computation.local.LocalComputationManager; +import com.powsybl.iidm.network.Bus; import com.powsybl.iidm.network.Network; +import com.powsybl.iidm.network.VariantManager; +import com.powsybl.loadflow.LoadFlow; +import com.powsybl.loadflow.LoadFlowParameters; +import com.powsybl.loadflow.LoadFlowResult; +import com.powsybl.openloadflow.OpenLoadFlowParameters; +import com.powsybl.openloadflow.network.SlackBusSelectionMode; import com.powsybl.openreac.parameters.OpenReacAmplIOFiles; import com.powsybl.openreac.parameters.input.OpenReacParameters; import com.powsybl.openreac.parameters.output.OpenReacResult; import com.powsybl.openreac.parameters.output.OpenReacStatus; +import java.util.HashMap; import java.util.Objects; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; /** * @author Nicolas Pierre {@literal } */ public final class OpenReacRunner { + private static final String WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX = "WithDcLoadFlow"; + private OpenReacRunner() { } @@ -74,7 +86,23 @@ public static OpenReacResult run(Network network, String variantId, OpenReacPara checkParameters(network, variantId, parameters, config, manager, reportNode); AmplModel reactiveOpf = OpenReacModel.buildModel(); OpenReacAmplIOFiles amplIoInterface = new OpenReacAmplIOFiles(parameters, amplExportConfig, network, config.isDebug(), Reports.createOpenReacReporter(reportNode, network.getId(), parameters.getObjective())); - AmplResults run = AmplModelRunner.run(network, variantId, reactiveOpf, manager, amplIoInterface); + + AmplResults run; + if (parameters.isDcLoadFlowBeforeOptimization()) { + // create new variant to avoid modifying the network + VariantManager variantManager = network.getVariantManager(); + variantManager.cloneVariant(variantId, WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); + variantManager.setWorkingVariant(WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); + // warm start the optimization with dc load flow results + runDcLf(network, parameters); + run = AmplModelRunner.run(network, WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX, reactiveOpf, manager, amplIoInterface); + // remove the variant created to store dc load flow results + variantManager.setWorkingVariant(variantId); + variantManager.removeVariant(WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); + } else { + run = AmplModelRunner.run(network, variantId, reactiveOpf, manager, amplIoInterface); + } + OpenReacResult result = new OpenReacResult(run.isSuccess() && amplIoInterface.checkErrors() ? OpenReacStatus.OK : OpenReacStatus.NOT_OK, amplIoInterface, run.getIndicators()); Reports.createShuntModificationsReporter(reportNode, network.getId(), amplIoInterface.getNetworkModifications().getShuntsWithDeltaDiscreteOptimalOverThreshold()); return result; @@ -107,7 +135,23 @@ public static CompletableFuture runAsync(Network network, String checkParameters(network, variantId, parameters, config, manager, reportNode); AmplModel reactiveOpf = OpenReacModel.buildModel(); OpenReacAmplIOFiles amplIoInterface = new OpenReacAmplIOFiles(parameters, amplExportConfig, network, config.isDebug(), Reports.createOpenReacReporter(reportNode, network.getId(), parameters.getObjective())); - CompletableFuture runAsync = AmplModelRunner.runAsync(network, variantId, reactiveOpf, manager, amplIoInterface); + + CompletableFuture runAsync; + if (parameters.isDcLoadFlowBeforeOptimization()) { + // create new variant to avoid modifying the network + VariantManager variantManager = network.getVariantManager(); + variantManager.cloneVariant(variantId, WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); + variantManager.setWorkingVariant(WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); + // warm start the optimization with dc load flow results + runDcLf(network, parameters); + runAsync = AmplModelRunner.runAsync(network, WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX, reactiveOpf, manager, amplIoInterface); + // remove the variant created to store dc load flow results + variantManager.setWorkingVariant(variantId); + variantManager.removeVariant(WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); + } else { + runAsync = AmplModelRunner.runAsync(network, variantId, reactiveOpf, manager, amplIoInterface); + } + return runAsync.thenApply(run -> { OpenReacResult result = new OpenReacResult(run.isSuccess() && amplIoInterface.checkErrors() ? OpenReacStatus.OK : OpenReacStatus.NOT_OK, amplIoInterface, run.getIndicators()); Reports.createShuntModificationsReporter(reportNode, network.getId(), amplIoInterface.getNetworkModifications().getShuntsWithDeltaDiscreteOptimalOverThreshold()); @@ -124,4 +168,32 @@ private static void checkParameters(Network network, String variantId, OpenReacP Objects.requireNonNull(reportNode); parameters.checkIntegrity(network, Reports.createParameterIntegrityReporter(reportNode, network.getId())); } + + private static void runDcLf(Network network, OpenReacParameters parameters) { + // store network voltages to apply them later + // currently, dc load flow erases these values for NaN + HashMap voltageValues = new HashMap<>(); + network.getBusView().getBusStream() + .filter(Bus::isInMainSynchronousComponent) + .forEach(bus -> voltageValues.put(bus.getId(), bus.getAngle())); + + LoadFlowParameters loadFlowParameters = new LoadFlowParameters(); + loadFlowParameters.setDc(true) + .setConnectedComponentMode(LoadFlowParameters.ConnectedComponentMode.MAIN) + .setDistributedSlack(true) + .setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_P); + OpenLoadFlowParameters.create(loadFlowParameters) + .setLowImpedanceThreshold(parameters.getLowImpedanceThreshold()) + .setLowImpedanceBranchMode(OpenLoadFlowParameters.LowImpedanceBranchMode.REPLACE_BY_MIN_IMPEDANCE_LINE) + .setSlackBusSelectionMode(SlackBusSelectionMode.NAME) + .setSlackBusId("b5_vl_0"); + + LoadFlowResult result = LoadFlow.find("OpenLoadFlow").run(network, loadFlowParameters); + if (result.isFailed()) { + throw new PowsyblException("If DC load flow fails, no hope that reactive ACOPF converges."); + } + + // restore voltage values of the network + voltageValues.forEach((k, v) -> network.getBusView().getBus(k).setV(1)); + } } diff --git a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java index 62d3352a..024fabde 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java +++ b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java @@ -127,6 +127,8 @@ public class OpenReacParameters { private double shuntCompensatorActivationAlertThreshold; + private boolean dcLoadFlowBeforeOptimization = true; + /** * Override some voltage level limits in the network. This will NOT modify the network object. *

@@ -548,6 +550,15 @@ public OpenReacParameters setShuntCompensatorActivationAlertThreshold(double shu return this; } + public boolean isDcLoadFlowBeforeOptimization() { + return dcLoadFlowBeforeOptimization; + } + + public OpenReacParameters setDcLoadFlowBeforeOptimization(boolean dcLoadFlowBeforeOptimization) { + this.dcLoadFlowBeforeOptimization = dcLoadFlowBeforeOptimization; + return this; + } + public List getAllAlgorithmParams() { ArrayList allAlgoParams = new ArrayList<>(); allAlgoParams.add(objective.toParam()); diff --git a/open-reac/src/main/resources/openreac/acopf.mod b/open-reac/src/main/resources/openreac/acopf.mod index 85bfb991..dc0d203d 100644 --- a/open-reac/src/main/resources/openreac/acopf.mod +++ b/open-reac/src/main/resources/openreac/acopf.mod @@ -30,6 +30,8 @@ set PROBLEM_ACOPF default { }; # Complex voltage = V*exp(i*teta). (with i**2=-1) # Phase of voltage +param teta_min default -10; # roughly 3*pi +param teta_max default 10; # roughly 3*pi var teta{BUSCC} <= teta_max, >= teta_min; subject to ctr_null_phase_bus{PROBLEM_ACOPF}: teta[null_phase_bus] = 0; diff --git a/open-reac/src/main/resources/openreac/acopf.run b/open-reac/src/main/resources/openreac/acopf.run index 67a329d6..d1d322de 100644 --- a/open-reac/src/main/resources/openreac/acopf.run +++ b/open-reac/src/main/resources/openreac/acopf.run @@ -20,7 +20,9 @@ ############################################################################### # DC values used as initialization for phases -let {n in BUSCC} teta[n] := teta_dc[n]; +let {n in BUSCC} teta[n] := if teta_min <= bus_angl0[1,n] and bus_angl0[1,n] <= teta_max + then bus_angl0[1,n] + else 0; # Voltages let {n in BUSVV} V[n] := bus_V0[1,n]; @@ -30,7 +32,7 @@ let {n in BUSCC diff BUSVV} V[n] := voltage_lower_bound[1,bus_substation[1,n]] let {n in BUSCC_SLACK} slack1_shunt_B[n] := 0; let {n in BUSCC_SLACK} slack2_shunt_B[n] := 0; let alpha := 0.01; -let {(g,n) in UNITON} P_bounded[g,n] := max(P_dcopf[g,n],unit_Pc[1,g,n]); +let {(g,n) in UNITON} P_bounded[g,n] := max(unit_P0[1,g,n],unit_Pc[1,g,n]);; let {(g,n) in UNITON} Q[g,n] := 0.5*(corrected_unit_Qmax[g,n] + corrected_unit_Qmin[g,n]); let {(shunt,n) in SHUNT_VAR} shunt_var[shunt,n] := min{(1,shunt,k) in SHUNT} shunt_valnom[1,shunt,k]; let {(svc,n) in SVCON} svc_qvar[svc,n] := 0.1; @@ -118,10 +120,10 @@ printf{LOG_INFO} "** ACopf results\n"; if 1 in LOG_INFO then display nb_iter_last,nb_iter_total, max({(qq,m,n) in BRANCHCC} branch_R[1,qq,m,n]),max({(qq,m,n) in BRANCHCC} branch_X[1,qq,m,n]), - teta_max, max({n in BUSCC} teta[n]), max({n in BUSCC} teta_dc[n]), - teta_min, min({n in BUSCC} teta[n]), min({n in BUSCC} teta_dc[n]), - max({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])), max({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])), - min({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])), min({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])), + teta_max, max({n in BUSCC} teta[n]),# max({n in BUSCC} teta_dc[n]), + teta_min, min({n in BUSCC} teta[n]),# min({n in BUSCC} teta_dc[n]), + max({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])),# max({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])), + min({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])),# min({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])), min({n in BUSCC}V[n]),max({n in BUSCC}V[n]) ; diff --git a/open-reac/src/main/resources/openreac/dcopf.mod b/open-reac/src/main/resources/openreac/dcopf.mod index 320c5ac4..50973615 100644 --- a/open-reac/src/main/resources/openreac/dcopf.mod +++ b/open-reac/src/main/resources/openreac/dcopf.mod @@ -1,71 +1,71 @@ -############################################################################### +################################################################################ +## +## Copyright (c) 2022 2023 2024, RTE (http://www.rte-france.com) +## 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 +## +################################################################################ # -# Copyright (c) 2022 2023 2024, RTE (http://www.rte-france.com) -# 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 +################################################################################ +## Reactive OPF +## Author: Jean Maeght 2022 2023 +## Author: Manuel Ruiz 2023 2024 +################################################################################ # -############################################################################### - -############################################################################### -# Reactive OPF -# Author: Jean Maeght 2022 2023 -# Author: Manuel Ruiz 2023 2024 -############################################################################### - - -set PROBLEM_DCOPF default {1}; - -############################################################################### # -# Variables and contraints for DCOPF +#set PROBLEM_DCOPF default {1}; # -############################################################################### -# Why doing a DCOPF before ACOPF? -# 1/ if DCOPF fails, how to hope that ACOPF is feasible? -> DCOPF may be seen as an unformal consistency check on data -# 2/ phases computed in DCOPF will be used as initial point for ACOPF -# Some of the variables and constraints defined for DCOPF will be used also for ACOPF - -# Phase of voltage -param teta_min default -10; # roughly 3*pi -param teta_max default 10; # roughly 3*pi -var teta_dc{n in BUSCC} <= teta_max, >= teta_min; -subject to ctr_null_phase_bus_dc{PROBLEM_DCOPF}: teta_dc[null_phase_bus] = 0; - -# Variable flow is the flow from bus 1 to bus 2 -var activeflow{BRANCHCC}; -subject to ctr_activeflow{PROBLEM_DCOPF, (qq,m,n) in BRANCHCC}: - activeflow[qq,m,n] = base100MVA * (teta_dc[m]-teta_dc[n]) / branch_X_mod[qq,m,n];#* branch_X_mod[qq,m,n] / (branch_X_mod[qq,m,n]**2+branch_R[1,qq,m,n]**2); - -# Generation for DCOPF -var P_dcopf{(g,n) in UNITON}; # >= unit_Pmin[1,g,n], <= unit_Pmax[1,g,n]; - -# Slack variable for each bus -# >=0 if too much generation in bus, <=0 if missing generation -var balance_pos{BUSCC} >= 0; -var balance_neg{BUSCC} >= 0; - -# Balance at each bus -subject to ctr_balance{PROBLEM_DCOPF, n in BUSCC}: - - sum{(g,n) in UNITON} P_dcopf[g,n] - - sum{(b,n) in BATTERYCC} battery_p0[1,b,n] - + sum{(c,n) in LOADCC} load_PFix[1,c,n] - + sum{(qq,n,m) in BRANCHCC} activeflow[qq,n,m] # active power flow outgoing on branch qq at bus n - - sum{(qq,m,n) in BRANCHCC} activeflow[qq,m,n] # active power flow entering in bus n on branch qq - + sum{(vscconv,n) in VSCCONVON} vscconv_P0[1,vscconv,n] - + sum{(l,n) in LCCCONVON} lccconv_P0[1,l,n] - = - balance_pos[n] - balance_neg[n]; - - +################################################################################ +## +## Variables and contraints for DCOPF +## +################################################################################ +## Why doing a DCOPF before ACOPF? +## 1/ if DCOPF fails, how to hope that ACOPF is feasible? -> DCOPF may be seen as an unformal consistency check on data +## 2/ phases computed in DCOPF will be used as initial point for ACOPF +## Some of the variables and constraints defined for DCOPF will be used also for ACOPF # -# objective function and penalties +## Phase of voltage +#param teta_min default -10; # roughly 3*pi +#param teta_max default 10; # roughly 3*pi +#var teta_dc{n in BUSCC} <= teta_max, >= teta_min; +#subject to ctr_null_phase_bus_dc{PROBLEM_DCOPF}: teta_dc[null_phase_bus] = 0; # -param penalty_gen := 1; -param penalty_balance := 1000; - -minimize problem_dcopf_objective: - penalty_gen * sum{(g,n) in UNITON} ((P_dcopf[g,n]-unit_Pc[1,g,n])/max(0.01*abs(unit_Pc[1,g,n]),1))**2 - + penalty_balance * sum{n in BUSCC} ( balance_pos[n] + balance_neg[n] ) - ; \ No newline at end of file +## Variable flow is the flow from bus 1 to bus 2 +#var activeflow{BRANCHCC}; +#subject to ctr_activeflow{PROBLEM_DCOPF, (qq,m,n) in BRANCHCC}: +# activeflow[qq,m,n] = base100MVA * (teta_dc[m]-teta_dc[n]) / branch_X_mod[qq,m,n];#* branch_X_mod[qq,m,n] / (branch_X_mod[qq,m,n]**2+branch_R[1,qq,m,n]**2); +# +## Generation for DCOPF +#var P_dcopf{(g,n) in UNITON}; # >= unit_Pmin[1,g,n], <= unit_Pmax[1,g,n]; +# +## Slack variable for each bus +## >=0 if too much generation in bus, <=0 if missing generation +#var balance_pos{BUSCC} >= 0; +#var balance_neg{BUSCC} >= 0; +# +## Balance at each bus +#subject to ctr_balance{PROBLEM_DCOPF, n in BUSCC}: +# - sum{(g,n) in UNITON} P_dcopf[g,n] +# - sum{(b,n) in BATTERYCC} battery_p0[1,b,n] +# + sum{(c,n) in LOADCC} load_PFix[1,c,n] +# + sum{(qq,n,m) in BRANCHCC} activeflow[qq,n,m] # active power flow outgoing on branch qq at bus n +# - sum{(qq,m,n) in BRANCHCC} activeflow[qq,m,n] # active power flow entering in bus n on branch qq +# + sum{(vscconv,n) in VSCCONVON} vscconv_P0[1,vscconv,n] +# + sum{(l,n) in LCCCONVON} lccconv_P0[1,l,n] +# = +# balance_pos[n] - balance_neg[n]; +# +# +## +## objective function and penalties +## +#param penalty_gen := 1; +#param penalty_balance := 1000; +# +#minimize problem_dcopf_objective: +# penalty_gen * sum{(g,n) in UNITON} ((P_dcopf[g,n]-unit_Pc[1,g,n])/max(0.01*abs(unit_Pc[1,g,n]),1))**2 +# + penalty_balance * sum{n in BUSCC} ( balance_pos[n] + balance_neg[n] ) +# ; \ No newline at end of file diff --git a/open-reac/src/main/resources/openreac/dcopf.run b/open-reac/src/main/resources/openreac/dcopf.run index 41a47db4..1b4823e3 100644 --- a/open-reac/src/main/resources/openreac/dcopf.run +++ b/open-reac/src/main/resources/openreac/dcopf.run @@ -1,136 +1,136 @@ -############################################################################### -# -# Copyright (c) 2022 2023 2024, RTE (http://www.rte-france.com) -# 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 -# -############################################################################### - -############################################################################### -# Reactive OPF -# Author: Jean Maeght 2022 2023 -# Author: Manuel Ruiz 2023 2024 -############################################################################### - - -############################################################################### -# Solve PROBLEM_DCOPF -############################################################################### - -let PROBLEM_DCOPF := {1}; -let tempstr := ctime(); -printf{LOG_KNITRO} "\n######################################################################\n"; -printf{LOG_KNITRO} "** DCopf solve: start (%s)\n\n",tempstr; - -option knitro_options ("outlev=3"); - -# solve dcopf and avoid knitro printing if user asks -if (log_level_knitro <= 1) then { - solve problem_dcopf_objective > (nullDevice); -} else { - solve problem_dcopf_objective; -} - -printf{LOG_KNITRO} "\n** DCopf solve: end (%s -> %s)\n",tempstr,ctime(); -printf{LOG_KNITRO} "######################################################################\n\n"; - - -############################################################################### -# Analysis of solve_result_num -############################################################################### - -if solve_result_num > 103 -then { - # First return codes of knitro : - # See https://www.artelys.com/docs/knitro/3_referenceManual/knitroamplReference.html#return-codes - # 0 Locally optimal or satisfactory solution. - # 100 Current feasible solution estimate cannot be improved. Nearly optimal. - # 101 Relative change in feasible solution estimate < xtol. - # 102 Current feasible solution estimate cannot be improved. - # 103 Relative change in feasible objective < ftol for ftol_iters. - # 200 Convergence to an infeasible point. Problem may be locally infeasible. - let errorMessage := "DCOPF optimisation failed"; - let final_status := "NOK"; - let dcopf_status := "NOK"; - include reactiveopfexit.run; -} -# "else" is useless since there is an "exit" just above -let dcopf_status := "OK"; - -if sum{n in BUSCC} (balance_pos[n] + balance_neg[n]) >= Pnull -then { - let errorMessage := "QP problem for Dcopf is not feasible since some slack variables are non zero"; - display card({n in BUSCC : balance_pos[n] + balance_neg[n] >= Pnull}); - display sum{n in BUSCC} (balance_pos[n] + balance_neg[n]); - - for{n in BUSCC: balance_pos[n] + balance_neg[n] >= Pnull} - printf{LOG_ERROR} "Bus %Q in substation %Q (Vnomi=%.2fkV, country=%Q) slacks %.2f and %.2f MW\n", - bus_id[1,n], substation_id[1,bus_substation[1,n]], - substation_Vnomi[1,bus_substation[1,n]], substation_country[1,bus_substation[1,n]], - balance_pos[n], balance_neg[n]; - - let final_status := "NOK"; - let dcopf_status := "NOK"; - include reactiveopfexit.run; -} -# "else" is useless since there is an "exit" just above - - -############################################################################### -# Displays after solving -############################################################################### - -printf{LOG_INFO} "\n######################################################################\n"; -printf{LOG_INFO} "** DCopf results\n"; -printf{LOG_INFO} "OK all slack variables for DCOPF are null\n"; -let dcopf_status := "OK"; - -# Print flows on branches with zero impedance -for{(qq,m,n) in BRANCHZNULL} printf{LOG_INFO} "Flow on zero impedance branch %Q: %.f MW\n",branch_id[1,qq,m,n],activeflow[qq,m,n]; - -# Print flows on most loaded lines -let temp1 := max{(qq,m,n) in BRANCHCC}abs(activeflow[qq,m,n]); -printf{LOG_INFO} "Maximum flow: %.2f MW\n",temp1; -for {(qq,m,n) in BRANCHCC : abs(activeflow[qq,m,n]) >= temp1*0.99} printf{LOG_INFO} "Maximum flow %.2f MW is on branch %Q\n", activeflow[qq,m,n],branch_id[1,qq,m,n]; - -# Print generations which are very different from their target value -let temp2 := max{(g,n) in UNITON} abs(P_dcopf[g,n]-unit_Pc[1,g,n]); -printf{LOG_INFO} "Maximum deviation between generation and target: %.2f MW\n",temp2; -if temp2 >= 10 then -for {(g,n) in UNITON : abs(P_dcopf[g,n]-unit_Pc[1,g,n]) >= temp2*0.99} - printf{LOG_INFO} "Generating unit %Q : Pc=%.2fMW P=%.2fMW (Pmin=%.2fMW Pmax=%.2fMW)\n", - unit_id[1,g,n],unit_Pc[1,g,n],P_dcopf[g,n],unit_Pmin[1,g,n],unit_Pmax[1,g,n]; - -# Balance check -let temp1 := sum{(c,n) in LOADCC} load_PFix[1,c,n]; -let temp2 := sum{(g,n) in UNITON} P_dcopf[g,n]; -let temp2 := temp2 + sum{(b,n) in BATTERYCC} battery_p0[1,b,n]; -let temp3 := (sum{(vscconv,n) in VSCCONVON} vscconv_P0[1,vscconv,n])+(sum{(l,k) in LCCCONVON} lccconv_P0[1,l,k]); -printf{LOG_INFO} "Sum of HVDC conv. H: %.0f MW\n", temp3; -printf{LOG_INFO} "Sum of loads C: %.0f MW\n", temp1; -printf{LOG_INFO} "Sum of generations P: %.0f MW\n", temp2; -printf{LOG_INFO} "Balance (P-C-H)/C: %.2f %%\n\n", (temp2-temp1-temp3)/temp1*100; - -# Analysis of phases computed by DC OPF -let teta_max := max({n in BUSCC} teta_dc[n].val) + 3; # radians -let teta_min := min({n in BUSCC} teta_dc[n].val) - 3; # radians -if 1 in LOG_INFO then display teta_max,teta_min,max({n in BUSCC} teta_dc[n]),min({n in BUSCC} teta_dc[n]), - max({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])),min({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])); - -let temp1 := max({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])); -let temp2 := min({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])); - -printf{LOG_INFO}"Branches with large Delta Teta:\n"; -for {(qq,m,n) in BRANCHCC: (teta_dc[m]-teta_dc[n])>temp1*0.99 or (teta_dc[m]-teta_dc[n]) (nullDevice); +#} else { +# solve problem_dcopf_objective; +#} +# +#printf{LOG_KNITRO} "\n** DCopf solve: end (%s -> %s)\n",tempstr,ctime(); +#printf{LOG_KNITRO} "######################################################################\n\n"; +# +# +################################################################################ +## Analysis of solve_result_num +################################################################################ +# +#if solve_result_num > 103 +#then { +# # First return codes of knitro : +# # See https://www.artelys.com/docs/knitro/3_referenceManual/knitroamplReference.html#return-codes +# # 0 Locally optimal or satisfactory solution. +# # 100 Current feasible solution estimate cannot be improved. Nearly optimal. +# # 101 Relative change in feasible solution estimate < xtol. +# # 102 Current feasible solution estimate cannot be improved. +# # 103 Relative change in feasible objective < ftol for ftol_iters. +# # 200 Convergence to an infeasible point. Problem may be locally infeasible. +# let errorMessage := "DCOPF optimisation failed"; +# let final_status := "NOK"; +# let dcopf_status := "NOK"; +# include reactiveopfexit.run; +#} +## "else" is useless since there is an "exit" just above +#let dcopf_status := "OK"; +# +#if sum{n in BUSCC} (balance_pos[n] + balance_neg[n]) >= Pnull +#then { +# let errorMessage := "QP problem for Dcopf is not feasible since some slack variables are non zero"; +# display card({n in BUSCC : balance_pos[n] + balance_neg[n] >= Pnull}); +# display sum{n in BUSCC} (balance_pos[n] + balance_neg[n]); +# +# for{n in BUSCC: balance_pos[n] + balance_neg[n] >= Pnull} +# printf{LOG_ERROR} "Bus %Q in substation %Q (Vnomi=%.2fkV, country=%Q) slacks %.2f and %.2f MW\n", +# bus_id[1,n], substation_id[1,bus_substation[1,n]], +# substation_Vnomi[1,bus_substation[1,n]], substation_country[1,bus_substation[1,n]], +# balance_pos[n], balance_neg[n]; +# +# let final_status := "NOK"; +# let dcopf_status := "NOK"; +# include reactiveopfexit.run; +#} +## "else" is useless since there is an "exit" just above +# +# +################################################################################ +## Displays after solving +################################################################################ +# +#printf{LOG_INFO} "\n######################################################################\n"; +#printf{LOG_INFO} "** DCopf results\n"; +#printf{LOG_INFO} "OK all slack variables for DCOPF are null\n"; +#let dcopf_status := "OK"; +# +## Print flows on branches with zero impedance +#for{(qq,m,n) in BRANCHZNULL} printf{LOG_INFO} "Flow on zero impedance branch %Q: %.f MW\n",branch_id[1,qq,m,n],activeflow[qq,m,n]; +# +## Print flows on most loaded lines +#let temp1 := max{(qq,m,n) in BRANCHCC}abs(activeflow[qq,m,n]); +#printf{LOG_INFO} "Maximum flow: %.2f MW\n",temp1; +#for {(qq,m,n) in BRANCHCC : abs(activeflow[qq,m,n]) >= temp1*0.99} printf{LOG_INFO} "Maximum flow %.2f MW is on branch %Q\n", activeflow[qq,m,n],branch_id[1,qq,m,n]; +# +## Print generations which are very different from their target value +#let temp2 := max{(g,n) in UNITON} abs(P_dcopf[g,n]-unit_Pc[1,g,n]); +#printf{LOG_INFO} "Maximum deviation between generation and target: %.2f MW\n",temp2; +#if temp2 >= 10 then +#for {(g,n) in UNITON : abs(P_dcopf[g,n]-unit_Pc[1,g,n]) >= temp2*0.99} +# printf{LOG_INFO} "Generating unit %Q : Pc=%.2fMW P=%.2fMW (Pmin=%.2fMW Pmax=%.2fMW)\n", +# unit_id[1,g,n],unit_Pc[1,g,n],P_dcopf[g,n],unit_Pmin[1,g,n],unit_Pmax[1,g,n]; +# +## Balance check +#let temp1 := sum{(c,n) in LOADCC} load_PFix[1,c,n]; +#let temp2 := sum{(g,n) in UNITON} P_dcopf[g,n]; +#let temp2 := temp2 + sum{(b,n) in BATTERYCC} battery_p0[1,b,n]; +#let temp3 := (sum{(vscconv,n) in VSCCONVON} vscconv_P0[1,vscconv,n])+(sum{(l,k) in LCCCONVON} lccconv_P0[1,l,k]); +#printf{LOG_INFO} "Sum of HVDC conv. H: %.0f MW\n", temp3; +#printf{LOG_INFO} "Sum of loads C: %.0f MW\n", temp1; +#printf{LOG_INFO} "Sum of generations P: %.0f MW\n", temp2; +#printf{LOG_INFO} "Balance (P-C-H)/C: %.2f %%\n\n", (temp2-temp1-temp3)/temp1*100; +# +## Analysis of phases computed by DC OPF +#let teta_max := max({n in BUSCC} teta_dc[n].val) + 3; # radians +#let teta_min := min({n in BUSCC} teta_dc[n].val) - 3; # radians +#if 1 in LOG_INFO then display teta_max,teta_min,max({n in BUSCC} teta_dc[n]),min({n in BUSCC} teta_dc[n]), +# max({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])),min({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])); +# +#let temp1 := max({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])); +#let temp2 := min({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])); +# +#printf{LOG_INFO}"Branches with large Delta Teta:\n"; +#for {(qq,m,n) in BRANCHCC: (teta_dc[m]-teta_dc[n])>temp1*0.99 or (teta_dc[m]-teta_dc[n]) (fileOut); printf "\n" > (fileOut); -printf "max_teta_dc %.2f\n",max({n in BUSCC} teta_dc[n]) > (fileOut); +#printf "max_teta_dc %.2f\n",max({n in BUSCC} teta_dc[n]) > (fileOut); printf "max_teta_ac %.2f\n",max({n in BUSCC} teta[n]) > (fileOut); printf "teta_max %.2f\n",teta_max > (fileOut); -printf "min_teta_dc %.2f\n",min({n in BUSCC} teta_dc[n]) > (fileOut); +#printf "min_teta_dc %.2f\n",min({n in BUSCC} teta_dc[n]) > (fileOut); printf "min_teta_ac %.2f\n",min({n in BUSCC} teta[n]) > (fileOut); printf "teta_min %.2f\n",teta_min > (fileOut); -printf "max_delta_teta_dc %2f\n",max({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])) > (fileOut); +#printf "max_delta_teta_dc %2f\n",max({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])) > (fileOut); printf "max_delta_teta_ac %2f\n",max({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])) > (fileOut); -printf "min_delta_teta_dc %2f\n",min({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])) > (fileOut); +#printf "min_delta_teta_dc %2f\n",min({(qq,m,n) in BRANCHCC} (teta_dc[m]-teta_dc[n])) > (fileOut); printf "min_delta_teta_ac %2f\n",min({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])) > (fileOut); printf "\n" > (fileOut); From adf98987cea3c040342ea1da2c599235e93cfec6 Mon Sep 17 00:00:00 2001 From: p-arvy Date: Wed, 7 Aug 2024 12:00:38 +0200 Subject: [PATCH 02/10] Add JSON ser/deserialization and modify TUs Signed-off-by: p-arvy --- .../input/json/OpenReacParametersDeserializer.java | 4 ++++ .../input/json/OpenReacParametersSerializer.java | 1 + .../java/com/powsybl/openreac/OpenReacRunnerTest.java | 8 ++++---- .../parameters/input/json/OpenReacJsonModuleTest.java | 2 ++ open-reac/src/test/resources/parametersLists.json | 3 ++- open-reac/src/test/resources/parametersThresholds.json | 3 ++- 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java index f49506a4..24c9e069 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java +++ b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java @@ -151,6 +151,10 @@ public OpenReacParameters deserialize(JsonParser parser, DeserializationContext parser.nextToken(); parameters.setShuntVariableScalingFactor(parser.readValueAs(Double.class)); } + case "dcLoadFlowBeforeOptimization" -> { + parser.nextToken(); + parameters.setDcLoadFlowBeforeOptimization(parser.readValueAs(Boolean.class)); + } default -> throw new IllegalStateException("Unexpected field: " + parser.getCurrentName()); } } diff --git a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java index 3225d5b0..e174177e 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java +++ b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java @@ -62,6 +62,7 @@ public void serialize(OpenReacParameters openReacParameters, JsonGenerator jsonG serializerProvider.defaultSerializeField("reactiveSlackVariableScalingFactor", openReacParameters.getReactiveSlackVariableScalingFactor(), jsonGenerator); serializerProvider.defaultSerializeField("twoWindingTransformerRatioVariableScalingFactor", openReacParameters.getTwoWindingTransformerRatioVariableScalingFactor(), jsonGenerator); serializerProvider.defaultSerializeField("shuntVariableScalingFactor", openReacParameters.getShuntVariableScalingFactor(), jsonGenerator); + serializerProvider.defaultSerializeField("dcLoadFlowBeforeOptimization", openReacParameters.isDcLoadFlowBeforeOptimization(), jsonGenerator); jsonGenerator.writeEndObject(); } } diff --git a/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java b/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java index 4a0179f7..954e20f8 100644 --- a/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java +++ b/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java @@ -385,7 +385,7 @@ void testWarmStart() throws IOException { setDefaultVoltageLimits(network); String subFolder = "openreac-output-warm-start"; OpenReacParameters parameters = new OpenReacParameters(); - + parameters.setDcLoadFlowBeforeOptimization(false); runAndApplyAllModifications(network, subFolder, parameters, false, ReportNode.NO_OP); // without warm start, no update assertEquals(Double.NaN, network.getBusBreakerView().getBus("BUS_1").getV()); assertEquals(Double.NaN, network.getBusBreakerView().getBus("BUS_1").getAngle()); @@ -414,9 +414,9 @@ private void runAndApplyAllModifications(Network network, String subFolder, Open subFolder + "/reactiveopf_results_vsc_converter_stations.csv", subFolder + "/reactiveopf_results_voltages.csv")); // To really run open reac, use the commentede line below. Be sure that open-reac/src/test/resources/com/powsybl/config/test/config.yml contains your ampl path -// try (ComputationManager computationManager = new LocalComputationManager()) { - try (ComputationManager computationManager = new LocalComputationManager(new LocalComputationConfig(tmpDir), - localCommandExecutor, ForkJoinPool.commonPool())) { + try (ComputationManager computationManager = new LocalComputationManager()) { +// try (ComputationManager computationManager = new LocalComputationManager(new LocalComputationConfig(tmpDir), +// localCommandExecutor, ForkJoinPool.commonPool())) { OpenReacResult openReacResult = OpenReacRunner.run(network, network.getVariantManager().getWorkingVariantId(), parameters, new OpenReacConfig(true), computationManager, reportNode, null); diff --git a/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java b/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java index 7f4e1b16..53771666 100644 --- a/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java +++ b/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java @@ -96,6 +96,7 @@ void testOpenReacParametersThresholds() throws IOException { parameters.setDefaultConstraintScalingFactor(0.888); parameters.setReactiveSlackVariableScalingFactor(1e-2); parameters.setTwoWindingTransformerRatioVariableScalingFactor(0.005); + parameters.setDcLoadFlowBeforeOptimization(false); String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(parameters); ComparisonUtils.assertTxtEquals(Objects.requireNonNull(getClass().getResourceAsStream("/parametersThresholds.json")), json); @@ -122,5 +123,6 @@ void testOpenReacParametersThresholds() throws IOException { assertEquals(0.888, parameters2.getDefaultConstraintScalingFactor()); assertEquals(1e-2, parameters2.getReactiveSlackVariableScalingFactor()); assertEquals(0.005, parameters2.getTwoWindingTransformerRatioVariableScalingFactor()); + assertEquals(false, parameters2.isDcLoadFlowBeforeOptimization()); } } diff --git a/open-reac/src/test/resources/parametersLists.json b/open-reac/src/test/resources/parametersLists.json index 69d5e7c3..50e4030c 100644 --- a/open-reac/src/test/resources/parametersLists.json +++ b/open-reac/src/test/resources/parametersLists.json @@ -45,5 +45,6 @@ "defaultConstraintScalingFactor" : 1.0, "reactiveSlackVariableScalingFactor" : 0.1, "twoWindingTransformerRatioVariableScalingFactor" : 0.001, - "shuntVariableScalingFactor" : 0.1 + "shuntVariableScalingFactor" : 0.1, + "dcLoadFlowBeforeOptimization" : true } \ No newline at end of file diff --git a/open-reac/src/test/resources/parametersThresholds.json b/open-reac/src/test/resources/parametersThresholds.json index 96df9fa8..4ee25537 100644 --- a/open-reac/src/test/resources/parametersThresholds.json +++ b/open-reac/src/test/resources/parametersThresholds.json @@ -25,5 +25,6 @@ "defaultConstraintScalingFactor" : 0.888, "reactiveSlackVariableScalingFactor" : 0.01, "twoWindingTransformerRatioVariableScalingFactor" : 0.005, - "shuntVariableScalingFactor" : 0.1 + "shuntVariableScalingFactor" : 0.1, + "dcLoadFlowBeforeOptimization" : false } \ No newline at end of file From 7efcc43ec3fe641365d95e77fa1a437d658cd635 Mon Sep 17 00:00:00 2001 From: p-arvy Date: Wed, 21 Aug 2024 15:53:19 +0200 Subject: [PATCH 03/10] Use initializer instead of LF Signed-off-by: p-arvy --- .../com/powsybl/openreac/OpenReacRunner.java | 82 ++++++++++++------- .../src/main/resources/openreac/acopf.mod | 4 +- .../src/main/resources/openreac/acopf.run | 3 + .../powsybl/openreac/OpenReacRunnerTest.java | 3 +- .../com/powsybl/config/test/config.yml | 2 +- 5 files changed, 61 insertions(+), 33 deletions(-) diff --git a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java index 6e47a498..ae907586 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java +++ b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java @@ -20,8 +20,15 @@ import com.powsybl.loadflow.LoadFlow; import com.powsybl.loadflow.LoadFlowParameters; import com.powsybl.loadflow.LoadFlowResult; +import com.powsybl.math.matrix.DenseMatrixFactory; +import com.powsybl.math.matrix.MatrixFactory; +import com.powsybl.openloadflow.FullVoltageInitializer; import com.powsybl.openloadflow.OpenLoadFlowParameters; -import com.powsybl.openloadflow.network.SlackBusSelectionMode; +import com.powsybl.openloadflow.ac.VoltageMagnitudeInitializer; +import com.powsybl.openloadflow.dc.DcValueVoltageInitializer; +import com.powsybl.openloadflow.dc.equations.DcApproximationType; +import com.powsybl.openloadflow.network.*; +import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl; import com.powsybl.openreac.parameters.OpenReacAmplIOFiles; import com.powsybl.openreac.parameters.input.OpenReacParameters; import com.powsybl.openreac.parameters.output.OpenReacResult; @@ -146,13 +153,13 @@ public static CompletableFuture runAsync(Network network, String runDcLf(network, parameters); runAsync = AmplModelRunner.runAsync(network, WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX, reactiveOpf, manager, amplIoInterface); // remove the variant created to store dc load flow results - variantManager.setWorkingVariant(variantId); - variantManager.removeVariant(WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); } else { runAsync = AmplModelRunner.runAsync(network, variantId, reactiveOpf, manager, amplIoInterface); } return runAsync.thenApply(run -> { + network.getVariantManager().setWorkingVariant(variantId); + network.getVariantManager().removeVariant(WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); OpenReacResult result = new OpenReacResult(run.isSuccess() && amplIoInterface.checkErrors() ? OpenReacStatus.OK : OpenReacStatus.NOT_OK, amplIoInterface, run.getIndicators()); Reports.createShuntModificationsReporter(reportNode, network.getId(), amplIoInterface.getNetworkModifications().getShuntsWithDeltaDiscreteOptimalOverThreshold()); return result; @@ -169,31 +176,48 @@ private static void checkParameters(Network network, String variantId, OpenReacP parameters.checkIntegrity(network, Reports.createParameterIntegrityReporter(reportNode, network.getId())); } - private static void runDcLf(Network network, OpenReacParameters parameters) { - // store network voltages to apply them later - // currently, dc load flow erases these values for NaN - HashMap voltageValues = new HashMap<>(); - network.getBusView().getBusStream() - .filter(Bus::isInMainSynchronousComponent) - .forEach(bus -> voltageValues.put(bus.getId(), bus.getAngle())); - - LoadFlowParameters loadFlowParameters = new LoadFlowParameters(); - loadFlowParameters.setDc(true) - .setConnectedComponentMode(LoadFlowParameters.ConnectedComponentMode.MAIN) - .setDistributedSlack(true) - .setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_P); - OpenLoadFlowParameters.create(loadFlowParameters) - .setLowImpedanceThreshold(parameters.getLowImpedanceThreshold()) - .setLowImpedanceBranchMode(OpenLoadFlowParameters.LowImpedanceBranchMode.REPLACE_BY_MIN_IMPEDANCE_LINE) - .setSlackBusSelectionMode(SlackBusSelectionMode.NAME) - .setSlackBusId("b5_vl_0"); - - LoadFlowResult result = LoadFlow.find("OpenLoadFlow").run(network, loadFlowParameters); - if (result.isFailed()) { - throw new PowsyblException("If DC load flow fails, no hope that reactive ACOPF converges."); - } - - // restore voltage values of the network - voltageValues.forEach((k, v) -> network.getBusView().getBus(k).setV(1)); + private static void runDcLf(Network network, OpenReacParameters openReacParameters) { + + SlackBusSelector slackBusSelector = new MostMeshedSlackBusSelector(); + LfNetwork lfNetwork = LfNetwork.load(network, new LfNetworkLoaderImpl(), slackBusSelector).get(0); + MatrixFactory matrixFactory = new DenseMatrixFactory(); + FullVoltageInitializer initializer = new FullVoltageInitializer( + new VoltageMagnitudeInitializer(false, matrixFactory, openReacParameters.getLowImpedanceThreshold()), + new DcValueVoltageInitializer(new LfNetworkParameters().setSlackBusSelector(slackBusSelector), + true, + LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_P, + true, + DcApproximationType.IGNORE_R, + matrixFactory, + 10)); + initializer.prepare(lfNetwork); + lfNetwork.updateState(new LfNetworkStateUpdateParameters(false, false, true, false, false, + false, true, false, ReactivePowerDispatchMode.Q_EQUAL_PROPORTION, false, ReferenceBusSelectionMode.FIRST_SLACK, false)); + +// // store network voltages to apply them later +// // currently, dc load flow erases these values for NaN +// HashMap voltageValues = new HashMap<>(); +// network.getBusView().getBusStream() +// .filter(Bus::isInMainSynchronousComponent) +// .forEach(bus -> voltageValues.put(bus.getId(), bus.getAngle())); +// +// LoadFlowParameters loadFlowParameters = new LoadFlowParameters(); +// loadFlowParameters.setDc(true) +// .setConnectedComponentMode(LoadFlowParameters.ConnectedComponentMode.MAIN) +// .setDistributedSlack(true) +// .setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_P) +// .setHvdcAcEmulation(false); +// OpenLoadFlowParameters.create(loadFlowParameters) +// .setAlwaysUpdateNetwork(true) +// .setLowImpedanceThreshold(openReacParameters.getLowImpedanceThreshold()) +// .setLowImpedanceBranchMode(OpenLoadFlowParameters.LowImpedanceBranchMode.REPLACE_BY_MIN_IMPEDANCE_LINE); + +// LoadFlowResult result = LoadFlow.find("OpenLoadFlow").run(network, loadFlowParameters); +// if (result.isFailed()) { +// throw new PowsyblException("If DC load flow fails, no hope that reactive ACOPF converges."); +// } +// +// // restore voltage values of the network +// voltageValues.forEach((k, v) -> network.getBusView().getBus(k).setV(v)); } } diff --git a/open-reac/src/main/resources/openreac/acopf.mod b/open-reac/src/main/resources/openreac/acopf.mod index dc0d203d..35cb3c84 100644 --- a/open-reac/src/main/resources/openreac/acopf.mod +++ b/open-reac/src/main/resources/openreac/acopf.mod @@ -30,8 +30,8 @@ set PROBLEM_ACOPF default { }; # Complex voltage = V*exp(i*teta). (with i**2=-1) # Phase of voltage -param teta_min default -10; # roughly 3*pi -param teta_max default 10; # roughly 3*pi +param teta_min default -3; # roughly 3*pi +param teta_max default 3; # roughly 3*pi var teta{BUSCC} <= teta_max, >= teta_min; subject to ctr_null_phase_bus{PROBLEM_ACOPF}: teta[null_phase_bus] = 0; diff --git a/open-reac/src/main/resources/openreac/acopf.run b/open-reac/src/main/resources/openreac/acopf.run index d1d322de..32c4f659 100644 --- a/open-reac/src/main/resources/openreac/acopf.run +++ b/open-reac/src/main/resources/openreac/acopf.run @@ -20,6 +20,9 @@ ############################################################################### # DC values used as initialization for phases + +let teta_max := max({n in BUSCC : -10 <= bus_angl0[1,n] and bus_angl0[1,n] <= 10} bus_angl0[1,n]) + 3; +let teta_min := min({n in BUSCC : -10 <= bus_angl0[1,n] and bus_angl0[1,n] <= 10} bus_angl0[1,n]) - 3; let {n in BUSCC} teta[n] := if teta_min <= bus_angl0[1,n] and bus_angl0[1,n] <= teta_max then bus_angl0[1,n] else 0; diff --git a/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java b/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java index 954e20f8..a6ae6990 100644 --- a/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java +++ b/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java @@ -284,6 +284,8 @@ void testHvdc() throws IOException { network.getVscConverterStation("cs3").getTerminal().setP(0.0); network.getVscConverterStation("cs4").getTerminal().setP(0.0); OpenReacParameters parameters = new OpenReacParameters(); +// parameters.setObjective(OpenReacOptimisationObjective.BETWEEN_HIGH_AND_LOW_VOLTAGE_LIMIT) +// .setObjectiveDistance(50); parameters.addConstantQGenerators(List.of("g1", "g2", "g5", "g6")); testAllModifAndLoadFlow(network, "openreac-output-vsc", parameters, ReportNode.NO_OP); } @@ -385,7 +387,6 @@ void testWarmStart() throws IOException { setDefaultVoltageLimits(network); String subFolder = "openreac-output-warm-start"; OpenReacParameters parameters = new OpenReacParameters(); - parameters.setDcLoadFlowBeforeOptimization(false); runAndApplyAllModifications(network, subFolder, parameters, false, ReportNode.NO_OP); // without warm start, no update assertEquals(Double.NaN, network.getBusBreakerView().getBus("BUS_1").getV()); assertEquals(Double.NaN, network.getBusBreakerView().getBus("BUS_1").getAngle()); diff --git a/open-reac/src/test/resources/com/powsybl/config/test/config.yml b/open-reac/src/test/resources/com/powsybl/config/test/config.yml index 1acd4f0d..9d797384 100644 --- a/open-reac/src/test/resources/com/powsybl/config/test/config.yml +++ b/open-reac/src/test/resources/com/powsybl/config/test/config.yml @@ -1,2 +1,2 @@ ampl: - homeDir: ??? + homeDir: D:\AMPL-13.1.20220703-Win-64 From 1f81ac86d88946aabb2d587fa82e76170068bca0 Mon Sep 17 00:00:00 2001 From: p-arvy Date: Wed, 21 Aug 2024 17:11:25 +0200 Subject: [PATCH 04/10] Small clean Signed-off-by: p-arvy --- .../com/powsybl/openreac/OpenReacRunner.java | 53 ++++++------------- .../powsybl/openreac/OpenReacRunnerTest.java | 4 +- .../com/powsybl/config/test/config.yml | 2 +- 3 files changed, 19 insertions(+), 40 deletions(-) diff --git a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java index ae907586..1a616e92 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java +++ b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java @@ -10,34 +10,28 @@ import com.powsybl.ampl.executor.AmplModel; import com.powsybl.ampl.executor.AmplModelRunner; import com.powsybl.ampl.executor.AmplResults; -import com.powsybl.commons.PowsyblException; import com.powsybl.commons.report.ReportNode; import com.powsybl.computation.ComputationManager; import com.powsybl.computation.local.LocalComputationManager; -import com.powsybl.iidm.network.Bus; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.VariantManager; -import com.powsybl.loadflow.LoadFlow; import com.powsybl.loadflow.LoadFlowParameters; -import com.powsybl.loadflow.LoadFlowResult; import com.powsybl.math.matrix.DenseMatrixFactory; import com.powsybl.math.matrix.MatrixFactory; import com.powsybl.openloadflow.FullVoltageInitializer; -import com.powsybl.openloadflow.OpenLoadFlowParameters; import com.powsybl.openloadflow.ac.VoltageMagnitudeInitializer; import com.powsybl.openloadflow.dc.DcValueVoltageInitializer; import com.powsybl.openloadflow.dc.equations.DcApproximationType; import com.powsybl.openloadflow.network.*; +import com.powsybl.openloadflow.network.impl.LfGeneratorImpl; import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl; import com.powsybl.openreac.parameters.OpenReacAmplIOFiles; import com.powsybl.openreac.parameters.input.OpenReacParameters; import com.powsybl.openreac.parameters.output.OpenReacResult; import com.powsybl.openreac.parameters.output.OpenReacStatus; -import java.util.HashMap; import java.util.Objects; import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; /** * @author Nicolas Pierre {@literal } @@ -177,10 +171,12 @@ private static void checkParameters(Network network, String variantId, OpenReacP } private static void runDcLf(Network network, OpenReacParameters openReacParameters) { - + // slack bus selection SlackBusSelector slackBusSelector = new MostMeshedSlackBusSelector(); LfNetwork lfNetwork = LfNetwork.load(network, new LfNetworkLoaderImpl(), slackBusSelector).get(0); MatrixFactory matrixFactory = new DenseMatrixFactory(); + + // full voltage initializer, to initialize voltage magnitudes and angles FullVoltageInitializer initializer = new FullVoltageInitializer( new VoltageMagnitudeInitializer(false, matrixFactory, openReacParameters.getLowImpedanceThreshold()), new DcValueVoltageInitializer(new LfNetworkParameters().setSlackBusSelector(slackBusSelector), @@ -189,35 +185,18 @@ private static void runDcLf(Network network, OpenReacParameters openReacParamete true, DcApproximationType.IGNORE_R, matrixFactory, - 10)); + 1)); // FIXME : which number is optimal ? + + // compute initialization initializer.prepare(lfNetwork); - lfNetwork.updateState(new LfNetworkStateUpdateParameters(false, false, true, false, false, - false, true, false, ReactivePowerDispatchMode.Q_EQUAL_PROPORTION, false, ReferenceBusSelectionMode.FIRST_SLACK, false)); - -// // store network voltages to apply them later -// // currently, dc load flow erases these values for NaN -// HashMap voltageValues = new HashMap<>(); -// network.getBusView().getBusStream() -// .filter(Bus::isInMainSynchronousComponent) -// .forEach(bus -> voltageValues.put(bus.getId(), bus.getAngle())); -// -// LoadFlowParameters loadFlowParameters = new LoadFlowParameters(); -// loadFlowParameters.setDc(true) -// .setConnectedComponentMode(LoadFlowParameters.ConnectedComponentMode.MAIN) -// .setDistributedSlack(true) -// .setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_P) -// .setHvdcAcEmulation(false); -// OpenLoadFlowParameters.create(loadFlowParameters) -// .setAlwaysUpdateNetwork(true) -// .setLowImpedanceThreshold(openReacParameters.getLowImpedanceThreshold()) -// .setLowImpedanceBranchMode(OpenLoadFlowParameters.LowImpedanceBranchMode.REPLACE_BY_MIN_IMPEDANCE_LINE); - -// LoadFlowResult result = LoadFlow.find("OpenLoadFlow").run(network, loadFlowParameters); -// if (result.isFailed()) { -// throw new PowsyblException("If DC load flow fails, no hope that reactive ACOPF converges."); -// } -// -// // restore voltage values of the network -// voltageValues.forEach((k, v) -> network.getBusView().getBus(k).setV(v)); + + // update the state of the buses and of the generators to warm start AC optimization + LfNetworkStateUpdateParameters updateParameters = new LfNetworkStateUpdateParameters(false, false, true, false, false, + false, true, false, ReactivePowerDispatchMode.Q_EQUAL_PROPORTION, false, ReferenceBusSelectionMode.FIRST_SLACK, false); + lfNetwork.getBuses().forEach(bus -> bus.updateState(updateParameters)); + lfNetwork.getBuses().stream() + .flatMap(lfBus -> lfBus.getGenerators().stream()) + .filter(lfGenerator -> lfGenerator instanceof LfGeneratorImpl) // only active power of generators is optimized in OpenReac, not one of batteries and vsc + .forEach(lfGenerator -> lfGenerator.updateState(updateParameters)); } } diff --git a/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java b/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java index a6ae6990..b0181dc0 100644 --- a/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java +++ b/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java @@ -284,8 +284,6 @@ void testHvdc() throws IOException { network.getVscConverterStation("cs3").getTerminal().setP(0.0); network.getVscConverterStation("cs4").getTerminal().setP(0.0); OpenReacParameters parameters = new OpenReacParameters(); -// parameters.setObjective(OpenReacOptimisationObjective.BETWEEN_HIGH_AND_LOW_VOLTAGE_LIMIT) -// .setObjectiveDistance(50); parameters.addConstantQGenerators(List.of("g1", "g2", "g5", "g6")); testAllModifAndLoadFlow(network, "openreac-output-vsc", parameters, ReportNode.NO_OP); } @@ -427,6 +425,8 @@ private void runAndApplyAllModifications(Network network, String subFolder, Open } } + // TODO : add a test to verify the network is not modify by open reac runner + public static Network create() { Network network = Network.create("svc", "test"); Substation s1 = network.newSubstation() diff --git a/open-reac/src/test/resources/com/powsybl/config/test/config.yml b/open-reac/src/test/resources/com/powsybl/config/test/config.yml index 9d797384..1acd4f0d 100644 --- a/open-reac/src/test/resources/com/powsybl/config/test/config.yml +++ b/open-reac/src/test/resources/com/powsybl/config/test/config.yml @@ -1,2 +1,2 @@ ampl: - homeDir: D:\AMPL-13.1.20220703-Win-64 + homeDir: ??? From e3be6069f79efde59381cc61df97f1008a9f5cf5 Mon Sep 17 00:00:00 2001 From: p-arvy Date: Wed, 21 Aug 2024 17:13:05 +0200 Subject: [PATCH 05/10] Remove usage of OR Signed-off-by: p-arvy --- .../test/java/com/powsybl/openreac/OpenReacRunnerTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java b/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java index b0181dc0..6f676d93 100644 --- a/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java +++ b/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java @@ -385,6 +385,7 @@ void testWarmStart() throws IOException { setDefaultVoltageLimits(network); String subFolder = "openreac-output-warm-start"; OpenReacParameters parameters = new OpenReacParameters(); + runAndApplyAllModifications(network, subFolder, parameters, false, ReportNode.NO_OP); // without warm start, no update assertEquals(Double.NaN, network.getBusBreakerView().getBus("BUS_1").getV()); assertEquals(Double.NaN, network.getBusBreakerView().getBus("BUS_1").getAngle()); @@ -413,9 +414,9 @@ private void runAndApplyAllModifications(Network network, String subFolder, Open subFolder + "/reactiveopf_results_vsc_converter_stations.csv", subFolder + "/reactiveopf_results_voltages.csv")); // To really run open reac, use the commentede line below. Be sure that open-reac/src/test/resources/com/powsybl/config/test/config.yml contains your ampl path - try (ComputationManager computationManager = new LocalComputationManager()) { -// try (ComputationManager computationManager = new LocalComputationManager(new LocalComputationConfig(tmpDir), -// localCommandExecutor, ForkJoinPool.commonPool())) { +// try (ComputationManager computationManager = new LocalComputationManager()) { + try (ComputationManager computationManager = new LocalComputationManager(new LocalComputationConfig(tmpDir), + localCommandExecutor, ForkJoinPool.commonPool())) { OpenReacResult openReacResult = OpenReacRunner.run(network, network.getVariantManager().getWorkingVariantId(), parameters, new OpenReacConfig(true), computationManager, reportNode, null); From 6826718b2309fbe828ca009c1f82f5b57b26fe52 Mon Sep 17 00:00:00 2001 From: p-arvy Date: Mon, 2 Sep 2024 15:47:06 +0200 Subject: [PATCH 06/10] Add GSK and update whole network after initialization Signed-off-by: p-arvy --- .../com/powsybl/openreac/OpenReacRunner.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java index 1a616e92..29ce2cbe 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java +++ b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java @@ -15,15 +15,15 @@ import com.powsybl.computation.local.LocalComputationManager; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.VariantManager; +import com.powsybl.iidm.network.extensions.ActivePowerControlAdder; import com.powsybl.loadflow.LoadFlowParameters; -import com.powsybl.math.matrix.DenseMatrixFactory; import com.powsybl.math.matrix.MatrixFactory; +import com.powsybl.math.matrix.SparseMatrixFactory; import com.powsybl.openloadflow.FullVoltageInitializer; import com.powsybl.openloadflow.ac.VoltageMagnitudeInitializer; import com.powsybl.openloadflow.dc.DcValueVoltageInitializer; import com.powsybl.openloadflow.dc.equations.DcApproximationType; import com.powsybl.openloadflow.network.*; -import com.powsybl.openloadflow.network.impl.LfGeneratorImpl; import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl; import com.powsybl.openreac.parameters.OpenReacAmplIOFiles; import com.powsybl.openreac.parameters.input.OpenReacParameters; @@ -171,17 +171,24 @@ private static void checkParameters(Network network, String variantId, OpenReacP } private static void runDcLf(Network network, OpenReacParameters openReacParameters) { + network.getGeneratorStream() + .forEach(generator -> generator.newExtension(ActivePowerControlAdder.class) + .withParticipate(true) + .withParticipationFactor(generator.getTargetP())); + // slack bus selection SlackBusSelector slackBusSelector = new MostMeshedSlackBusSelector(); + + // get lfNetwork to apply initialization on it LfNetwork lfNetwork = LfNetwork.load(network, new LfNetworkLoaderImpl(), slackBusSelector).get(0); - MatrixFactory matrixFactory = new DenseMatrixFactory(); // full voltage initializer, to initialize voltage magnitudes and angles + MatrixFactory matrixFactory = new SparseMatrixFactory(); FullVoltageInitializer initializer = new FullVoltageInitializer( new VoltageMagnitudeInitializer(false, matrixFactory, openReacParameters.getLowImpedanceThreshold()), new DcValueVoltageInitializer(new LfNetworkParameters().setSlackBusSelector(slackBusSelector), true, - LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_P, + LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_PARTICIPATION_FACTOR, true, DcApproximationType.IGNORE_R, matrixFactory, @@ -193,10 +200,11 @@ private static void runDcLf(Network network, OpenReacParameters openReacParamete // update the state of the buses and of the generators to warm start AC optimization LfNetworkStateUpdateParameters updateParameters = new LfNetworkStateUpdateParameters(false, false, true, false, false, false, true, false, ReactivePowerDispatchMode.Q_EQUAL_PROPORTION, false, ReferenceBusSelectionMode.FIRST_SLACK, false); - lfNetwork.getBuses().forEach(bus -> bus.updateState(updateParameters)); - lfNetwork.getBuses().stream() - .flatMap(lfBus -> lfBus.getGenerators().stream()) - .filter(lfGenerator -> lfGenerator instanceof LfGeneratorImpl) // only active power of generators is optimized in OpenReac, not one of batteries and vsc - .forEach(lfGenerator -> lfGenerator.updateState(updateParameters)); + lfNetwork.updateState(updateParameters); + // lfNetwork.getBuses().forEach(bus -> bus.updateState(updateParameters)); +// lfNetwork.getBuses().stream() +// .flatMap(lfBus -> lfBus.getGenerators().stream()) +// .filter(lfGenerator -> lfGenerator instanceof LfGeneratorImpl) // only active power of generators is optimized in OpenReac, not one of batteries and vsc +// .forEach(lfGenerator -> lfGenerator.updateState(updateParameters)); } } From ff1353037d912bcf22dbb1071b48886dbc66429c Mon Sep 17 00:00:00 2001 From: p-arvy Date: Mon, 2 Sep 2024 16:24:51 +0200 Subject: [PATCH 07/10] Add voltage initialization options in open reac java parameters Signed-off-by: p-arvy --- .../com/powsybl/openreac/OpenReacRunner.java | 111 +++++++++++------- .../parameters/input/OpenReacParameters.java | 17 ++- 2 files changed, 80 insertions(+), 48 deletions(-) diff --git a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java index 29ce2cbe..2d757fb1 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java +++ b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java @@ -25,6 +25,8 @@ import com.powsybl.openloadflow.dc.equations.DcApproximationType; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl; +import com.powsybl.openloadflow.network.util.UniformValueVoltageInitializer; +import com.powsybl.openloadflow.network.util.VoltageInitializer; import com.powsybl.openreac.parameters.OpenReacAmplIOFiles; import com.powsybl.openreac.parameters.input.OpenReacParameters; import com.powsybl.openreac.parameters.output.OpenReacResult; @@ -38,7 +40,7 @@ */ public final class OpenReacRunner { - private static final String WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX = "WithDcLoadFlow"; + private static final String WITH_USER_INITIALIZATION_ID_VARIANT = "WithDcLoadFlow"; private OpenReacRunner() { } @@ -89,19 +91,26 @@ public static OpenReacResult run(Network network, String variantId, OpenReacPara OpenReacAmplIOFiles amplIoInterface = new OpenReacAmplIOFiles(parameters, amplExportConfig, network, config.isDebug(), Reports.createOpenReacReporter(reportNode, network.getId(), parameters.getObjective())); AmplResults run; - if (parameters.isDcLoadFlowBeforeOptimization()) { - // create new variant to avoid modifying the network + // current voltage values are used to initialize ACOPF optimization + if (parameters.getVoltageInitialization() == OpenReacParameters.OpenReacVoltageInitialization.PREVIOUS_VALUES) { + run = AmplModelRunner.run(network, variantId, reactiveOpf, manager, amplIoInterface); + + // initialize optimization with user option + } else { + // create new variant to avoid modifications of the network VariantManager variantManager = network.getVariantManager(); - variantManager.cloneVariant(variantId, WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); - variantManager.setWorkingVariant(WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); - // warm start the optimization with dc load flow results - runDcLf(network, parameters); - run = AmplModelRunner.run(network, WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX, reactiveOpf, manager, amplIoInterface); + variantManager.cloneVariant(variantId, WITH_USER_INITIALIZATION_ID_VARIANT); + variantManager.setWorkingVariant(WITH_USER_INITIALIZATION_ID_VARIANT); + + // initialize the optimization with given process + initializeVoltageBeforeOptimization(network, parameters); + + // execute ampl code + run = AmplModelRunner.run(network, WITH_USER_INITIALIZATION_ID_VARIANT, reactiveOpf, manager, amplIoInterface); + // remove the variant created to store dc load flow results variantManager.setWorkingVariant(variantId); - variantManager.removeVariant(WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); - } else { - run = AmplModelRunner.run(network, variantId, reactiveOpf, manager, amplIoInterface); + variantManager.removeVariant(WITH_USER_INITIALIZATION_ID_VARIANT); } OpenReacResult result = new OpenReacResult(run.isSuccess() && amplIoInterface.checkErrors() ? OpenReacStatus.OK : OpenReacStatus.NOT_OK, amplIoInterface, run.getIndicators()); @@ -138,22 +147,27 @@ public static CompletableFuture runAsync(Network network, String OpenReacAmplIOFiles amplIoInterface = new OpenReacAmplIOFiles(parameters, amplExportConfig, network, config.isDebug(), Reports.createOpenReacReporter(reportNode, network.getId(), parameters.getObjective())); CompletableFuture runAsync; - if (parameters.isDcLoadFlowBeforeOptimization()) { - // create new variant to avoid modifying the network - VariantManager variantManager = network.getVariantManager(); - variantManager.cloneVariant(variantId, WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); - variantManager.setWorkingVariant(WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); - // warm start the optimization with dc load flow results - runDcLf(network, parameters); - runAsync = AmplModelRunner.runAsync(network, WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX, reactiveOpf, manager, amplIoInterface); - // remove the variant created to store dc load flow results - } else { + if (parameters.getVoltageInitialization() == OpenReacParameters.OpenReacVoltageInitialization.PREVIOUS_VALUES) { runAsync = AmplModelRunner.runAsync(network, variantId, reactiveOpf, manager, amplIoInterface); + } else { + // create new variant to avoid modifications of the network + VariantManager variantManager = network.getVariantManager(); + variantManager.cloneVariant(variantId, WITH_USER_INITIALIZATION_ID_VARIANT); + variantManager.setWorkingVariant(WITH_USER_INITIALIZATION_ID_VARIANT); + + // initialize the optimization with given process + initializeVoltageBeforeOptimization(network, parameters); + + // execute ampl code + runAsync = AmplModelRunner.runAsync(network, WITH_USER_INITIALIZATION_ID_VARIANT, reactiveOpf, manager, amplIoInterface); } return runAsync.thenApply(run -> { - network.getVariantManager().setWorkingVariant(variantId); - network.getVariantManager().removeVariant(WITH_DC_LOAD_FLOW_ID_VARIANT_SUFFIX); + if (parameters.getVoltageInitialization() != OpenReacParameters.OpenReacVoltageInitialization.PREVIOUS_VALUES) { + // remove the variant created to store dc load flow results + network.getVariantManager().setWorkingVariant(variantId); + network.getVariantManager().removeVariant(WITH_USER_INITIALIZATION_ID_VARIANT); + } OpenReacResult result = new OpenReacResult(run.isSuccess() && amplIoInterface.checkErrors() ? OpenReacStatus.OK : OpenReacStatus.NOT_OK, amplIoInterface, run.getIndicators()); Reports.createShuntModificationsReporter(reportNode, network.getId(), amplIoInterface.getNetworkModifications().getShuntsWithDeltaDiscreteOptimalOverThreshold()); return result; @@ -170,7 +184,8 @@ private static void checkParameters(Network network, String variantId, OpenReacP parameters.checkIntegrity(network, Reports.createParameterIntegrityReporter(reportNode, network.getId())); } - private static void runDcLf(Network network, OpenReacParameters openReacParameters) { + private static void initializeVoltageBeforeOptimization(Network network, OpenReacParameters openReacParameters) { + // gsk to only distribute on generators network.getGeneratorStream() .forEach(generator -> generator.newExtension(ActivePowerControlAdder.class) .withParticipate(true) @@ -179,32 +194,42 @@ private static void runDcLf(Network network, OpenReacParameters openReacParamete // slack bus selection SlackBusSelector slackBusSelector = new MostMeshedSlackBusSelector(); - // get lfNetwork to apply initialization on it + // get lfNetwork to apply voltage initialization LfNetwork lfNetwork = LfNetwork.load(network, new LfNetworkLoaderImpl(), slackBusSelector).get(0); - // full voltage initializer, to initialize voltage magnitudes and angles + // get initializer depending on user option + VoltageInitializer initializer; MatrixFactory matrixFactory = new SparseMatrixFactory(); - FullVoltageInitializer initializer = new FullVoltageInitializer( - new VoltageMagnitudeInitializer(false, matrixFactory, openReacParameters.getLowImpedanceThreshold()), - new DcValueVoltageInitializer(new LfNetworkParameters().setSlackBusSelector(slackBusSelector), - true, - LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_PARTICIPATION_FACTOR, - true, - DcApproximationType.IGNORE_R, - matrixFactory, - 1)); // FIXME : which number is optimal ? - - // compute initialization + switch (openReacParameters.getVoltageInitialization()) { + // uniform voltage initializer, for flat start voltage angles + case UNIFORM_VALUES -> initializer = new UniformValueVoltageInitializer(); + // direct current initializer, to initialize voltage angles + case DC_VALUES -> initializer = new DcValueVoltageInitializer(new LfNetworkParameters().setSlackBusSelector(slackBusSelector), + true, + LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_PARTICIPATION_FACTOR, + true, + DcApproximationType.IGNORE_R, + matrixFactory, + 1); + // full voltage initializer, to initialize voltage magnitudes and angles + case FULL_VOLTAGE -> initializer = new FullVoltageInitializer( + new VoltageMagnitudeInitializer(false, matrixFactory, openReacParameters.getLowImpedanceThreshold()), + new DcValueVoltageInitializer(new LfNetworkParameters().setSlackBusSelector(slackBusSelector), + true, + LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_PARTICIPATION_FACTOR, + true, + DcApproximationType.IGNORE_R, + matrixFactory, + 1)); + default -> throw new IllegalStateException("Unexpected value: " + openReacParameters.getVoltageInitialization()); + } + + // initialize voltage values initializer.prepare(lfNetwork); - // update the state of the buses and of the generators to warm start AC optimization + // update the network with initialization LfNetworkStateUpdateParameters updateParameters = new LfNetworkStateUpdateParameters(false, false, true, false, false, false, true, false, ReactivePowerDispatchMode.Q_EQUAL_PROPORTION, false, ReferenceBusSelectionMode.FIRST_SLACK, false); lfNetwork.updateState(updateParameters); - // lfNetwork.getBuses().forEach(bus -> bus.updateState(updateParameters)); -// lfNetwork.getBuses().stream() -// .flatMap(lfBus -> lfBus.getGenerators().stream()) -// .filter(lfGenerator -> lfGenerator instanceof LfGeneratorImpl) // only active power of generators is optimized in OpenReac, not one of batteries and vsc -// .forEach(lfGenerator -> lfGenerator.updateState(updateParameters)); } } diff --git a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java index 024fabde..56e71339 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java +++ b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java @@ -127,7 +127,14 @@ public class OpenReacParameters { private double shuntCompensatorActivationAlertThreshold; - private boolean dcLoadFlowBeforeOptimization = true; + private OpenReacVoltageInitialization voltageInitialization = OpenReacVoltageInitialization.PREVIOUS_VALUES; + + public enum OpenReacVoltageInitialization { + PREVIOUS_VALUES, + UNIFORM_VALUES, + DC_VALUES, + FULL_VOLTAGE; + } /** * Override some voltage level limits in the network. This will NOT modify the network object. @@ -550,12 +557,12 @@ public OpenReacParameters setShuntCompensatorActivationAlertThreshold(double shu return this; } - public boolean isDcLoadFlowBeforeOptimization() { - return dcLoadFlowBeforeOptimization; + public OpenReacVoltageInitialization getVoltageInitialization() { + return voltageInitialization; } - public OpenReacParameters setDcLoadFlowBeforeOptimization(boolean dcLoadFlowBeforeOptimization) { - this.dcLoadFlowBeforeOptimization = dcLoadFlowBeforeOptimization; + public OpenReacParameters setVoltageInitialization(OpenReacVoltageInitialization voltageInitialization) { + this.voltageInitialization = Objects.requireNonNull(voltageInitialization); return this; } From 57d1c405798335f711e2bae25946ffbedc3ea8a2 Mon Sep 17 00:00:00 2001 From: p-arvy Date: Mon, 2 Sep 2024 16:29:03 +0200 Subject: [PATCH 08/10] Remove usage of dcLoadFlow boolean Signed-off-by: p-arvy --- .../powsybl/openreac/parameters/input/OpenReacParameters.java | 2 +- .../parameters/input/json/OpenReacParametersDeserializer.java | 4 ---- .../parameters/input/json/OpenReacParametersSerializer.java | 1 - .../parameters/input/json/OpenReacJsonModuleTest.java | 2 -- open-reac/src/test/resources/parametersLists.json | 3 +-- open-reac/src/test/resources/parametersThresholds.json | 3 +-- 6 files changed, 3 insertions(+), 12 deletions(-) diff --git a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java index 56e71339..6896efcd 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java +++ b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/OpenReacParameters.java @@ -127,7 +127,7 @@ public class OpenReacParameters { private double shuntCompensatorActivationAlertThreshold; - private OpenReacVoltageInitialization voltageInitialization = OpenReacVoltageInitialization.PREVIOUS_VALUES; + private OpenReacVoltageInitialization voltageInitialization = OpenReacVoltageInitialization.FULL_VOLTAGE; public enum OpenReacVoltageInitialization { PREVIOUS_VALUES, diff --git a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java index 24c9e069..f49506a4 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java +++ b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java @@ -151,10 +151,6 @@ public OpenReacParameters deserialize(JsonParser parser, DeserializationContext parser.nextToken(); parameters.setShuntVariableScalingFactor(parser.readValueAs(Double.class)); } - case "dcLoadFlowBeforeOptimization" -> { - parser.nextToken(); - parameters.setDcLoadFlowBeforeOptimization(parser.readValueAs(Boolean.class)); - } default -> throw new IllegalStateException("Unexpected field: " + parser.getCurrentName()); } } diff --git a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java index e174177e..3225d5b0 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java +++ b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java @@ -62,7 +62,6 @@ public void serialize(OpenReacParameters openReacParameters, JsonGenerator jsonG serializerProvider.defaultSerializeField("reactiveSlackVariableScalingFactor", openReacParameters.getReactiveSlackVariableScalingFactor(), jsonGenerator); serializerProvider.defaultSerializeField("twoWindingTransformerRatioVariableScalingFactor", openReacParameters.getTwoWindingTransformerRatioVariableScalingFactor(), jsonGenerator); serializerProvider.defaultSerializeField("shuntVariableScalingFactor", openReacParameters.getShuntVariableScalingFactor(), jsonGenerator); - serializerProvider.defaultSerializeField("dcLoadFlowBeforeOptimization", openReacParameters.isDcLoadFlowBeforeOptimization(), jsonGenerator); jsonGenerator.writeEndObject(); } } diff --git a/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java b/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java index 53771666..7f4e1b16 100644 --- a/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java +++ b/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java @@ -96,7 +96,6 @@ void testOpenReacParametersThresholds() throws IOException { parameters.setDefaultConstraintScalingFactor(0.888); parameters.setReactiveSlackVariableScalingFactor(1e-2); parameters.setTwoWindingTransformerRatioVariableScalingFactor(0.005); - parameters.setDcLoadFlowBeforeOptimization(false); String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(parameters); ComparisonUtils.assertTxtEquals(Objects.requireNonNull(getClass().getResourceAsStream("/parametersThresholds.json")), json); @@ -123,6 +122,5 @@ void testOpenReacParametersThresholds() throws IOException { assertEquals(0.888, parameters2.getDefaultConstraintScalingFactor()); assertEquals(1e-2, parameters2.getReactiveSlackVariableScalingFactor()); assertEquals(0.005, parameters2.getTwoWindingTransformerRatioVariableScalingFactor()); - assertEquals(false, parameters2.isDcLoadFlowBeforeOptimization()); } } diff --git a/open-reac/src/test/resources/parametersLists.json b/open-reac/src/test/resources/parametersLists.json index 50e4030c..69d5e7c3 100644 --- a/open-reac/src/test/resources/parametersLists.json +++ b/open-reac/src/test/resources/parametersLists.json @@ -45,6 +45,5 @@ "defaultConstraintScalingFactor" : 1.0, "reactiveSlackVariableScalingFactor" : 0.1, "twoWindingTransformerRatioVariableScalingFactor" : 0.001, - "shuntVariableScalingFactor" : 0.1, - "dcLoadFlowBeforeOptimization" : true + "shuntVariableScalingFactor" : 0.1 } \ No newline at end of file diff --git a/open-reac/src/test/resources/parametersThresholds.json b/open-reac/src/test/resources/parametersThresholds.json index 4ee25537..96df9fa8 100644 --- a/open-reac/src/test/resources/parametersThresholds.json +++ b/open-reac/src/test/resources/parametersThresholds.json @@ -25,6 +25,5 @@ "defaultConstraintScalingFactor" : 0.888, "reactiveSlackVariableScalingFactor" : 0.01, "twoWindingTransformerRatioVariableScalingFactor" : 0.005, - "shuntVariableScalingFactor" : 0.1, - "dcLoadFlowBeforeOptimization" : false + "shuntVariableScalingFactor" : 0.1 } \ No newline at end of file From 1e89c68b0651324e54de7b497b854e7831e6f98c Mon Sep 17 00:00:00 2001 From: p-arvy Date: Mon, 2 Sep 2024 16:52:19 +0200 Subject: [PATCH 09/10] Add serialization and update TUs Signed-off-by: p-arvy --- .../parameters/input/json/OpenReacParametersDeserializer.java | 4 ++++ .../parameters/input/json/OpenReacParametersSerializer.java | 1 + .../test/java/com/powsybl/openreac/OpenReacRunnerTest.java | 1 + .../parameters/input/json/OpenReacJsonModuleTest.java | 2 ++ open-reac/src/test/resources/parametersLists.json | 3 ++- open-reac/src/test/resources/parametersThresholds.json | 3 ++- 6 files changed, 12 insertions(+), 2 deletions(-) diff --git a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java index f49506a4..f930136b 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java +++ b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersDeserializer.java @@ -151,6 +151,10 @@ public OpenReacParameters deserialize(JsonParser parser, DeserializationContext parser.nextToken(); parameters.setShuntVariableScalingFactor(parser.readValueAs(Double.class)); } + case "voltageInitialization" -> { + parser.nextToken(); + parameters.setVoltageInitialization(OpenReacParameters.OpenReacVoltageInitialization.valueOf(parser.getText())); + } default -> throw new IllegalStateException("Unexpected field: " + parser.getCurrentName()); } } diff --git a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java index 3225d5b0..6dfe7127 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java +++ b/open-reac/src/main/java/com/powsybl/openreac/parameters/input/json/OpenReacParametersSerializer.java @@ -62,6 +62,7 @@ public void serialize(OpenReacParameters openReacParameters, JsonGenerator jsonG serializerProvider.defaultSerializeField("reactiveSlackVariableScalingFactor", openReacParameters.getReactiveSlackVariableScalingFactor(), jsonGenerator); serializerProvider.defaultSerializeField("twoWindingTransformerRatioVariableScalingFactor", openReacParameters.getTwoWindingTransformerRatioVariableScalingFactor(), jsonGenerator); serializerProvider.defaultSerializeField("shuntVariableScalingFactor", openReacParameters.getShuntVariableScalingFactor(), jsonGenerator); + serializerProvider.defaultSerializeField("voltageInitialization", openReacParameters.getVoltageInitialization(), jsonGenerator); jsonGenerator.writeEndObject(); } } diff --git a/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java b/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java index 6f676d93..3429c251 100644 --- a/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java +++ b/open-reac/src/test/java/com/powsybl/openreac/OpenReacRunnerTest.java @@ -283,6 +283,7 @@ void testHvdc() throws IOException { setDefaultVoltageLimits(network); // set default voltage limits to every voltage levels of the network network.getVscConverterStation("cs3").getTerminal().setP(0.0); network.getVscConverterStation("cs4").getTerminal().setP(0.0); + network.getHvdcLine("hvdc34").setActivePowerSetpoint(0); OpenReacParameters parameters = new OpenReacParameters(); parameters.addConstantQGenerators(List.of("g1", "g2", "g5", "g6")); testAllModifAndLoadFlow(network, "openreac-output-vsc", parameters, ReportNode.NO_OP); diff --git a/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java b/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java index 7f4e1b16..a7a6a054 100644 --- a/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java +++ b/open-reac/src/test/java/com/powsybl/openreac/parameters/input/json/OpenReacJsonModuleTest.java @@ -96,6 +96,7 @@ void testOpenReacParametersThresholds() throws IOException { parameters.setDefaultConstraintScalingFactor(0.888); parameters.setReactiveSlackVariableScalingFactor(1e-2); parameters.setTwoWindingTransformerRatioVariableScalingFactor(0.005); + parameters.setVoltageInitialization(OpenReacParameters.OpenReacVoltageInitialization.DC_VALUES); String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(parameters); ComparisonUtils.assertTxtEquals(Objects.requireNonNull(getClass().getResourceAsStream("/parametersThresholds.json")), json); @@ -122,5 +123,6 @@ void testOpenReacParametersThresholds() throws IOException { assertEquals(0.888, parameters2.getDefaultConstraintScalingFactor()); assertEquals(1e-2, parameters2.getReactiveSlackVariableScalingFactor()); assertEquals(0.005, parameters2.getTwoWindingTransformerRatioVariableScalingFactor()); + assertEquals(OpenReacParameters.OpenReacVoltageInitialization.DC_VALUES, parameters2.getVoltageInitialization()); } } diff --git a/open-reac/src/test/resources/parametersLists.json b/open-reac/src/test/resources/parametersLists.json index 69d5e7c3..ef04132e 100644 --- a/open-reac/src/test/resources/parametersLists.json +++ b/open-reac/src/test/resources/parametersLists.json @@ -45,5 +45,6 @@ "defaultConstraintScalingFactor" : 1.0, "reactiveSlackVariableScalingFactor" : 0.1, "twoWindingTransformerRatioVariableScalingFactor" : 0.001, - "shuntVariableScalingFactor" : 0.1 + "shuntVariableScalingFactor" : 0.1, + "voltageInitialization" : "FULL_VOLTAGE" } \ No newline at end of file diff --git a/open-reac/src/test/resources/parametersThresholds.json b/open-reac/src/test/resources/parametersThresholds.json index 96df9fa8..f05094ff 100644 --- a/open-reac/src/test/resources/parametersThresholds.json +++ b/open-reac/src/test/resources/parametersThresholds.json @@ -25,5 +25,6 @@ "defaultConstraintScalingFactor" : 0.888, "reactiveSlackVariableScalingFactor" : 0.01, "twoWindingTransformerRatioVariableScalingFactor" : 0.005, - "shuntVariableScalingFactor" : 0.1 + "shuntVariableScalingFactor" : 0.1, + "voltageInitialization" : "DC_VALUES" } \ No newline at end of file From 523c2fd2eba54e71cfdfa7c21af60724e3158553 Mon Sep 17 00:00:00 2001 From: p-arvy Date: Mon, 2 Sep 2024 17:44:52 +0200 Subject: [PATCH 10/10] Add TUs to test voltage initialization Signed-off-by: p-arvy --- .../com/powsybl/openreac/OpenReacRunner.java | 44 +++++++----- .../openreac/OpenReacParametersTest.java | 16 +++++ .../OpenReacVoltageInitializationTest.java | 71 +++++++++++++++++++ 3 files changed, 113 insertions(+), 18 deletions(-) create mode 100644 open-reac/src/test/java/com/powsybl/openreac/OpenReacVoltageInitializationTest.java diff --git a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java index 2d757fb1..907bdd8e 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java +++ b/open-reac/src/main/java/com/powsybl/openreac/OpenReacRunner.java @@ -25,7 +25,6 @@ import com.powsybl.openloadflow.dc.equations.DcApproximationType; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl; -import com.powsybl.openloadflow.network.util.UniformValueVoltageInitializer; import com.powsybl.openloadflow.network.util.VoltageInitializer; import com.powsybl.openreac.parameters.OpenReacAmplIOFiles; import com.powsybl.openreac.parameters.input.OpenReacParameters; @@ -184,7 +183,7 @@ private static void checkParameters(Network network, String variantId, OpenReacP parameters.checkIntegrity(network, Reports.createParameterIntegrityReporter(reportNode, network.getId())); } - private static void initializeVoltageBeforeOptimization(Network network, OpenReacParameters openReacParameters) { + public static void initializeVoltageBeforeOptimization(Network network, OpenReacParameters openReacParameters) { // gsk to only distribute on generators network.getGeneratorStream() .forEach(generator -> generator.newExtension(ActivePowerControlAdder.class) @@ -198,34 +197,43 @@ private static void initializeVoltageBeforeOptimization(Network network, OpenRea LfNetwork lfNetwork = LfNetwork.load(network, new LfNetworkLoaderImpl(), slackBusSelector).get(0); // get initializer depending on user option - VoltageInitializer initializer; MatrixFactory matrixFactory = new SparseMatrixFactory(); switch (openReacParameters.getVoltageInitialization()) { // uniform voltage initializer, for flat start voltage angles - case UNIFORM_VALUES -> initializer = new UniformValueVoltageInitializer(); + case UNIFORM_VALUES -> { + for (LfBus lfBus : lfNetwork.getBuses()) { + lfBus.setV(1); + lfBus.setAngle(0); + } + } // direct current initializer, to initialize voltage angles - case DC_VALUES -> initializer = new DcValueVoltageInitializer(new LfNetworkParameters().setSlackBusSelector(slackBusSelector), - true, + case DC_VALUES -> { + VoltageInitializer initializer = new DcValueVoltageInitializer(new LfNetworkParameters().setSlackBusSelector(slackBusSelector), + true, + LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_PARTICIPATION_FACTOR, + true, + DcApproximationType.IGNORE_R, + matrixFactory, + 1); + initializer.prepare(lfNetwork); + } + // full voltage initializer, to initialize voltage magnitudes and angles + case FULL_VOLTAGE -> { + VoltageInitializer initializer = new FullVoltageInitializer( + new VoltageMagnitudeInitializer(false, matrixFactory, openReacParameters.getLowImpedanceThreshold()), + new DcValueVoltageInitializer(new LfNetworkParameters().setSlackBusSelector(slackBusSelector), + true, LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_PARTICIPATION_FACTOR, true, DcApproximationType.IGNORE_R, matrixFactory, - 1); - // full voltage initializer, to initialize voltage magnitudes and angles - case FULL_VOLTAGE -> initializer = new FullVoltageInitializer( - new VoltageMagnitudeInitializer(false, matrixFactory, openReacParameters.getLowImpedanceThreshold()), - new DcValueVoltageInitializer(new LfNetworkParameters().setSlackBusSelector(slackBusSelector), - true, - LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_PARTICIPATION_FACTOR, - true, - DcApproximationType.IGNORE_R, - matrixFactory, - 1)); + 1)); + initializer.prepare(lfNetwork); + } default -> throw new IllegalStateException("Unexpected value: " + openReacParameters.getVoltageInitialization()); } // initialize voltage values - initializer.prepare(lfNetwork); // update the network with initialization LfNetworkStateUpdateParameters updateParameters = new LfNetworkStateUpdateParameters(false, false, true, false, false, diff --git a/open-reac/src/test/java/com/powsybl/openreac/OpenReacParametersTest.java b/open-reac/src/test/java/com/powsybl/openreac/OpenReacParametersTest.java index dd3e89a1..a922b98c 100644 --- a/open-reac/src/test/java/com/powsybl/openreac/OpenReacParametersTest.java +++ b/open-reac/src/test/java/com/powsybl/openreac/OpenReacParametersTest.java @@ -389,6 +389,21 @@ void testBusesWithReactiveSlackConfigIntegrity() { assertEquals("ALL", parameters.getReactiveSlackBusesMode().toParam().getValue()); } + @Test + void testVoltageInitializationIntegrity() { + OpenReacParameters parameters = new OpenReacParameters(); + + assertThrows(NullPointerException.class, () -> parameters.setVoltageInitialization(null)); + parameters.setVoltageInitialization(OpenReacParameters.OpenReacVoltageInitialization.DC_VALUES); + assertEquals(OpenReacParameters.OpenReacVoltageInitialization.DC_VALUES, parameters.getVoltageInitialization()); + parameters.setVoltageInitialization(OpenReacParameters.OpenReacVoltageInitialization.PREVIOUS_VALUES); + assertEquals(OpenReacParameters.OpenReacVoltageInitialization.PREVIOUS_VALUES, parameters.getVoltageInitialization()); + parameters.setVoltageInitialization(OpenReacParameters.OpenReacVoltageInitialization.UNIFORM_VALUES); + assertEquals(OpenReacParameters.OpenReacVoltageInitialization.UNIFORM_VALUES, parameters.getVoltageInitialization()); + parameters.setVoltageInitialization(OpenReacParameters.OpenReacVoltageInitialization.FULL_VOLTAGE); + assertEquals(OpenReacParameters.OpenReacVoltageInitialization.FULL_VOLTAGE, parameters.getVoltageInitialization()); + } + @Test void testDefaultParametersValuesIntegrity() { OpenReacParameters parameters = new OpenReacParameters(); @@ -413,6 +428,7 @@ void testDefaultParametersValuesIntegrity() { assertEquals(1e-1, parameters.getReactiveSlackVariableScalingFactor()); assertEquals(1e-3, parameters.getTwoWindingTransformerRatioVariableScalingFactor()); assertEquals(1e-1, parameters.getShuntVariableScalingFactor()); + assertEquals(OpenReacParameters.OpenReacVoltageInitialization.FULL_VOLTAGE, parameters.getVoltageInitialization()); assertTrue(parameters.checkAlgorithmParametersIntegrity()); } diff --git a/open-reac/src/test/java/com/powsybl/openreac/OpenReacVoltageInitializationTest.java b/open-reac/src/test/java/com/powsybl/openreac/OpenReacVoltageInitializationTest.java new file mode 100644 index 00000000..d9ac1bb9 --- /dev/null +++ b/open-reac/src/test/java/com/powsybl/openreac/OpenReacVoltageInitializationTest.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * 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/. + */ +package com.powsybl.openreac; + +import com.powsybl.iidm.network.Bus; +import com.powsybl.iidm.network.Network; +import com.powsybl.openreac.network.VoltageControlNetworkFactory; +import com.powsybl.openreac.parameters.input.OpenReacParameters; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class OpenReacVoltageInitializationTest { + + final double deltaVoltage = 1e-3; + OpenReacParameters openReacParameters; + Network network; + Bus b1; + Bus b2; + Bus b3; + + @BeforeEach + void setUp() { + openReacParameters = new OpenReacParameters(); + network = VoltageControlNetworkFactory.createNetworkWithT2wt(); + b1 = network.getBusBreakerView().getBus("BUS_1"); + b2 = network.getBusBreakerView().getBus("BUS_2"); + b3 = network.getBusBreakerView().getBus("BUS_3"); + } + + @Test + void testDcVoltageInitialization() { + openReacParameters.setVoltageInitialization(OpenReacParameters.OpenReacVoltageInitialization.DC_VALUES); + OpenReacRunner.initializeVoltageBeforeOptimization(network, openReacParameters); + assertEquals(Double.NaN, b1.getV()); + assertEquals(0.822, b1.getAngle(), deltaVoltage); + assertEquals(Double.NaN, b2.getV()); + assertEquals(0, b2.getAngle(), deltaVoltage); + assertEquals(Double.NaN, b3.getV()); + assertEquals(-2.923, b3.getAngle(), deltaVoltage); + } + + @Test + void testUniformVoltageInitialization() { + openReacParameters.setVoltageInitialization(OpenReacParameters.OpenReacVoltageInitialization.UNIFORM_VALUES); + OpenReacRunner.initializeVoltageBeforeOptimization(network, openReacParameters); + assertEquals(b1.getVoltageLevel().getNominalV(), b1.getV()); + assertEquals(0, b1.getAngle()); + assertEquals(b2.getVoltageLevel().getNominalV(), b2.getV()); + assertEquals(0, b2.getAngle()); + assertEquals(b3.getVoltageLevel().getNominalV(), b3.getV()); + assertEquals(0, b3.getAngle()); + } + + @Test + void testFullVoltageInitialization() { + openReacParameters.setVoltageInitialization(OpenReacParameters.OpenReacVoltageInitialization.FULL_VOLTAGE); + OpenReacRunner.initializeVoltageBeforeOptimization(network, openReacParameters); + assertEquals(135, b1.getV(), deltaVoltage); + assertEquals(0.822, b1.getAngle(), deltaVoltage); + assertEquals(135, b2.getV(), deltaVoltage); + assertEquals(0, b2.getAngle(), deltaVoltage); + assertEquals(30.375, b3.getV(), deltaVoltage); + assertEquals(-2.923, b3.getAngle(), deltaVoltage); + } +}