diff --git a/open-reac/README.md b/open-reac/README.md index 48136249..0ef90e31 100644 --- a/open-reac/README.md +++ b/open-reac/README.md @@ -57,8 +57,11 @@ each serving a specific function: - `reactiveopf.dat` defines the network data files imported (files with *ampl_* prefix), and the files used to configure the run (files with *param_* prefix). Refer to section [3](#3-input). -- `reactiveopf.mod` defines the sets, parameters and optimization problems (CC, DCOPF, ACOPF) solved in `reactiveopf.run`. - Refer to sections [5](#5-slack-bus--main-connex-component), [6](#6-direct-current-optimal-power-flow) and [7](#7-alternative-current-optimal-power-flow). +- `iidm_importer.mod`, `or_param_importer.mod` and `commons.mod` define the sets and parameters of the optimization. +- `connected_component.mod`, `dcopf.mod` and `acopf.mod` define the optimization problems solved in `reactiveopf.run`. + Refer to sections [5](#5-slack-bus--main-connex-component), [6](#6-direct-current-optimal-power-flow) and [7](#7-alternative-current-optimal-power-flow), + respectively. +- `connected_component.run`, `dcopf.run`, `acopf_preprocessing.run` and `acopf.run` orchestrate the optimization and its post-process. - `reactiveopfoutput.mod` exports result files if the execution of `reactiveopf.run` is successful. Refer to section [8.1](#81-in-case-of-convergence). - `reactiveopfexit.run` contains the code executed when the process fails. diff --git a/open-reac/src/main/java/com/powsybl/openreac/OpenReacModel.java b/open-reac/src/main/java/com/powsybl/openreac/OpenReacModel.java index 4f4f8ec9..1b2338f4 100644 --- a/open-reac/src/main/java/com/powsybl/openreac/OpenReacModel.java +++ b/open-reac/src/main/java/com/powsybl/openreac/OpenReacModel.java @@ -52,7 +52,11 @@ public Charset getFileEncoding() { public static OpenReacModel buildModel() { return new OpenReacModel(OUTPUT_FILE_PREFIX, "openreac", List.of("reactiveopf.run"), - List.of("reactiveopf.mod", "reactiveopf.dat", "reactiveopfoutput.run", "reactiveopfexit.run")); + List.of("commons.mod", "iidm_importer.mod", "or_param_importer.mod", "reactiveopf.dat", // code to import the data + "connected_component.mod", "connected_component.run", // slack bus and main synchronous component computation + "dcopf.mod", "dcopf.run", // dcopf to warm start the acopf + "acopf_preprocessing.run", "acopf.mod", "acopf.run", // reactive acopf + "reactiveopfexit.run", "reactiveopfoutput.run")); // code to export optimization results } private static final String NETWORK_DATA_PREFIX = "ampl"; diff --git a/open-reac/src/main/resources/openreac/acopf.mod b/open-reac/src/main/resources/openreac/acopf.mod new file mode 100644 index 00000000..85bfb991 --- /dev/null +++ b/open-reac/src/main/resources/openreac/acopf.mod @@ -0,0 +1,251 @@ +############################################################################### +# +# 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 +############################################################################### + + +set PROBLEM_ACOPF default { }; + +############################################################################### +# +# Variables and contraints for ACOPF +# +############################################################################### +# Notice that some variables and constraints for DCOPF are also used for ACOPF + +# +# Phase and modulus of voltage +# +# Complex voltage = V*exp(i*teta). (with i**2=-1) + +# Phase of voltage +var teta{BUSCC} <= teta_max, >= teta_min; +subject to ctr_null_phase_bus{PROBLEM_ACOPF}: teta[null_phase_bus] = 0; + +# Modulus of voltage +var V{n in BUSCC} + <= + if substation_Vnomi[1,bus_substation[1,n]] <= ignore_voltage_bounds then max_plausible_high_voltage_limit else + voltage_upper_bound[1,bus_substation[1,n]], + >= + if substation_Vnomi[1,bus_substation[1,n]] <= ignore_voltage_bounds then min_plausible_low_voltage_limit else + voltage_lower_bound[1,bus_substation[1,n]]; + + +# +# Generation +# +# General idea: generation is an input data, but as voltage may vary, generation may vary a little. +# Variations of generation is totally controlled by unique scalar variable alpha +# Before and after optimization, there is no waranty that P is within +# its "bounds" [corrected_unit_Pmin;corrected_unit_Pmax] +# + +# Active generation +var alpha <=1, >=-1; # If alpha==1 then all units are at Pmax +var P_bounded{(g,n) in UNITON} <= max(unit_Pc[1,g,n],corrected_unit_Pmax[g,n]), >= min(unit_Pc[1,g,n],corrected_unit_Pmin[g,n]); +# If coeff_alpha == 1 then all P are defined by the single variable alpha +# If coeff_alpha == 0 then all P are free within their respective bounds +# todo faire des tests avec les valeurs de coeff_alpha +var P{(g,n) in UNITON} = + if ( unit_Pc[1,g,n] < (corrected_unit_Pmax[g,n] - Pnull) and unit_Pc[1,g,n] > Pnull ) + then ( coeff_alpha * ( unit_Pc[1,g,n] + alpha*(corrected_unit_Pmax[g,n]- unit_Pc[1,g,n]) ) + + (1-coeff_alpha) * P_bounded[g,n] ) + else unit_Pc[1,g,n] ; + + +# +# Reactive generation +# +# todo: add trapeze or hexagone constraints for reactive power +var Q{(g,n) in UNITON} <= corrected_unit_Qmax[g,n], >= corrected_unit_Qmin[g,n]; + + +# +# Variable shunts +# +var shunt_var{(shunt,n) in SHUNT_VAR} + >= min{(1,shunt,k) in SHUNT} shunt_valmin[1,shunt,k], + <= max{(1,shunt,k) in SHUNT} shunt_valmax[1,shunt,k]; + + +# +# SVC reactive generation +# +var svc_qvar{(svc,n) in SVCON} >= svc_bmin[1,svc,n], <= svc_bmax[1,svc,n]; + + +# +# VSCCONV reactive generation +# +var vscconv_qvar{(v,n) in VSCCONVON} + >= min(vscconv_qP[1,v,n],vscconv_qp0[1,v,n],vscconv_qp[1,v,n]), + <= max(vscconv_QP[1,v,n],vscconv_Qp0[1,v,n],vscconv_Qp[1,v,n]); +# todo: add trapeze or hexagone constraints for reactive power + + +# +# Ratios of transformers +# +var branch_Ror_var{(qq,m,n) in BRANCHCC_REGL_VAR} + >= regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]], + <= regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]]; + +# +# Flows +# + +var Red_Tran_Act_Dir{(qq,m,n) in BRANCHCC } = + V[n] * branch_admi[qq,m,n] * sin(teta[m]-teta[n]+branch_dephor[qq,m,n]-branch_angper[qq,m,n]) + * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n]) + + V[m] * (branch_admi[qq,m,n]*sin(branch_angper[qq,m,n])+branch_Gor[1,qq,m,n]) + * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n])**2 + ; + +var Red_Tran_Rea_Dir{(qq,m,n) in BRANCHCC } = + - V[n] * branch_admi[qq,m,n] * cos(teta[m]-teta[n]+branch_dephor[qq,m,n]-branch_angper[qq,m,n]) + * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n]) + + V[m] * (branch_admi[qq,m,n]*cos(branch_angper[qq,m,n])-branch_Bor[1,qq,m,n]) + * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n])^2 + ; + +var Red_Tran_Act_Inv{(qq,m,n) in BRANCHCC } = + V[m] * branch_admi[qq,m,n] * sin(teta[n]-teta[m]-branch_dephor[qq,m,n]-branch_angper[qq,m,n]) + * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n]) + + V[n] * (branch_admi[qq,m,n]*sin(branch_angper[qq,m,n])+branch_Gex[1,qq,m,n]) + ; + +var Red_Tran_Rea_Inv{(qq,m,n) in BRANCHCC } = + - V[m] * branch_admi[qq,m,n] * cos(teta[n]-teta[m]-branch_dephor[qq,m,n]-branch_angper[qq,m,n]) + * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n]) + + V[n] * (branch_admi[qq,m,n]*cos(branch_angper[qq,m,n])-branch_Bex[1,qq,m,n]) + ; + + +# +# Active Balance +# + +subject to ctr_balance_P{PROBLEM_ACOPF,k in BUSCC}: + # Flows + sum{(qq,k,n) in BRANCHCC} base100MVA * V[k] * Red_Tran_Act_Dir[qq,k,n] + + sum{(qq,m,k) in BRANCHCC} base100MVA * V[k] * Red_Tran_Act_Inv[qq,m,k] + # Generating units + - sum{(g,k) in UNITON} P[g,k] + # Batteries + - sum{(b,k) in BATTERYCC} battery_p0[1,b,k] + # Loads + + sum{(c,k) in LOADCC} load_PFix[1,c,k] # Fixed value + # VSC converters + + sum{(v,k) in VSCCONVON} vscconv_P0[1,v,k] # Fixed value + # LCC converters + + sum{(l,k) in LCCCONVON} lccconv_P0[1,l,k] # Fixed value + = 0; # No slack variables for active power. If data are really too bad, may not converge. + + +# +# Reactive Balance +# + +# Reactive balance slack variables at configured nodes +set BUSCC_SLACK := if buses_with_reactive_slacks == "ALL" then BUSCC + else if buses_with_reactive_slacks == "NO_GENERATION" then {n in BUSCC: (card{(g,n) in UNITON: (g,n) not in UNIT_FIXQ}==0 and card{(svc,n) in SVCON}==0 and card{(vscconv,n) in VSCCONVON}==0)} + else BUSCC inter PARAM_BUSES_WITH_REACTIVE_SLACK; # if = "CONFIGURED", buses given as parameter but in connex component +var slack1_shunt_B{BUSCC_SLACK} >= 0; +var slack2_shunt_B{BUSCC_SLACK} >= 0; +#subject to ctr_compl_slack_Q{PROBLEM_ACOPF,k in BUSCC_SLACK}: slack1_balance_Q[k] >= 0 complements slack2_balance_Q[k] >= 0; + +subject to ctr_balance_Q{PROBLEM_ACOPF,k in BUSCC}: + # Flows + sum{(qq,k,n) in BRANCHCC} base100MVA * V[k] * Red_Tran_Rea_Dir[qq,k,n] + + sum{(qq,m,k) in BRANCHCC} base100MVA * V[k] * Red_Tran_Rea_Inv[qq,m,k] + # Generating units + - sum{(g,k) in UNITON: (g,k) not in UNIT_FIXQ } Q[g,k] + - sum{(g,k) in UNIT_FIXQ} unit_Qc[1,g,k] + # Batteries + - sum{(b,k) in BATTERYCC} battery_q0[1,b,k] + # Loads + + sum{(c,k) in LOADCC} load_QFix[1,c,k] + # Shunts + - sum{(shunt,k) in SHUNT_FIX} base100MVA * shunt_valnom[1,shunt,k] * V[k]^2 + - sum{(shunt,k) in SHUNT_VAR} base100MVA * shunt_var[shunt,k] * V[k]^2 + # SVC + - sum{(svc,k) in SVCON} base100MVA * svc_qvar[svc,k] * V[k]^2 + # VSC converters + - sum{(v,k) in VSCCONVON} vscconv_qvar[v,k] + # LCC converters + + sum{(l,k) in LCCCONVON} lccconv_Q0[1,l,k] # Fixed value + # Slack variables + + if k in BUSCC_SLACK then + (- base100MVA * V[k]^2 * slack1_shunt_B[k] # Homogeneous to a generation of reactive power (condensator) + + base100MVA * V[k]^2 * slack2_shunt_B[k]) # homogeneous to a reactive load (self) + = 0; + + +# +# Definitions for objective function +# + +# Voltage target : ratio between Vmin and Vmax +var target_voltage_ratio = sum{n in BUSCC: substation_Vnomi[1,bus_substation[1,n]] > ignore_voltage_bounds} + ( V[n] - (1-ratio_voltage_target)*voltage_lower_bound[1,bus_substation[1,n]] + ratio_voltage_target*voltage_upper_bound[1,bus_substation[1,n]] )**2; + +# Voltage target : value V0 in input data +var target_voltage_data = sum{n in BUSVV} (V[n] - bus_V0[1,n])**2; + + +# +# Objective function and penalties +# +param penalty_invest_rea_pos := 10; +param penalty_invest_rea_neg := 10; +param penalty_units_reactive := 0.1; +param penalty_transfo_ratio := 0.1; + +param penalty_active_power_high := 1; +param penalty_active_power_low := 0.01; + +param penalty_voltage_target_high := 1; +param penalty_voltage_target_low := 0.01; + +minimize problem_acopf_objective: + sum{n in BUSCC_SLACK} ( + penalty_invest_rea_pos * base100MVA * slack1_shunt_B[n] + + penalty_invest_rea_neg * base100MVA * slack2_shunt_B[n] + ) + + # coeff_alpha == 1 : minimize sum of generation, all generating units vary with 1 unique variable alpha + # coeff_alpha == 0 : minimize sum of squared difference between target and value + + (if objective_choice==1 or objective_choice==2 then penalty_active_power_low else penalty_active_power_high) + * sum{(g,n) in UNITON} (coeff_alpha * P[g,n] + (1-coeff_alpha)*( (P[g,n]-unit_Pc[1,g,n])/max(1,abs(unit_Pc[1,g,n])) )**2 ) + + # Voltage for busses, ratio between Vmin and Vmax + + (if objective_choice==1 then penalty_voltage_target_high else penalty_voltage_target_low) + * target_voltage_ratio + + # Voltage target : value V0 in input data + + (if objective_choice==2 then penalty_voltage_target_high else penalty_voltage_target_low) + * target_voltage_data + + # Reactive power of units + + penalty_units_reactive * sum{(g,n) in UNITON} (Q[g,n]/max(1,abs(corrected_unit_Qmin[g,n]),abs(corrected_unit_Qmax[g,n])))**2 + + # Ratio of transformers + + penalty_transfo_ratio * sum{(qq,m,n) in BRANCHCC_REGL_VAR} (branch_Ror[qq,m,n]-branch_Ror_var[qq,m,n])**2 + ; + + +# +param solve_result_num_limit := 200; +param output_results binary default 0; \ No newline at end of file diff --git a/open-reac/src/main/resources/openreac/acopf.run b/open-reac/src/main/resources/openreac/acopf.run new file mode 100644 index 00000000..67a329d6 --- /dev/null +++ b/open-reac/src/main/resources/openreac/acopf.run @@ -0,0 +1,167 @@ +############################################################################### +# +# 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 +############################################################################### + + +############################################################################### +# Initial values of the solving +############################################################################### + +# DC values used as initialization for phases +let {n in BUSCC} teta[n] := teta_dc[n]; + +# Voltages +let {n in BUSVV} V[n] := bus_V0[1,n]; +let {n in BUSCC diff BUSVV} V[n] := voltage_lower_bound[1,bus_substation[1,n]] + + 0.8 *(voltage_upper_bound[1,bus_substation[1,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} 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; +let {(v,n) in VSCCONVON} vscconv_qvar[v,n] := if abs(vscconv_targetQ[1,v,n]) < PQmax then vscconv_targetQ[1,v,n] else 0; +let {(qq,m,n) in BRANCHCC_REGL_VAR} branch_Ror_var[qq,m,n] := branch_Ror[qq,m,n]; + + +############################################################################### +# Solve +############################################################################### + +let PROBLEM_ACOPF := {1}; +let tempstr := ctime(); +printf{LOG_KNITRO} "\n######################################################################\n"; +printf{LOG_KNITRO} "** ACopf solve: start (%s)\n\n",ctime(); + +option knitro_options ("opttol=1 opttolabs=1e-1 feastol=1 feastolabs=1e-3 maxit=300 outlev=3"); + +let {i in 1.._nvars} _var[i].xscalefactor := default_variable_scaling_factor; +let {i in 1.._ncons} _con[i].cscalefactor := default_constraint_scaling_factor; + +let {n in BUSCC_SLACK} slack1_shunt_B[n].xscalefactor := reactive_slack_variable_scaling_factor; +let {n in BUSCC_SLACK} slack2_shunt_B[n].xscalefactor := reactive_slack_variable_scaling_factor; + +let {(qq,m,n) in BRANCHCC_REGL_VAR} branch_Ror_var[qq,m,n].xscalefactor := transformer_ratio_variable_scaling_factor; + +let {(shunt,n) in SHUNT_VAR} shunt_var[shunt,n].xscalefactor := shunt_variable_scaling_factor; + +# solve acopf and avoid knitro printing if user asks +if (log_level_knitro <= 1) then { + solve problem_acopf_objective > (nullDevice); +} else { + solve problem_acopf_objective; +} + + +let nb_iter_last := problem_acopf_objective.numiters; +let nb_iter_total := nb_iter_total + nb_iter_last; + +printf{LOG_KNITRO} "\n** ACopf solve: end (%s -> %s)\n",tempstr,ctime(); +printf{LOG_KNITRO} "######################################################################\n\n"; + +param slack1_balance_Q{n in BUSCC_SLACK}; +param slack2_balance_Q{n in BUSCC_SLACK}; +for {n in BUSCC_SLACK} { + let slack1_balance_Q[n] := base100MVA * V[n]^2 * slack1_shunt_B[n].val; + let slack2_balance_Q[n] := base100MVA * V[n]^2 * slack2_shunt_B[n].val; +} + +############################################################################### +# Analysis of solve_result_num +############################################################################### + +# <= 103 : feasible +# 200 convergence to unfeasible +# > 200 : failure +if solve_result_num == 200 +then { + let output_results := 0; + let messageInfo := "Acopf optimization was ***not*** successfull - Convergence to an infeasible solution"; + printf{LOG_ERROR} "%s\n", messageInfo; + let messagesInfo := messagesInfo union {messageInfo}; + let final_status := "NOK"; +} +else if solve_result_num > 103 +then { + let output_results := 0; + let messageInfo := "Acopf optimization was ***not*** successfull - no solution found"; + printf{LOG_ERROR} "%s\n", messageInfo; + let messagesInfo := messagesInfo union {messageInfo}; + let final_status := "NOK"; +} +else { + let output_results := 1; + let final_status := "OK"; +} + + +############################################################################### +# Displays after solving +############################################################################### + +printf{LOG_INFO} "\n######################################################################\n"; +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])), + min({n in BUSCC}V[n]),max({n in BUSCC}V[n]) + ; + +let temp1 := max({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])); +let temp2 := min({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])); + +for {(qq,m,n) in BRANCHCC: (teta[m]-teta[n])>temp1*0.99 or (teta[m]-teta[n]) Pnull +then { + + if 1 in LOG_INFO then + display + sum{n in BUSCC_SLACK} slack1_balance_Q[n], + sum{n in BUSCC_SLACK} slack2_balance_Q[n], + max{n in BUSCC_SLACK} slack1_balance_Q[n], + max{n in BUSCC_SLACK} slack2_balance_Q[n], + card({n in BUSCC_SLACK: slack2_balance_Q[n]+slack1_balance_Q[n]>Pnull}); + + if output_results > 0 then + if card({n in BUSCC_SLACK: slack1_balance_Q[n]+slack2_balance_Q[n] > Pnull}) > 0 then printf{LOG_WARNING} "WARNING buses with non zero reactive slack :\n"; + for {n in BUSCC_SLACK: slack1_balance_Q[n]+slack2_balance_Q[n] > Pnull} + printf{LOG_WARNING} "Bus %Q in substation %Q (%ikV) has non zero reactive slacks %.1f %.1f, Vmin=%.3f Vopt=%.3f Vmax=%.3f \n", + bus_id[1,n],substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], + slack1_balance_Q[n],slack2_balance_Q[n], + voltage_lower_bound[1,bus_substation[1,n]],V[n],voltage_upper_bound[1,bus_substation[1,n]]; +} + +let PROBLEM_ACOPF := { }; diff --git a/open-reac/src/main/resources/openreac/acopf_preprocessing.run b/open-reac/src/main/resources/openreac/acopf_preprocessing.run new file mode 100644 index 00000000..59fd08fd --- /dev/null +++ b/open-reac/src/main/resources/openreac/acopf_preprocessing.run @@ -0,0 +1,255 @@ +############################################################################### +# +# 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 +############################################################################### + + +############################################################################### +# Voltage bounds that will really been ussed +############################################################################### + +# Voltage bounds +let temp1 := min{(t,s) in SUBSTATIONS: substation_Vmin[t,s] > 0} substation_Vmin[t,s]; +for {(t,s) in SUBSTATIONS: substation_Vmin[t,s] > 0 and substation_Vmin[t,s] <= temp1*1.01} + printf{LOG_INFO} "Substations %Q with lowest voltage lower bound Vnom=%ikV Vmin=%.3fpu\n",substation_id[t,s],substation_Vnomi[t,s],substation_Vmin[t,s]; +let temp1 := max{(t,s) in SUBSTATIONS: substation_Vmax[t,s] > 0} substation_Vmax[t,s]; +for {(t,s) in SUBSTATIONS: substation_Vmax[t,s] > 0 and substation_Vmax[t,s] >= temp1*0.99} + printf{LOG_INFO} "Substations %Q with highest voltage upper bound Vnom=%ikV Vmax=%.3fpu\n",substation_id[t,s],substation_Vnomi[t,s],substation_Vmax[t,s]; +printf{LOG_INFO} "If voltage lower bounds are missing or too small, they are set to %.3fpu\n",minimal_voltage_lower_bound; +printf{LOG_INFO} "If voltage upper bounds are missing or too high, they are set to %.3fpu\n",maximal_voltage_upper_bound; +let temp1 := card({n in BUSCC: substation_Vnomi[1,bus_substation[1,n]] <= ignore_voltage_bounds}); +if temp1 > 0 then +printf{LOG_WARNING} "Voltage bounds for substations with nominal voltage <= %ikV are set to [%.3fpu;%.3fpu] (%i busses)\n", + ignore_voltage_bounds,minimal_voltage_lower_bound,maximal_voltage_upper_bound,temp1; +printf{LOG_INFO} "Maximal diameter of voltage interval: %.3f\n",max({(t,s) in SUBSTATIONS}(voltage_upper_bound[t,s] - voltage_lower_bound[t,s])); +printf{LOG_INFO} "Minimal diameter of voltage interval: %.3f\n",min({(t,s) in SUBSTATIONS}(voltage_upper_bound[t,s] - voltage_lower_bound[t,s])); + + +############################################################################### +# Consistency of transformers ratios +############################################################################### + +let temp1 := min{(t,r) in REGL} regl_ratio_min[1,r]; +let temp2 := max{(t,r) in REGL} regl_ratio_max[1,r]; +printf{LOG_INFO} "Minimal transformer ratio : %.3f\n",temp1; +printf{LOG_INFO} "Maximal transformer ratio : %.3f\n",temp2; +for {(qq,m,n) in BRANCHCC_REGL: qq in PARAM_TRANSFORMERS_RATIO_VARIABLE + and not regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]] < regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]]} +{ + let messageInfo := sprintf ( + "Transformer %Q %Q(%ikV)->%Q(%ikV) cstratio=%.3f ratio_min=%.3f ratio_max=%.3f should have variable ratio but min and max are equal", + branch_id[1,qq,m,n], + substation_id[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,m]], + substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], + branch_cstratio[1,qq,m,n], + regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]],regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]]); + printf{LOG_WARNING} "%s\n",messageInfo; + let messagesInfo := messagesInfo union {messageInfo}; +} +for {(qq,m,n) in BRANCHCC_REGL: regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]] <= temp1 * 1.01 + or regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]] >= temp2 * 0.99 } +{ + printf{LOG_INFO} "Transformer %Q ratio_min=%.3f ratio_max=%.3f\n", + branch_id[1,qq,m,n], + regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]], + regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]] +} +# Looking for unconsistencies +let tempo := 0; # If non zero, major inconsistency detected +for {(qq,m,n) in BRANCHCC_REGL: substation_Vnomi[1,bus_substation[1,m]] > 30 and substation_Vnomi[1,bus_substation[1,n]] > 30 and 1=0} { + let temp1 := regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]]; + let temp2 := regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]]; + if voltage_lower_bound[1,bus_substation[1,m]]*temp1*branch_cstratio[1,qq,m,n] > voltage_upper_bound[1,bus_substation[1,n]] + then { + if substation_Vnomi[1,bus_substation[1,m]] > ignore_voltage_bounds + and substation_Vnomi[1,bus_substation[1,n]] > ignore_voltage_bounds + then let tempo := 1; + let messageInfo := sprintf ( + "ERROR INFEASIBLE transformer %Q %Q(%ikV)->%Q(%ikV) cstratio=%.3f ratio_min=%.3f ratio_max=%.3f : Vmin1=%.3f * ratio_min > Vmax2=%.3f", + branch_id[1,qq,m,n], + substation_id[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,m]], + substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], + branch_cstratio[1,qq,m,n],temp1,temp2, + voltage_lower_bound[1,bus_substation[1,m]], + voltage_upper_bound[1,bus_substation[1,n]]); + printf{LOG_ERROR} "%s\n",messageInfo; + let messagesInfo := messagesInfo union {messageInfo}; + } + if voltage_upper_bound[1,bus_substation[1,m]]*temp2*branch_cstratio[1,qq,m,n] < voltage_lower_bound[1,bus_substation[1,n]] + then { + if substation_Vnomi[1,bus_substation[1,m]] > ignore_voltage_bounds + and substation_Vnomi[1,bus_substation[1,n]] > ignore_voltage_bounds + then let tempo := 1; + let messageInfo := sprintf ( + "ERROR INFEASIBLE transformer %Q %Q(%ikV)->%Q(%ikV) cstratio=%.3f ratio_min=%.3f ratio_max=%.3f : Vmax1=%.3f * ratio_max < Vmin2=%.3f", + branch_id[1,qq,m,n], + substation_id[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,m]], + substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], + branch_cstratio[1,qq,m,n],temp1,temp2, + voltage_upper_bound[1,bus_substation[1,m]], + voltage_lower_bound[1,bus_substation[1,n]]); + printf{LOG_ERROR} "%s\n",messageInfo; + let messagesInfo := messagesInfo union {messageInfo}; + } +} +# Consistency for transformers with fixed ratio +for {(qq,m,n) in BRANCHCC_REGL_FIX: substation_Vnomi[1,bus_substation[1,m]] > 30 and substation_Vnomi[1,bus_substation[1,n]] > 30 and 1=0} { + let temp1 := tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],regl_tap0[1,branch_ptrRegl[1,qq,m,n]]]; + if voltage_lower_bound[1,bus_substation[1,m]]*temp1*branch_cstratio[1,qq,m,n] > voltage_upper_bound[1,bus_substation[1,n]] + then { + if substation_Vnomi[1,bus_substation[1,m]] > ignore_voltage_bounds + and substation_Vnomi[1,bus_substation[1,n]] > ignore_voltage_bounds + then let tempo := 1; + let messageInfo := sprintf ( + "ERROR INFEASIBLE transformer %Q %Q(%ikV)->%Q(%ikV) cstratio=%.3f fixed_ratio=%.3f : Vmin1=%.3f * ratio > Vmax2=%.3f", + branch_id[1,qq,m,n], + substation_id[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,m]], + substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], + branch_cstratio[1,qq,m,n],temp1, + voltage_lower_bound[1,bus_substation[1,m]], + voltage_upper_bound[1,bus_substation[1,n]]); + printf{LOG_ERROR} "%s\n",messageInfo; + let messagesInfo := messagesInfo union {messageInfo}; + } + if voltage_upper_bound[1,bus_substation[1,m]]*temp1*branch_cstratio[1,qq,m,n] < voltage_lower_bound[1,bus_substation[1,n]] + then { + if substation_Vnomi[1,bus_substation[1,m]] > ignore_voltage_bounds + and substation_Vnomi[1,bus_substation[1,n]] > ignore_voltage_bounds + then let tempo := 1; + let messageInfo := sprintf ( + "ERROR INFEASIBLE transformer %Q %Q(%ikV)->%Q(%ikV) cstratio=%.3f fixed_ratio=%.3f : Vmax1=%.3f * ratio < Vmin2=%.3f", + branch_id[1,qq,m,n], + substation_id[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,m]], + substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], + branch_cstratio[1,qq,m,n],temp1, + voltage_upper_bound[1,bus_substation[1,m]], + voltage_lower_bound[1,bus_substation[1,n]]); + printf{LOG_ERROR} "%s\n",messageInfo; + let messagesInfo := messagesInfo union {messageInfo}; + } +} +if tempo > 0.5 then { + let errorMessage := "ERROR INFEASIBLE some voltages bounds and not feasible with transformers ratios"; + let final_status := "NOK"; + include reactiveopfexit.run; +} + + + +############################################################################### +# Correction of units' P and Q domains +############################################################################### + +printf{LOG_WARNING} "\nWARNING Correction of P/Q units domains:\n"; +for {(g,n) in UNITON} { + + if abs(unit_Pmax[1,g,n]) >= PQmax then { + let corrected_unit_Pmax[g,n] := max(defaultPmax,unit_Pc[1,g,n]); + printf{LOG_WARNING} "%Q for %Q is %Q -> corrected to %Q\n","unit_Pmax",unit_id[1,g,n],unit_Pmax[1,g,n],corrected_unit_Pmax[g,n]; + } + else let corrected_unit_Pmax[g,n] := unit_Pmax[1,g,n]; + + if abs(unit_Pmin[1,g,n]) >= PQmax then { + let corrected_unit_Pmin[g,n] := min(defaultPmin,unit_Pc[1,g,n]); + printf{LOG_WARNING} "%Q for %Q is %Q -> corrected to %Q\n","unit_Pmin",unit_id[1,g,n],unit_Pmin[1,g,n],corrected_unit_Pmin[g,n]; + } + else let corrected_unit_Pmin[g,n] := unit_Pmin[1,g,n]; + + if abs(corrected_unit_Pmax[g,n]-corrected_unit_Pmin[g,n]) <= minimalQPrange then { + if abs(unit_Pc[1,g,n]) > 1 then + printf{LOG_WARNING} "Unit %Q has Pmin=%.1f and Pmax=%.1f too close -> we set Pmin=Pmax=Pc=%Q\n", + unit_id[1,g,n],corrected_unit_Pmin[g,n],corrected_unit_Pmax[g,n],unit_Pc[1,g,n]; + let corrected_unit_Pmin[g,n] := unit_Pc[1,g,n]; + let corrected_unit_Pmax[g,n] := unit_Pc[1,g,n]; + } + + if abs(unit_qp[1,g,n]) >= PQmax then { + let corrected_unit_qp[g,n] := -defaultQmaxPmaxRatio * corrected_unit_Pmax[g,n]; + printf{LOG_DEBUG} "%Q for %Q is %Q -> corrected to %Q\n","unit_qp",unit_id[1,g,n],unit_qp[1,g,n],corrected_unit_qp[g,n]; + } + else let corrected_unit_qp[g,n] := unit_qp[1,g,n]; + + if abs(unit_qP[1,g,n]) >= PQmax then { + let corrected_unit_qP[g,n] := -defaultQmaxPmaxRatio * corrected_unit_Pmax[g,n]; + printf{LOG_DEBUG} "%Q for %Q is %Q -> corrected to %Q\n","unit_qP",unit_id[1,g,n],unit_qP[1,g,n],corrected_unit_qP[g,n]; + } + else let corrected_unit_qP[g,n] := unit_qP[1,g,n]; + + if abs(unit_Qp[1,g,n]) >= PQmax then { + let corrected_unit_Qp[g,n] := defaultQmaxPmaxRatio * corrected_unit_Pmax[g,n]; + printf{LOG_DEBUG} "%Q for %Q is %Q -> corrected to %Q\n","unit_Qp",unit_id[1,g,n],unit_Qp[1,g,n],corrected_unit_Qp[g,n]; + } + else let corrected_unit_Qp[g,n] := unit_Qp[1,g,n]; + + if abs(unit_QP[1,g,n]) >= PQmax then { + let corrected_unit_QP[g,n] := defaultQmaxPmaxRatio * corrected_unit_Pmax[g,n]; + printf{LOG_DEBUG} "%Q for %Q is %Q -> corrected to %Q\n","unit_QP",unit_id[1,g,n],unit_QP[1,g,n],corrected_unit_QP[g,n]; + } + else let corrected_unit_QP[g,n] := unit_QP[1,g,n]; + + if corrected_unit_qp[g,n] > corrected_unit_Qp[g,n] then { + printf{LOG_WARNING} "Warning unit %Q : unit_qp > unit_Qp -> we invert them",unit_id[1,g,n]; + let tempo := corrected_unit_qp[g,n]; + let corrected_unit_qp[g,n] := corrected_unit_Qp[g,n]; + let corrected_unit_Qp[g,n] := tempo; + } + + if corrected_unit_qP[g,n] > corrected_unit_QP[g,n] then { + printf{LOG_WARNING} "Warning unit %Q : unit_qP > unit_QP -> we invert them",unit_id[1,g,n]; + let tempo := corrected_unit_qP[g,n]; + let corrected_unit_qP[g,n] := corrected_unit_QP[g,n]; + let corrected_unit_QP[g,n] := tempo; + } + + if abs(corrected_unit_qP[g,n]-corrected_unit_QP[g,n]) <= minimalQPrange + and abs(corrected_unit_qp[g,n]-corrected_unit_Qp[g,n]) <= minimalQPrange + and abs(corrected_unit_QP[g,n]-corrected_unit_qp[g,n]) <= minimalQPrange + then { + let tempo := 0.25*(corrected_unit_qP[g,n]+corrected_unit_QP[g,n]+corrected_unit_qp[g,n]+corrected_unit_Qp[g,n]); + printf{LOG_DEBUG} "Unit %Q has reactive diagram too small -> we set qp=qP=Qp=QP=%Q (Pc=%Q)\n", + unit_id[1,g,n],tempo,unit_Pc[1,g,n]; + let corrected_unit_qP[g,n] := tempo; + let corrected_unit_QP[g,n] := tempo; + let corrected_unit_qp[g,n] := tempo; + let corrected_unit_Qp[g,n] := tempo; + } + + let corrected_unit_Qmin[g,n] := min(corrected_unit_qP[g,n],corrected_unit_qp[g,n]); + let corrected_unit_Qmax[g,n] := min(corrected_unit_QP[g,n],corrected_unit_Qp[g,n]); + + if unit_Pc[1,g,n] > corrected_unit_Pmax[g,n] or unit_Pc[1,g,n] < corrected_unit_Pmin[g,n] + then printf{LOG_WARNING} "Warning unit %Q Pc=%Q not in bounds [ Pmin=%Q ; Pmax=%Q ]\n", + unit_id[1,g,n],unit_Pc[1,g,n],corrected_unit_Pmin[g,n],corrected_unit_Pmax[g,n]; + + if abs(corrected_unit_Qmin[g,n] - corrected_unit_Qmax[g,n]) >= minimalQPrange + and ( corrected_unit_Qmin[g,n] > 0 or corrected_unit_Qmax[g,n] < 0 ) + then printf{LOG_WARNING} "Warning unit %Q: 0 not in bounds [ Qmin=%Q ; Qmax=%Q ]\n", + unit_id[1,g,n],corrected_unit_Qmin[g,n],corrected_unit_Qmax[g,n]; +} + +printf{LOG_INFO} "\nFew information on P/Q units domains:\n"; +printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_Pmin[1,g,n]),"unit_Pmin",max({(g,n) in UNITON} unit_Pmin[1,g,n]); +printf{LOG_INFO} "Active generation: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_Pc[1,g,n]), "unit_Pc", max({(g,n) in UNITON} unit_Pc[1,g,n]); +printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_Pmax[1,g,n]),"unit_Pmax",max({(g,n) in UNITON} unit_Pmax[1,g,n]); +printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_qP[1,g,n]), "unit_qP", max({(g,n) in UNITON} unit_qP[1,g,n]); +printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_qp[1,g,n]), "unit_qp", max({(g,n) in UNITON} unit_qp[1,g,n]); +printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_QP[1,g,n]), "unit_QP", max({(g,n) in UNITON} unit_QP[1,g,n]); +printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_Qp[1,g,n]), "unit_Qp", max({(g,n) in UNITON} unit_Qp[1,g,n]); + +printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_Pmin[g,n]),"corrected_unit_Pmin",max({(g,n) in UNITON} corrected_unit_Pmin[g,n]); +printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_Pmax[g,n]),"corrected_unit_Pmax",max({(g,n) in UNITON} corrected_unit_Pmax[g,n]); +printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_qP[g,n]), "corrected_unit_qP", max({(g,n) in UNITON} corrected_unit_qP[g,n]); +printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_qp[g,n]), "corrected_unit_qp", max({(g,n) in UNITON} corrected_unit_qp[g,n]); +printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_QP[g,n]), "corrected_unit_QP", max({(g,n) in UNITON} corrected_unit_QP[g,n]); +printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_Qp[g,n]), "corrected_unit_Qp", max({(g,n) in UNITON} corrected_unit_Qp[g,n]); \ No newline at end of file diff --git a/open-reac/src/main/resources/openreac/commons.mod b/open-reac/src/main/resources/openreac/commons.mod new file mode 100644 index 00000000..776cb080 --- /dev/null +++ b/open-reac/src/main/resources/openreac/commons.mod @@ -0,0 +1,210 @@ +############################################################################### +# +# 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 +############################################################################### + + +############################################################################### +# Voltage bounds that will really been used +############################################################################### + +# Negative value for substation_Vmin or substation_Vmax means that the value is undefined +# In that case, minimal_voltage_lower_bound or maximal_voltage_upper_bound is used instead + +# Note that low and high override are taken into account only if +# substation_new_Vmin > minimal_voltage_lower_bound and substation_new_Vmax < maximal_voltage_upper_bound + +param voltage_lower_bound{(t,s) in SUBSTATIONS} := + max( minimal_voltage_lower_bound, + if s in BOUND_OVERRIDES then substation_new_Vmin[s] else substation_Vmin[t,s] + ); + +param voltage_upper_bound{(t,s) in SUBSTATIONS} := + if s in BOUND_OVERRIDES and substation_new_Vmax[s] <= voltage_lower_bound[t,s] then maximal_voltage_upper_bound + else if s in BOUND_OVERRIDES then min(maximal_voltage_upper_bound,substation_new_Vmax[s]) + else if substation_Vmax[t,s] <= voltage_lower_bound[t,s] then maximal_voltage_upper_bound + else min(maximal_voltage_upper_bound,substation_Vmax[t,s]); + +check {(t,s) in SUBSTATIONS}: voltage_lower_bound[t,s] < voltage_upper_bound[t,s]; + +# Elements in main connex component +set BUS2:= setof {(1,n) in BUS: + bus_CC[1,n] == 0 + and n >= 0 + and substation_Vnomi[1,bus_substation[1,n]] >= epsilon_nominal_voltage + } n; +set BRANCH2:= setof {(1,qq,m,n) in BRANCH: m in BUS2 and n in BUS2} (qq,m,n); + +set BUSCC dimen 1 default {}; +set BRANCHCC := {(qq,m,n) in BRANCH2: m in BUSCC and n in BUSCC}; + + +############################################################################### +# Maximum flows on branches +############################################################################### +param Fmax{(qq,m,n) in BRANCHCC} := + 1.732 * 0.001 + * max(substation_Vnomi[1,bus_substation[1,m]]*abs(branch_patl1[1,qq,m,n]),substation_Vnomi[1,bus_substation[1,n]]*abs(branch_patl2[1,qq,m,n])); + +set LOADCC := setof {(1,c,n) in LOAD : n in BUSCC} (c,n); +set UNITCC := setof {(1,g,n) in UNIT : n in BUSCC} (g,n); +set BATTERYCC := setof {(1,b,n) in BATTERY : n in BUSCC} (b,n); + + +# Units up and generating: +# Warning: units with Ptarget=0 are considered as out of order +set UNITON := {(g,n) in UNITCC : abs(unit_Pc[1,g,n]) >= Pnull}; + +# +# VSC converter stations +# +set VSCCONVON := setof{(t,v,n) in VSCCONV: + n in BUSCC + and abs(vscconv_P0[t,v,n] ) <= PQmax + and abs(vscconv_Pmin[t,v,n]) <= PQmax + and abs(vscconv_Pmax[t,v,n]) <= PQmax + and vscconv_P0[t,v,n] >= vscconv_Pmin[t,v,n] + and vscconv_P0[t,v,n] <= vscconv_Pmax[t,v,n] + } (v,n); + +# +# LCC converter stations +# +set LCCCONVON := setof{(t,l,n) in LCCCONV: + n in BUSCC + and abs(lccconv_P0[1,l,n]) <= PQmax + and abs(lccconv_Q0[1,l,n]) <= PQmax + } (l,n); + + +############################################################################### +# Corrected values for reactances +############################################################################### + +# Branches with zero or near zero impedances +# Notice: module of Z is equal to square root of (R^2+X^2) +set BRANCHZNULL := {(qq,m,n) in BRANCHCC: branch_R[1,qq,m,n]^2+branch_X[1,qq,m,n]^2 <= Znull^2}; + + +# If in BRANCHZNULL, then set X to ZNULL +param branch_X_mod{(qq,m,n) in BRANCHCC} := + if (qq,m,n) in BRANCHZNULL then Znull + else branch_X[1,qq,m,n]; +check {(qq,m,n) in BRANCHCC}: abs(branch_X_mod[qq,m,n]) > 0; + +# Busses with valid voltage value +set BUSVV := {n in BUSCC : bus_V0[1,n] >= min_plausible_low_voltage_limit}; + +# Reactive +set SHUNTCC := {(1,s,n) in SHUNT: n in BUSCC or shunt_possiblebus[1,s,n] in BUSCC}; # We want to be able to reconnect shunts +set BRANCHCC_REGL := {(qq,m,n) in BRANCHCC diff BRANCHZNULL: branch_ptrRegl[1,qq,m,n] != -1 }; +set BRANCHCC_DEPH := {(qq,m,n) in BRANCHCC diff BRANCHZNULL: branch_ptrDeph[1,qq,m,n] != -1 }; +set SVCCC := {(1,svc,n) in SVC: n in BUSCC}; + +# +# Control parameters for SVC +# +# Simple: if regul==true then SVC is on, else it is off +set SVCON := {(svc,n) in SVCCC: svc_vregul[1,svc,n]=="true" and svc_bmin[1,svc,n]<=svc_bmax[1,svc,n]-Pnull/base100MVA}; + +# +# Control parameters for shunts +# If no shunt in PARAM_SHUNT, it means that hey are all fixed +# +# Variable shunts +# Shunts wich are not connected (n=-1) but which are in PARAM_SHUNT are considered as connected to their possible bus, with variable reactance +set SHUNT_VAR := setof {(1,s,n) in SHUNT : + s in PARAM_SHUNT + and (s,n) in SHUNTCC # Remember n might be -1 if shunt_possiblebus[1,s,n] is in BUSCC + and abs(shunt_valmin[1,s,n])+abs(shunt_valmax[1,s,n]) >= Pnull / base100MVA # Useless to allow change if values are too small + } (s,shunt_possiblebus[1,s,n]); +# Shunts with fixed values +set SHUNT_FIX := setof {(1,s,n) in SHUNT: s not in PARAM_SHUNT and n in BUSCC} (s,n); +# If a shunt is not connected (n=-1) and it is not in PARAM_SHUNT, then it will not be +# reconnected by reactive opf. These shunts are not in SHUNT_VAR nor in SHUNT_FIX; they +# are simply ignored + +# +# Control parameters for reactive power of units +# +# If unit_Qc is not consistent, then reactive power will be a variable +set UNIT_FIXQ := {(g,n) in UNITON: g in PARAM_UNIT_FIXQ and abs(unit_Qc[1,g,n])= Znull + then branch_R[1,qq,m,n]*branch_Xdeph[qq,m,n]/branch_X_mod[qq,m,n] + else branch_R[1,qq,m,n] + ; + +param branch_angper{(qq,m,n) in BRANCHCC} = + if (qq,m,n) in BRANCHCC_DEPH + then atan2(branch_Rdeph[qq,m,n], branch_Xdeph[qq,m,n]) + else atan2(branch_R[1,qq,m,n] , branch_X_mod[qq,m,n] ); + +param branch_admi {(qq,m,n) in BRANCHCC} = + if (qq,m,n) in BRANCHCC_DEPH + then 1./sqrt(branch_Rdeph[qq,m,n]^2 + branch_Xdeph[qq,m,n]^2 ) + else 1./sqrt(branch_R[1,qq,m,n]^2 + branch_X_mod[qq,m,n]^2 ); + +# Later in this file, a variable branch_Ror_var will be created, to replace branch_Ror when it is not variable +param branch_Ror {(qq,m,n) in BRANCHCC} = + ( if ((qq,m,n) in BRANCHCC_REGL) + then tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],regl_tap0[1,branch_ptrRegl[1,qq,m,n]]] + else 1.0 + ) + * ( if ((qq,m,n) in BRANCHCC_DEPH) + then tap_ratio[1,deph_table[1,branch_ptrDeph[1,qq,m,n]],deph_tap0[1,branch_ptrDeph[1,qq,m,n]]] + else 1.0 + ) + * (branch_cstratio[1,qq,m,n]); +param branch_Rex {(q,m,n) in BRANCHCC} = 1; # In IIDM, everything is in bus1 so ratio at bus2 is always 1 + +param branch_dephor {(qq,m,n) in BRANCHCC} = + if ((qq,m,n) in BRANCHCC_DEPH) + then tap_angle [1,deph_table[1,branch_ptrDeph[1,qq,m,n]],deph_tap0[1,branch_ptrDeph[1,qq,m,n]]] + else 0; +param branch_dephex {(qq,m,n) in BRANCHCC} = 0; # In IIDM, everything is in bus1 so dephase at bus2 is always 0 + + +############################################################################### +# Corrected values for units +############################################################################### +param corrected_unit_Pmin{UNITON} default defaultPmin; +param corrected_unit_Pmax{UNITON} default defaultPmax; +param corrected_unit_qP {UNITON} default defaultQmin; +param corrected_unit_qp {UNITON} default defaultQmin; +param corrected_unit_QP {UNITON} default defaultQmax; +param corrected_unit_Qp {UNITON} default defaultQmax; +param corrected_unit_Qmin{UNITON} default defaultQmin; +param corrected_unit_Qmax{UNITON} default defaultQmax; \ No newline at end of file diff --git a/open-reac/src/main/resources/openreac/connected_component.mod b/open-reac/src/main/resources/openreac/connected_component.mod new file mode 100644 index 00000000..c7c7ba39 --- /dev/null +++ b/open-reac/src/main/resources/openreac/connected_component.mod @@ -0,0 +1,32 @@ +############################################################################### +# +# 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 +############################################################################### + +set PROBLEM_CCOMP default { }; + +############################################################################### +# +# Variables and contraints for connexity computation +# +############################################################################### +# Even if set BUS2 is only with busses in connex component (CC) number '0', for an OPF we +# have to do connexity computation using only AC branches, ie in only one single synchronous area. +# Indeed, HVDC branches may connect 2 synchronous areas; one might consider in that case that de grid is connex +# In our case we have to consider only buses which are connected to reference bus with AC branches +var teta_ccomputation{BUS2} >=0, <=1; +subject to ctr_null_phase_bus_cccomputation{PROBLEM_CCOMP}: teta_ccomputation[null_phase_bus] = 0; +subject to ctr_flow_cccomputation{PROBLEM_CCOMP, (qq,m,n) in BRANCH2}: teta_ccomputation[m]-teta_ccomputation[n]=0; +maximize cccomputation_objective: sum{n in BUS2} teta_ccomputation[n]; +# All busses AC-connected to null_phase_bus will have '0' as optimal value, other will have '1' \ No newline at end of file diff --git a/open-reac/src/main/resources/openreac/connected_component.run b/open-reac/src/main/resources/openreac/connected_component.run new file mode 100644 index 00000000..8dfe864c --- /dev/null +++ b/open-reac/src/main/resources/openreac/connected_component.run @@ -0,0 +1,153 @@ +############################################################################### +# +# 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 +############################################################################### + + +############################################################################### +# +# Computation of "slack bus" or reference bus +# +############################################################################### +# This is not really a slack bus since this reactive OPF will change values +# of generation proportionally, to ensure global balance generation=losses+load +# So this "slack node" is used only for zero phase constraint +# This reference bus is also used to choose on which connect component computation si performed +printf{LOG_INFO} "\nComputation of bus with largest number of branches connected, in order to fix phase to 0 and to choose on which connex component reacive OPF will run\n"; +let temp1 := min(300,max{n in BUS2} substation_Vnomi[1,bus_substation[1,n]]); +let null_phase_bus := min{n in BUS2} n; +let tempo := 0; +for {n in BUS2 : substation_Vnomi[1,bus_substation[1,n]] >= temp1 * 0.9} + let tempo := max (tempo, card({(qq,mm,n) in BRANCH2} union {(qq,n,nn) in BRANCH2})); +for {n in BUS2 : substation_Vnomi[1,bus_substation[1,n]] >= temp1 * 0.9 && card({(qq,mm,n) in BRANCH2} union {(qq,n,nn) in BRANCH2}) == tempo} + let null_phase_bus := n; +if ( tempo > 0 ) then + printf{LOG_INFO} "Bus %QkV with most branches: %Q in substation %s/%s with %Q connected branches\n", + substation_Vnomi[1,bus_substation[1,null_phase_bus]], + null_phase_bus, + substation_id[1,bus_substation[1,null_phase_bus]], + substation_description[1,bus_substation[1,null_phase_bus]], + tempo; +if ( tempo == 0 ) then + printf{LOG_WARNING} "Bus with most branches: not found. Take first bus (=%Q) for phase=0 constraint\n",null_phase_bus; + + +############################################################################### +# Solve PROBLEM_CCOMP +############################################################################### + +let PROBLEM_CCOMP := {1}; +let tempstr := ctime(); +printf{LOG_KNITRO} "\n######################################################################\n"; +printf{LOG_KNITRO} "** CCcomp solve: start (%s)\n\n",tempstr; + +option presolve 0; +option knitro_options ("outlev=3");; + +# TODO : remove suffix printing +if (log_level_knitro <= 1) then { + solve cccomputation_objective > (nullDevice); +} else { + solve cccomputation_objective; +} + +printf{LOG_KNITRO} "\n** CCcomp solve: end (%s -> %s)\n",tempstr,ctime(); +printf{LOG_KNITRO} "######################################################################\n\n"; + + +############################################################################### +# Analysis of solve_result_num +############################################################################### + +if solve_result_num > 103 or card({n in BUS2: teta_ccomputation[n].val > 0.01 and teta_ccomputation[n].val < 0.99})>0 +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. + let errorMessage := "Optimization for connex component computation failed"; + let final_status := "NOK"; + include reactiveopfexit.run; +} +option presolve 10; + + +############################################################################### +# Definition of BUSCC below was the purpose of this optimization +############################################################################### + +printf{LOG_INFO} "\n######################################################################\n"; +printf{LOG_INFO} "** CCcomp results\n"; + +let BUSCC := {n in BUS2: teta_ccomputation[n].val <= 0.01}; +for{n in BUS2 diff BUSCC} + printf{LOG_WARNING} "Bus %Q in substation %Q (Vnomi=%.2fkV, country=%Q) is out of main AC CC\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]]; +printf{LOG_INFO} "Nb of busses in AC+DC CC: %i\n",card(BUS2); +printf{LOG_INFO} "Nb of busses in CC %Q: %i\n",bus_id[1,null_phase_bus],card(BUSCC); +printf{LOG_INFO} "Nb of busses in other CCs: %Q\n",card(BUS2)-card(BUSCC); +printf "\n"; + + +############################################################################### +# A few information +############################################################################### + +if 1 in LOG_INFO then { + display + maximal_voltage_upper_bound, minimal_voltage_lower_bound, + card(SUBSTATIONS),card(BUS),card(BUS2),card(BUSCC),card(BUS2 diff BUSCC),card(BUSVV), + card(BRANCH),card(BRANCHCC),card(BRANCHZNULL),card(BRANCHCC diff BRANCHZNULL), + card(UNIT),card(UNITCC),card(UNITON),card(UNITON diff UNIT_FIXQ),card(UNIT_FIXQ), + card(LOAD),card(LOADCC), + card(SHUNTCC),card(SHUNT_FIX),card(SHUNT_VAR), + card(SVC),card(SVCCC),card(SVCON), + card(VSCCONV),card(VSCCONVON), + card(LCCCONV),card(LCCCONVON) +; +} + +# Is the case power globally power balanced? +let temp1 := sum{(c,n) in LOADCC} load_PFix[1,c,n]; +let temp2 := sum{(g,n) in UNITON} unit_Pc[1,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]); +let global_initial_losses_ratio := (temp2-temp1-temp3)/(temp1+temp3); + +printf{LOG_INFO} "HVDC injections (homogeneous to loads):\n"; +for {(v,n) in VSCCONVON} + printf{LOG_INFO} "VSC converter %Q in %Q: P0=%.1fMW is fixed, Q is variable\n", + vscconv_id[1,v,n],substation_id[1,bus_substation[1,n]],vscconv_P0[1,v,n]; +for {(l,n) in LCCCONVON} + printf{LOG_INFO} "LCC converter %Q in %Q: P0=%.1fMW is fixed, Q0=%.1fMvar is fixed\n", + lccconv_id[1,l,n],substation_id[1,bus_substation[1,n]],lccconv_P0[1,l,n],lccconv_Q0[1,l,n]; +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} " (including batteries for %.1f MW\n", sum{(b,n) in BATTERYCC} battery_p0[1,b,n]; +printf{LOG_INFO} "Balance (P-C-H)/C: %.2f %% (global_initial_losses_ratio=%f)\n\n", (temp2-temp1-temp3)/temp1*100,global_initial_losses_ratio; + +# Branches with low current limits (but keep in mind they are not used; this is just for information) +let temp1 := min{(qq,m,n) in BRANCHCC} Fmax[qq,m,n]; +for {(qq,m,n) in BRANCHCC : Fmax[qq,m,n] <= temp1 * 1.5} + printf{LOG_INFO} "Branch %Q Fmax=%.2fMW is small ; Vnom1=%ikV Vnom2=%ikV patl1=%iA patl2=%iA (Fmax not used, this is just for information)\n", + branch_id[1,qq,m,n],Fmax[qq,m,n],substation_Vnomi[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,n]],branch_patl1[1,qq,m,n],branch_patl1[1,qq,m,n]; + +# Abnormally low nominal voltages +for {(t,n) in BUS: substation_Vnomi[1,bus_substation[1,n]] < epsilon_nominal_voltage} + printf{LOG_WARNING} "Warning: bus %Q in substation %Q has nominal voltage %.2fkV < %QkV -> bus is ignored\n", + bus_id[1,n], substation_id[1,bus_substation[1,n]], substation_Vnomi[1,bus_substation[1,n]], epsilon_nominal_voltage; + +# desactivate optimization problem +let PROBLEM_CCOMP := { }; \ No newline at end of file diff --git a/open-reac/src/main/resources/openreac/dcopf.mod b/open-reac/src/main/resources/openreac/dcopf.mod new file mode 100644 index 00000000..320c5ac4 --- /dev/null +++ b/open-reac/src/main/resources/openreac/dcopf.mod @@ -0,0 +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 +# +############################################################################### + +############################################################################### +# Reactive OPF +# Author: Jean Maeght 2022 2023 +# Author: Manuel Ruiz 2023 2024 +############################################################################### + + +set PROBLEM_DCOPF default {1}; + +############################################################################### +# +# 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 + +# 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]; + + +# +# 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 new file mode 100644 index 00000000..41a47db4 --- /dev/null +++ b/open-reac/src/main/resources/openreac/dcopf.run @@ -0,0 +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])= epsilon_nominal_voltage}) > 1; + +# Voltage bounds +check{(t,s) in SUBSTATIONS: substation_Vmin[t,s] >= min_plausible_low_voltage_limit and substation_Vmax[t,s] >= min_plausible_low_voltage_limit}: +substation_Vmin[t,s] < substation_Vmax[t,s]; + +# Parameters min_plausible_low_voltage_limit and max_plausible_high_voltage_limit are used to force voltage to be in interval [min_plausible_low_voltage_limit;max_plausible_high_voltage_limit]. +# Default value is [0.5;1.5] although academics would use low limit equals to 0.9 or 0.95 +# Bounds below will be used for substations without bounds or with bad bounds +param minimal_voltage_lower_bound := +if card({(t,s) in SUBSTATIONS: substation_Vmin[t,s] > 0}) > 0 +then max(min_plausible_low_voltage_limit,min{(t,s) in SUBSTATIONS: substation_Vmin[t,s] > 0} substation_Vmin[t,s]) +else min_plausible_low_voltage_limit; +param maximal_voltage_upper_bound := +if card({(t,s) in SUBSTATIONS: substation_Vmin[t,s] > 0}) > 0 +then min(max_plausible_high_voltage_limit,max{(t,s) in SUBSTATIONS: substation_Vmax[t,s] > 0} substation_Vmax[t,s]) +else max_plausible_high_voltage_limit; +check minimal_voltage_lower_bound > 0; +check maximal_voltage_upper_bound > minimal_voltage_lower_bound; + + + +############################################################################### +# Buses +############################################################################### +# ampl_network_buses.txt +set BUS dimen 2 ; # [variant, bus] +param bus_substation{BUS} integer; +param bus_CC {BUS} integer; # num of connex component. Computation only in CC number 0 (=main connex component) +param bus_V0 {BUS}; +param bus_angl0 {BUS}; +param bus_injA {BUS}; +param bus_injR {BUS}; +param bus_fault {BUS}; +param bus_curative {BUS}; +param bus_id {BUS} symbolic; + +# Consistency checks +check{(t,n) in BUS}: t in TIME; +check{(t,n) in BUS}: n >= -1; +check{(t,n) in BUS}: (t,bus_substation[t,n]) in SUBSTATIONS; + +param null_phase_bus; + + + +############################################################################### +# Generating units +############################################################################### +# ampl_network_generators.txt + +set UNIT dimen 3; # [variant, unit, bus] +param unit_potentialbus{UNIT} integer; +param unit_substation {UNIT} integer; +param unit_Pmin {UNIT}; +param unit_Pmax {UNIT}; +param unit_qP {UNIT}; +param unit_qp0 {UNIT}; +param unit_qp {UNIT}; +param unit_QP {UNIT}; +param unit_Qp0 {UNIT}; +param unit_Qp {UNIT}; +param unit_vregul {UNIT} symbolic; # Does unit do voltage regulation, or PQ bus? +param unit_Vc {UNIT}; # Voltage set point (in case of voltage regulation) +param unit_Pc {UNIT}; # Active power set point +param unit_Qc {UNIT}; # Rective power set point (in case no voltage regulation) +param unit_fault {UNIT}; +param unit_curative{UNIT}; +param unit_id {UNIT} symbolic; +param unit_name {UNIT} symbolic; # description +param unit_P0 {UNIT}; # Initial value of P (if relevant) +param unit_Q0 {UNIT}; # Initial value of Q (if relevant) + +# +# Consistency +# +check {(t,g,n) in UNIT}: t in TIME; +check {(t,g,n) in UNIT}: (t,n) in BUS or n==-1; +check {(t,g,n) in UNIT}: (t,unit_substation[t,g,n]) in SUBSTATIONS; +check {(t,g,n) in UNIT}: unit_Pmax[t,g,n] >= -Pnull; +check {(t,g,n) in UNIT}: unit_Pmax[t,g,n] >= unit_Pmin[t,g,n]; +# Checks below are useless since values will be corrected for units in UNITON +#check {(t,g,n) in UNIT}: unit_Qp[t,g,n] >= unit_qp[t,g,n]; +#check {(t,g,n) in UNIT}: unit_QP[t,g,n] >= unit_qP[t,g,n] ; + +# Global inital losses_ratio: value of (P-C-H)/(C+H) in data files +# Value is 0 if no losses +# Value 0.02 means % of losses +param global_initial_losses_ratio default 0.02; # Typical value value for transmission + + + +############################################################################### +# Loads +############################################################################### +# ampl_network_loads.txt + +set LOAD dimen 3; # [variant, load, bus] +param load_substation{LOAD} integer; +param load_PFix {LOAD}; +param load_QFix {LOAD}; +param load_fault {LOAD}; +param load_curative {LOAD}; +param load_id {LOAD} symbolic; +param load_name {LOAD} symbolic; +param load_p {LOAD}; +param load_q {LOAD}; + +# Consistency checks +check {(t,c,n) in LOAD}: t in TIME; +check {(t,c,n) in LOAD}: (t,n) in BUS or n==-1; +check {(t,c,n) in LOAD}: (t,load_substation[t,c,n]) in SUBSTATIONS; + + + +############################################################################### +# Shunts +############################################################################### +# ampl_network_shunts.txt + +set SHUNT dimen 3; # [variant, shunt, bus] +param shunt_possiblebus {SHUNT} integer; +param shunt_substation {SHUNT} integer; +param shunt_valmin {SHUNT}; # Susceptance B in p.u.: compute B*100*V^2 to get MVAr +param shunt_valmax {SHUNT}; # Susceptance B in p.u.: compute B*100*V^2 to get MVAr +param shunt_interPoints {SHUNT}; # Intermediate points: if there are 0 interPoint, it means that either min or max are possible +param shunt_valnom {SHUNT}; # Susceptance B in p.u.: compute B*100*V^2 to get MVAr. If value >= 0, this means reactive power generation +param shunt_fault {SHUNT}; +param shunt_curative {SHUNT}; +param shunt_id {SHUNT} symbolic; +param shunt_nom {SHUNT} symbolic; +param shunt_P0 {SHUNT}; +param shunt_Q0 {SHUNT}; # Reactive power load: valnom >= 0 means Q0 <= 0 +param shunt_sections_count{SHUNT} integer; + +# Consistency checks +check {(t,s,n) in SHUNT}: (t,n) in BUS or n==-1; +check {(t,s,n) in SHUNT}: n==-1 or shunt_possiblebus[t,s,n]==n; +check {(t,s,-1) in SHUNT}: (t,shunt_possiblebus[t,s,-1]) in BUS or shunt_possiblebus[t,s,-1]==-1; +check {(t,s,n) in SHUNT}: (t,shunt_substation[t,s,n]) in SUBSTATIONS; + +# Case of a reactance : check valmin < 0 and valmax=0 +check {(t,s,n) in SHUNT}: shunt_valmin[1,s,n] <= 0; +check {(t,s,n) in SHUNT : shunt_valmin[1,s,n] <= -Pnull / base100MVA}: shunt_valmax[1,s,n] <= Pnull / base100MVA; +# Case of a condo : check valmin = 0 and valmax>0 +check {(t,s,n) in SHUNT}: shunt_valmax[1,s,n] >= 0; +check {(t,s,n) in SHUNT : shunt_valmax[1,s,n] >= Pnull / base100MVA}: shunt_valmin[1,s,n] >= -Pnull / base100MVA; + + + +############################################################################### +# Static Var Compensator +############################################################################### +# ampl_network_static_var_compensators.txt + +set SVC dimen 3; # [variant, svc, bus] +param svc_possiblebus {SVC} integer; +param svc_substation {SVC} integer; +param svc_bmin {SVC}; # Susceptance B in p.u.: compute B*100*V^2 to get MVAr +param svc_bmax {SVC}; # Susceptance B in p.u.: compute B*100*V^2 to get MVAr +param svc_vregul {SVC} symbolic; # true if SVC is in voltage regulation mode +param svc_targetV {SVC}; # Voltage target for voltage regulation mode +param svc_targetQ {SVC}; +param svc_fault {SVC}; +param svc_curative {SVC}; +param svc_id {SVC} symbolic; +param svc_description {SVC} symbolic; +param svc_P0 {SVC}; +param svc_Q0 {SVC}; # Fixed value to be used if SVC is not in voltage regulation mode. If value >= 0, this means reactive power generation + +# Consistency checks +check {(t,svc,n) in SVC}: (t,n) in BUS or n==-1; +check {(t,svc,n) in SVC}: (t,svc_substation[t,svc,n]) in SUBSTATIONS; + + + +############################################################################### +# Batteries +############################################################################### +# ampl_network_batteries.txt +set BATTERY dimen 3; # [variant, battery, bus] +param battery_possiblebus{BATTERY} integer; +param battery_substation {BATTERY} integer; +param battery_p0 {BATTERY}; # current P of the battery, P0 <= 0 if batterie is charging +param battery_q0 {BATTERY}; +param battery_Pmin {BATTERY}; +param battery_Pmax {BATTERY}; +param battery_qP {BATTERY}; +param battery_qp0 {BATTERY}; +param battery_qp {BATTERY}; +param battery_QP {BATTERY}; +param battery_Qp0 {BATTERY}; +param battery_Qp {BATTERY}; +param battery_fault {BATTERY}; +param battery_curative{BATTERY}; +param battery_id {BATTERY} symbolic; +param battery_name {BATTERY} symbolic; +param battery_P0 {BATTERY}; +param battery_Q0 {BATTERY}; + +# Consistency checks +check {(t,b,n) in BATTERY} : (t,n) in BUS union {(t,-1)}; +check {(t,b,n) in BATTERY} : (t,battery_substation[t,b,n]) in SUBSTATIONS; +check {(t,b,n) in BATTERY: (t,n) in BUS} : battery_substation[t,b,n] == bus_substation[t,n]; +check {(t,b,n) in BATTERY} : battery_Pmin[t,b,n] <= battery_Pmax[t,b,n] ; +check {(t,b,n) in BATTERY} : abs(battery_p0[t,b,n]) <= PQmax; +check {(t,b,n) in BATTERY} : abs(battery_q0[t,b,n]) <= PQmax; + + + +############################################################################### +# Tables of taps +############################################################################### +# ampl_network_tct.txt +# Data in these tables are used for both ratio tap changers and phase taps changers + +set TAPS dimen 3; # [variant, num, tap] +param tap_ratio {TAPS}; +param tap_x {TAPS}; +param tap_angle {TAPS}; +param tap_fault {TAPS}; +param tap_curative {TAPS}; + +# Created data +set TAPTABLES := setof {(t,tab,tap) in TAPS} tab; + +# Consistency checks +check {(t,tab,tap) in TAPS}: tab > 0 && tap >= 0; + + + +############################################################################### +# Ratio tap changers +############################################################################### +# ampl_network_rtc.txt + +param regl_V_missing := -99999.0; +set REGL dimen 2; # [variant, num] +param regl_tap0 {REGL} integer; +param regl_table {REGL} integer; +param regl_onLoad {REGL} symbolic; +param regl_V {REGL} ; +param regl_fault {REGL}; +param regl_curative {REGL}; +param regl_id {REGL} symbolic; + +# Consistency checks +check {(t,r) in REGL}: regl_table[t,r] in TAPTABLES; +check {(t,r) in REGL}: (t,regl_table[t,r], regl_tap0[t,r]) in TAPS; + +param regl_ratio_min{(t,r) in REGL} := min{(t,regl_table[t,r],tap) in TAPS} tap_ratio[t,regl_table[t,r],tap]; +param regl_ratio_max{(t,r) in REGL} := max{(t,regl_table[t,r],tap) in TAPS} tap_ratio[t,regl_table[t,r],tap]; + + + +############################################################################### +# Phase tap changers +############################################################################### +# ampl_network_ptc.txt + +set DEPH dimen 2; # [variant, num] +param deph_tap0 {DEPH} integer; +param deph_table {DEPH} integer; +param deph_fault {DEPH}; +param deph_curative {DEPH}; +param deph_id {DEPH} symbolic; + +# Consistency checks +check {(t,d) in DEPH}: deph_table[t,d] in TAPTABLES; +check {(t,d) in DEPH}: (t,deph_table[t,d], deph_tap0[t,d]) in TAPS; + + + +############################################################################### +# Branches +############################################################################### +# ampl_network_branches.txt + +set BRANCH dimen 4; # [variant, branch, bus1, bus2] +param branch_subor {BRANCH} integer; +param branch_subex {BRANCH} integer; +param branch_3wt {BRANCH}; +param branch_R {BRANCH}; +param branch_X {BRANCH}; +param branch_Gor {BRANCH}; +param branch_Gex {BRANCH}; +param branch_Bor {BRANCH}; +param branch_Bex {BRANCH}; +param branch_cstratio {BRANCH}; # fixed ratio +param branch_ptrRegl {BRANCH} integer; # Number of ratio tap changer +param branch_ptrDeph {BRANCH} integer; # Number of phase tap changer +param branch_Por {BRANCH}; +param branch_Pex {BRANCH}; +param branch_Qor {BRANCH}; +param branch_Qex {BRANCH}; +param branch_patl1 {BRANCH}; +param branch_patl2 {BRANCH}; +param branch_merged {BRANCH} symbolic; +param branch_fault {BRANCH}; +param branch_curative {BRANCH}; +param branch_id {BRANCH} symbolic; +param branch_name {BRANCH} symbolic; + + +# Consistency checks +check {(t,qq,m,n) in BRANCH}: t in TIME; +check {(t,qq,m,n) in BRANCH}: + ( (t,m) in BUS or m==-1 ) + && ( (t,n) in BUS or n==-1 ) + && ( m != n || m == -1 ) # no problem if m==n==-1 + && qq > 0 + && (t,branch_subor[t,qq,m,n]) in SUBSTATIONS + && (t,branch_subex[t,qq,m,n]) in SUBSTATIONS; +check {(t,qq,m,n) in BRANCH}: (t,branch_ptrRegl[t,qq,m,n]) in REGL union {(1,-1)}; +check {(t,qq,m,n) in BRANCH}: (t,branch_ptrDeph[t,qq,m,n]) in DEPH union {(1,-1)}; + +# Admittances +#param branch_G {(t,qq,m,n) in BRANCH} = +branch_R[t,qq,m,n]/(branch_R[t,qq,m,n]^2+branch_X[t,qq,m,n]^2); +#param branch_B {(t,qq,m,n) in BRANCH} = -branch_X[t,qq,m,n]/(branch_R[t,qq,m,n]^2+branch_X[t,qq,m,n]^2); + + + +############################################################################### +# VSC converter station data +############################################################################### +# ampl_network_vsc_converter_stations.txt + +set VSCCONV dimen 3; # [variant, num, bus] +param vscconv_possiblebus {VSCCONV} integer; +param vscconv_substation {VSCCONV} integer; +param vscconv_Pmin {VSCCONV}; +param vscconv_Pmax {VSCCONV}; +param vscconv_qP {VSCCONV}; +param vscconv_qp0 {VSCCONV}; +param vscconv_qp {VSCCONV}; +param vscconv_QP {VSCCONV}; +param vscconv_Qp0 {VSCCONV}; +param vscconv_Qp {VSCCONV}; +param vscconv_vregul {VSCCONV} symbolic; +param vscconv_targetV {VSCCONV}; +param vscconv_targetQ {VSCCONV}; +param vscconv_lossFactor {VSCCONV}; +param vscconv_fault {VSCCONV}; +param vscconv_curative {VSCCONV}; +param vscconv_id {VSCCONV} symbolic; +param vscconv_description {VSCCONV} symbolic; +param vscconv_P0 {VSCCONV}; # P0 >= 0 means active power going from AC grid to DC line (homogeneous to a load) +param vscconv_Q0 {VSCCONV}; + +# Consistency checks +check {(t,cs,n) in VSCCONV}: (t,n) in BUS union {(1,-1)}; +check {(t,cs,n) in VSCCONV}: (t,vscconv_substation[t,cs,n]) in SUBSTATIONS; +check {(t,cs,n) in VSCCONV}: vscconv_Pmin[t,cs,n] <= vscconv_Pmax[t,cs,n]; +check {(t,cs,n) in VSCCONV}: vscconv_qp[t,cs,n] <= vscconv_Qp[t,cs,n]; +check {(t,cs,n) in VSCCONV}: vscconv_qp0[t,cs,n] <= vscconv_Qp0[t,cs,n]; +check {(t,cs,n) in VSCCONV}: vscconv_qP[t,cs,n] <= vscconv_QP[t,cs,n]; + + + +############################################################################### +# LCC converter station data +############################################################################### +# ampl_network_lcc_converter_stations.txt +#"variant" "num" "bus" "con. bus" "substation" "lossFactor (%PDC)" "powerFactor" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" + +set LCCCONV dimen 3; # [variant, num, bus] +param lccconv_possiblebus {LCCCONV} integer; +param lccconv_substation {LCCCONV} integer; +param lccconv_loss_factor {LCCCONV}; +param lccconv_power_factor{LCCCONV}; +param lccconv_fault {LCCCONV}; +param lccconv_curative {LCCCONV}; +param lccconv_id {LCCCONV} symbolic; +param lccconv_description {LCCCONV} symbolic; +param lccconv_P0 {LCCCONV}; +param lccconv_Q0 {LCCCONV}; + + + +############################################################################### +# HVDC +############################################################################### +# ampl_network_hvdc.txt + +set HVDC dimen 2; # [variant, num] +param hvdc_type {HVDC} integer; # 1->vscConverterStation, 2->lccConverterStation +param hvdc_conv1 {HVDC} integer; +param hvdc_conv2 {HVDC} integer; +param hvdc_r {HVDC}; +param hvdc_Vnom {HVDC}; +param hvdc_convertersMode {HVDC} symbolic; +param hvdc_targetP {HVDC}; +param hvdc_Pmax {HVDC}; +param hvdc_fault {HVDC}; +param hvdc_curative {HVDC}; +param hvdc_id {HVDC} symbolic; +param hvdc_description {HVDC} symbolic; + +# Consistency checks +check {(t,h) in HVDC}: hvdc_type[t,h] == 1 or hvdc_type[t,h] == 2; +check {(t,h) in HVDC}: hvdc_conv1[t,h] != hvdc_conv2[t,h]; +check {(t,h) in HVDC: hvdc_type[t,h] == 1}: hvdc_conv1[t,h] in setof{(t,n,bus) in VSCCONV}n; +check {(t,h) in HVDC: hvdc_type[t,h] == 1}: hvdc_conv2[t,h] in setof{(t,n,bus) in VSCCONV}n; +check {(t,h) in HVDC: hvdc_type[t,h] == 2}: hvdc_conv1[t,h] in setof{(t,n,bus) in LCCCONV}n; +check {(t,h) in HVDC: hvdc_type[t,h] == 2}: hvdc_conv2[t,h] in setof{(t,n,bus) in LCCCONV}n; +check {(t,h) in HVDC}: hvdc_Vnom[t,h] >= epsilon_nominal_voltage; +check {(t,h) in HVDC}: hvdc_convertersMode[t,h] == "SIDE_1_RECTIFIER_SIDE_2_INVERTER" or hvdc_convertersMode[t,h] == "SIDE_1_INVERTER_SIDE_2_RECTIFIER"; +check {(t,h) in HVDC}: hvdc_targetP[t,h] >= 0.0; +check {(t,h) in HVDC}: hvdc_targetP[t,h] <= hvdc_Pmax[t,h]; + diff --git a/open-reac/src/main/resources/openreac/or_param_importer.mod b/open-reac/src/main/resources/openreac/or_param_importer.mod new file mode 100644 index 00000000..11a0ddd6 --- /dev/null +++ b/open-reac/src/main/resources/openreac/or_param_importer.mod @@ -0,0 +1,77 @@ +############################################################################### +# +# 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 +############################################################################### + + +############################################################################### +# Overrides for voltage bounds of substations +############################################################################### +#ampl_network_substations_override.txt +set BOUND_OVERRIDES dimen 1 default {}; +param substation_new_Vmin {BOUND_OVERRIDES}; +param substation_new_Vmax {BOUND_OVERRIDES}; +param substation_new_checkId {BOUND_OVERRIDES} symbolic; + +# Consistency checks +check {(t,s) in SUBSTATIONS: s in BOUND_OVERRIDES}: substation_id[t,s] == substation_new_checkId[s]; +check {(t,s) in SUBSTATIONS: s in BOUND_OVERRIDES}: substation_new_Vmin[s] >= 0; +check {(t,s) in SUBSTATIONS: s in BOUND_OVERRIDES}: substation_new_Vmax[s] >= 0; +check {(t,s) in SUBSTATIONS: s in BOUND_OVERRIDES}: substation_new_Vmin[s] < substation_new_Vmax[s]; + + +############################################################################### +# Controls for shunts decision +############################################################################### +# param_shunts.txt +# All shunts are considered fixed to their value in ampl_network_shunts.txt (set and parameters based on SHUNT above) +# Only shunts listed here will be changed by this reactive opf +set PARAM_SHUNT dimen 1 default {}; +param param_shunt_id{PARAM_SHUNT} symbolic; +check {(t,s,n) in SHUNT: s in PARAM_SHUNT}: shunt_id[t,s,n] == param_shunt_id[s]; + + +############################################################################### +# Controls for reactive power of generating units +############################################################################### +# param_generators_reactive.txt +# All units are considered with variable Q, within bounds. +# Only units listed in this file will be considered with fixed reactive power value +#"num" "id" +set PARAM_UNIT_FIXQ dimen 1 default {}; +param param_unit_fixq_id{PARAM_UNIT_FIXQ} symbolic; +check {(t,g,n) in UNIT: g in PARAM_UNIT_FIXQ}: unit_id[t,g,n] == param_unit_fixq_id[g]; + + +############################################################################### +# Controls for transformers +############################################################################### +# param_transformers.txt +# All transformers are considered with fixed ratio +# Only transformers listed in this file will be considered with variable ratio value +#"num" "id" +set PARAM_TRANSFORMERS_RATIO_VARIABLE dimen 1 default {}; +param param_transformers_ratio_variable_id{PARAM_TRANSFORMERS_RATIO_VARIABLE} symbolic; +check {(t,qq,m,n) in BRANCH: qq in PARAM_TRANSFORMERS_RATIO_VARIABLE}: branch_id[t,qq,m,n] == param_transformers_ratio_variable_id[qq]; + + +############################################################################### +# Buses with reactive slacks +############################################################################### +# param_buses_with_reactive_slack.txt +# If buses_with_reactive_slacks == "CONFIGURED" then only buses listed in this file will have reactive slacks attached in ACOPF +#"num" "id" +set PARAM_BUSES_WITH_REACTIVE_SLACK dimen 1 default {}; +param param_buses_with_reactive_slack_id{PARAM_BUSES_WITH_REACTIVE_SLACK} symbolic; +check {(t,n) in BUS: n in PARAM_BUSES_WITH_REACTIVE_SLACK}: bus_id[t,n] == param_buses_with_reactive_slack_id[n]; \ No newline at end of file diff --git a/open-reac/src/main/resources/openreac/reactiveopf.dat b/open-reac/src/main/resources/openreac/reactiveopf.dat index b1c52df1..7bb546ac 100644 --- a/open-reac/src/main/resources/openreac/reactiveopf.dat +++ b/open-reac/src/main/resources/openreac/reactiveopf.dat @@ -1,94 +1,95 @@ -############################################################################### -# -# Copyright (c) 2022 2023, 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/. -# -############################################################################### - -############################################################################### -# Reactive OPF -# Author: Jean Maeght 2022 2023 -# Author: Manuel Ruiz 2023 2024 -############################################################################### - -data; - -# ampl_network_substations.txt -#"variant" "num" "horizon" "reference date distance (minutes)" "nomV (KV)" "minV (pu)" "maxV (pu)" "fault" "curative" "country" "id" "description" -param: SUBSTATIONS: substation_horizon substation_fodist substation_Vnomi substation_Vmin substation_Vmax substation_fault substation_curative substation_country substation_id substation_description := include ampl_network_substations.txt; - -# ampl_network_buses.txt -#"variant" "num" "substation" "cc" "v (pu)" "theta (rad)" "p (MW)" "q (MVar)" "fault" "curative" "id" -param: BUS: bus_substation bus_CC bus_V0 bus_angl0 bus_injA bus_injR bus_fault bus_curative bus_id := include ampl_network_buses.txt; - -# ampl_network_generators.txt -#"variant" "num" "bus" "con. bus" "substation" "minP (MW)" "maxP (MW)" "minQmaxP (MVar)" "minQ0 (MVar)" "minQminP (MVar)" "maxQmaxP (MVar)" "maxQ0 (MVar)" "maxQminP (MVar)" "v regul." "targetV (pu)" "targetP (MW)" "targetQ (MVar)" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" -param: UNIT: unit_potentialbus unit_substation unit_Pmin unit_Pmax unit_qP unit_qp0 unit_qp unit_QP unit_Qp0 unit_Qp unit_vregul unit_Vc unit_Pc unit_Qc unit_fault unit_curative unit_id unit_name unit_P0 unit_Q0 := include ampl_network_generators.txt; - -# ampl_network_loads.txt -#"variant" "num" "bus" "substation" "p (MW)" "q (MVar)" "fault" "curative" "id" "description" "p (MW)" "q (MVar)" -param: LOAD: load_substation load_PFix load_QFix load_fault load_curative load_id load_name load_p load_q := include ampl_network_loads.txt; - -# ampl_network_shunts.txt -#"variant" "num" "bus" "con. bus" "substation" "minB (pu)" "maxB (pu)" "inter. points" "b (pu)" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" "sections count" -param: SHUNT: shunt_possiblebus shunt_substation shunt_valmin shunt_valmax shunt_interPoints shunt_valnom shunt_fault shunt_curative shunt_id shunt_nom shunt_P0 shunt_Q0 shunt_sections_count := include ampl_network_shunts.txt; - -# ampl_network_static_var_compensators.txt -#"variant" "num" "bus" "con. bus" "substation" "minB (pu)" "maxB (pu)" "v regul." "targetV (pu)" "targetQ (MVar)" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" -param: SVC: svc_possiblebus svc_substation svc_bmin svc_bmax svc_vregul svc_targetV svc_targetQ svc_fault svc_curative svc_id svc_description svc_P0 svc_Q0 := include ampl_network_static_var_compensators.txt; - -# ampl_network_batteries.txt -#"variant" "num" "bus" "con. bus" "substation" "p0 (MW)" "q0 (MW)" "minP (MW)" "maxP (MW)" "minQmaxP (MVar)" "minQ0 (MVar)" "minQminP (MVar)" "maxQmaxP (MVar)" "maxQ0 (MVar)" "maxQminP (MVar)" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" -param: BATTERY: battery_possiblebus battery_substation battery_p0 battery_q0 battery_Pmin battery_Pmax battery_qP battery_qp0 battery_qp battery_QP battery_Qp0 battery_Qp battery_fault battery_curative battery_id battery_name battery_P0 battery_Q0 := include ampl_network_batteries.txt; - -# ampl_network_tct.txt -#"variant" "num" "tap" "var ratio" "x (pu)" "angle (rad)" "fault" "curative" -param: TAPS: tap_ratio tap_x tap_angle tap_fault tap_curative := include ampl_network_tct.txt; - -# ampl_network_rtc.txt -#"num" "tap" "table" "onLoad" "targetV" "fault" "curative" "id" -#param: REGL: regl_tap0 regl_table regl_onLoad regl_V regl_fault regl_curative regl_id := include ampl_network_rtc.txt; -param: REGL: regl_tap0 regl_table regl_onLoad regl_V regl_fault regl_id := include ampl_network_rtc.txt; - -# ampl_network_ptc.txt -#"num" "tap" "table" "fault" "curative" "id" -param: DEPH: deph_tap0 deph_table deph_fault deph_curative deph_id := include ampl_network_ptc.txt; - -# ampl_network_vsc_converter_stations.txt -#"variant" "num" "bus" "con. bus" "substation" "minP (MW)" "maxP (MW)" "minQmaxP (MVar)" "minQ0 (MVar)" "minQminP (MVar)" "maxQmaxP (MVar)" "maxQ0 (MVar)" "maxQminP (MVar)" "v regul." "targetV (pu)" "targetQ (MVar)" "lossFactor (%PDC)" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" -param: VSCCONV: vscconv_possiblebus vscconv_substation vscconv_Pmin vscconv_Pmax vscconv_qP vscconv_qp0 vscconv_qp vscconv_QP vscconv_Qp0 vscconv_Qp vscconv_vregul vscconv_targetV vscconv_targetQ vscconv_lossFactor vscconv_fault vscconv_curative vscconv_id vscconv_description vscconv_P0 vscconv_Q0 := include ampl_network_vsc_converter_stations.txt; - -# ampl_network_lcc_converter_stations.txt -#"variant" "num" "bus" "con. bus" "substation" "lossFactor (%PDC)" "powerFactor" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" -param: LCCCONV: lccconv_possiblebus lccconv_substation lccconv_loss_factor lccconv_power_factor lccconv_fault lccconv_curative lccconv_id lccconv_description lccconv_P0 lccconv_Q0 := include ampl_network_lcc_converter_stations.txt; - -#ampl_network_hvdc.txt -#"variant" "num" "type" "converterStation1" "converterStation2" "r (ohm)" "nomV (KV)" "convertersMode" "targetP (MW)" "maxP (MW)" "fault" "curative" "id" "description" -#ampl_network_hvdc.txt -param: HVDC: hvdc_type hvdc_conv1 hvdc_conv2 hvdc_r hvdc_Vnom hvdc_convertersMode hvdc_targetP hvdc_Pmax hvdc_fault hvdc_curative hvdc_id hvdc_description := include ampl_network_hvdc.txt; - -# ampl_network_branches.txt -#"variant" "num" "bus1" "bus2" "3wt num" "sub.1" "sub.2" "r (pu)" "x (pu)" "g1 (pu)" "g2 (pu)" "b1 (pu)" "b2 (pu)" "cst ratio (pu)" "ratio tc" "phase tc" "p1 (MW)" "p2 (MW)" "q1 (MVar)" "q2 (MVar)" "patl1 (A)" "patl2 (A)" "merged" "fault" "curative" "id" "description" -param: BRANCH: branch_3wt branch_subor branch_subex branch_R branch_X branch_Gor branch_Gex branch_Bor branch_Bex branch_cstratio branch_ptrRegl branch_ptrDeph branch_Por branch_Pex branch_Qor branch_Qex branch_patl1 branch_patl2 branch_merged branch_fault branch_curative branch_id branch_name := include ampl_network_branches.txt; - -# ampl_network_substations_override.txt -#"num" "minV (pu)" "maxV (pu)" "id" -param: BOUND_OVERRIDES: substation_new_Vmin, substation_new_Vmax, substation_new_checkId := include ampl_network_substations_override.txt; - -# param_shunts.txt -#"num" "id" -param: PARAM_SHUNT: param_shunt_id := include param_shunts.txt; - -# param_generators_reactive.txt -#"num" "id" -param: PARAM_UNIT_FIXQ: param_unit_fixq_id := include param_generators_reactive.txt; - -# param_transformers.txt -#"num" "id" -param: PARAM_TRANSFORMERS_RATIO_VARIABLE: param_transformers_ratio_variable_id := include param_transformers.txt; - -# param_buses_with_reactive_slack.txt -#"num" "id" -param: PARAM_BUSES_WITH_REACTIVE_SLACK: param_buses_with_reactive_slack_id := include param_buses_with_reactive_slack.txt; +############################################################################### +# +# 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 +############################################################################### + +data; + +# ampl_network_substations.txt +#"variant" "num" "horizon" "reference date distance (minutes)" "nomV (KV)" "minV (pu)" "maxV (pu)" "fault" "curative" "country" "id" "description" +param: SUBSTATIONS: substation_horizon substation_fodist substation_Vnomi substation_Vmin substation_Vmax substation_fault substation_curative substation_country substation_id substation_description := include ampl_network_substations.txt; + +# ampl_network_buses.txt +#"variant" "num" "substation" "cc" "v (pu)" "theta (rad)" "p (MW)" "q (MVar)" "fault" "curative" "id" +param: BUS: bus_substation bus_CC bus_V0 bus_angl0 bus_injA bus_injR bus_fault bus_curative bus_id := include ampl_network_buses.txt; + +# ampl_network_generators.txt +#"variant" "num" "bus" "con. bus" "substation" "minP (MW)" "maxP (MW)" "minQmaxP (MVar)" "minQ0 (MVar)" "minQminP (MVar)" "maxQmaxP (MVar)" "maxQ0 (MVar)" "maxQminP (MVar)" "v regul." "targetV (pu)" "targetP (MW)" "targetQ (MVar)" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" +param: UNIT: unit_potentialbus unit_substation unit_Pmin unit_Pmax unit_qP unit_qp0 unit_qp unit_QP unit_Qp0 unit_Qp unit_vregul unit_Vc unit_Pc unit_Qc unit_fault unit_curative unit_id unit_name unit_P0 unit_Q0 := include ampl_network_generators.txt; + +# ampl_network_loads.txt +#"variant" "num" "bus" "substation" "p (MW)" "q (MVar)" "fault" "curative" "id" "description" "p (MW)" "q (MVar)" +param: LOAD: load_substation load_PFix load_QFix load_fault load_curative load_id load_name load_p load_q := include ampl_network_loads.txt; + +# ampl_network_shunts.txt +#"variant" "num" "bus" "con. bus" "substation" "minB (pu)" "maxB (pu)" "inter. points" "b (pu)" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" "sections count" +param: SHUNT: shunt_possiblebus shunt_substation shunt_valmin shunt_valmax shunt_interPoints shunt_valnom shunt_fault shunt_curative shunt_id shunt_nom shunt_P0 shunt_Q0 shunt_sections_count := include ampl_network_shunts.txt; + +# ampl_network_static_var_compensators.txt +#"variant" "num" "bus" "con. bus" "substation" "minB (pu)" "maxB (pu)" "v regul." "targetV (pu)" "targetQ (MVar)" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" +param: SVC: svc_possiblebus svc_substation svc_bmin svc_bmax svc_vregul svc_targetV svc_targetQ svc_fault svc_curative svc_id svc_description svc_P0 svc_Q0 := include ampl_network_static_var_compensators.txt; + +# ampl_network_batteries.txt +#"variant" "num" "bus" "con. bus" "substation" "p0 (MW)" "q0 (MW)" "minP (MW)" "maxP (MW)" "minQmaxP (MVar)" "minQ0 (MVar)" "minQminP (MVar)" "maxQmaxP (MVar)" "maxQ0 (MVar)" "maxQminP (MVar)" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" +param: BATTERY: battery_possiblebus battery_substation battery_p0 battery_q0 battery_Pmin battery_Pmax battery_qP battery_qp0 battery_qp battery_QP battery_Qp0 battery_Qp battery_fault battery_curative battery_id battery_name battery_P0 battery_Q0 := include ampl_network_batteries.txt; + +# ampl_network_tct.txt +#"variant" "num" "tap" "var ratio" "x (pu)" "angle (rad)" "fault" "curative" +param: TAPS: tap_ratio tap_x tap_angle tap_fault tap_curative := include ampl_network_tct.txt; + +# ampl_network_rtc.txt +#"num" "tap" "table" "onLoad" "targetV" "fault" "curative" "id" +#param: REGL: regl_tap0 regl_table regl_onLoad regl_V regl_fault regl_curative regl_id := include ampl_network_rtc.txt; +param: REGL: regl_tap0 regl_table regl_onLoad regl_V regl_fault regl_id := include ampl_network_rtc.txt; + +# ampl_network_ptc.txt +#"num" "tap" "table" "fault" "curative" "id" +param: DEPH: deph_tap0 deph_table deph_fault deph_curative deph_id := include ampl_network_ptc.txt; + +# ampl_network_vsc_converter_stations.txt +#"variant" "num" "bus" "con. bus" "substation" "minP (MW)" "maxP (MW)" "minQmaxP (MVar)" "minQ0 (MVar)" "minQminP (MVar)" "maxQmaxP (MVar)" "maxQ0 (MVar)" "maxQminP (MVar)" "v regul." "targetV (pu)" "targetQ (MVar)" "lossFactor (%PDC)" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" +param: VSCCONV: vscconv_possiblebus vscconv_substation vscconv_Pmin vscconv_Pmax vscconv_qP vscconv_qp0 vscconv_qp vscconv_QP vscconv_Qp0 vscconv_Qp vscconv_vregul vscconv_targetV vscconv_targetQ vscconv_lossFactor vscconv_fault vscconv_curative vscconv_id vscconv_description vscconv_P0 vscconv_Q0 := include ampl_network_vsc_converter_stations.txt; + +# ampl_network_lcc_converter_stations.txt +#"variant" "num" "bus" "con. bus" "substation" "lossFactor (%PDC)" "powerFactor" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" +param: LCCCONV: lccconv_possiblebus lccconv_substation lccconv_loss_factor lccconv_power_factor lccconv_fault lccconv_curative lccconv_id lccconv_description lccconv_P0 lccconv_Q0 := include ampl_network_lcc_converter_stations.txt; + +#ampl_network_hvdc.txt +#"variant" "num" "type" "converterStation1" "converterStation2" "r (ohm)" "nomV (KV)" "convertersMode" "targetP (MW)" "maxP (MW)" "fault" "curative" "id" "description" +#ampl_network_hvdc.txt +param: HVDC: hvdc_type hvdc_conv1 hvdc_conv2 hvdc_r hvdc_Vnom hvdc_convertersMode hvdc_targetP hvdc_Pmax hvdc_fault hvdc_curative hvdc_id hvdc_description := include ampl_network_hvdc.txt; + +# ampl_network_branches.txt +#"variant" "num" "bus1" "bus2" "3wt num" "sub.1" "sub.2" "r (pu)" "x (pu)" "g1 (pu)" "g2 (pu)" "b1 (pu)" "b2 (pu)" "cst ratio (pu)" "ratio tc" "phase tc" "p1 (MW)" "p2 (MW)" "q1 (MVar)" "q2 (MVar)" "patl1 (A)" "patl2 (A)" "merged" "fault" "curative" "id" "description" +param: BRANCH: branch_3wt branch_subor branch_subex branch_R branch_X branch_Gor branch_Gex branch_Bor branch_Bex branch_cstratio branch_ptrRegl branch_ptrDeph branch_Por branch_Pex branch_Qor branch_Qex branch_patl1 branch_patl2 branch_merged branch_fault branch_curative branch_id branch_name := include ampl_network_branches.txt; + +# ampl_network_substations_override.txt +#"num" "minV (pu)" "maxV (pu)" "id" +param: BOUND_OVERRIDES: substation_new_Vmin, substation_new_Vmax, substation_new_checkId := include ampl_network_substations_override.txt; + +# param_shunts.txt +#"num" "id" +param: PARAM_SHUNT: param_shunt_id := include param_shunts.txt; + +# param_generators_reactive.txt +#"num" "id" +param: PARAM_UNIT_FIXQ: param_unit_fixq_id := include param_generators_reactive.txt; + +# param_transformers.txt +#"num" "id" +param: PARAM_TRANSFORMERS_RATIO_VARIABLE: param_transformers_ratio_variable_id := include param_transformers.txt; + +# param_buses_with_reactive_slack.txt +#"num" "id" +param: PARAM_BUSES_WITH_REACTIVE_SLACK: param_buses_with_reactive_slack_id := include param_buses_with_reactive_slack.txt; diff --git a/open-reac/src/main/resources/openreac/reactiveopf.mod b/open-reac/src/main/resources/openreac/reactiveopf.mod deleted file mode 100644 index df57bc3a..00000000 --- a/open-reac/src/main/resources/openreac/reactiveopf.mod +++ /dev/null @@ -1,1039 +0,0 @@ -############################################################################### -# -# Copyright (c) 2022 2023, 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/. -# -############################################################################### - -############################################################################### -# Reactive OPF -# Author: Jean Maeght 2022 2023 -# Author: Manuel Ruiz 2023 2024 -############################################################################### - - - -############################################################################### -# Substations -############################################################################### -#ampl_network_substations.txt -# [variant, substation] -# The 1st column "variant" may also be used to define time step, in case this -# PowSyBl format is used for multi-timestep OPF. This is why the letter for -# the variant is mostly 't' and not 'v' (in power system, v is for voltage). -set SUBSTATIONS dimen 2; #See this in error message? Use "ampl reactiveopf.run" instead of .mod -param substation_horizon {SUBSTATIONS} symbolic; -param substation_fodist {SUBSTATIONS}; -param substation_Vnomi {SUBSTATIONS}; # kV -param substation_Vmin {SUBSTATIONS}; # pu -param substation_Vmax {SUBSTATIONS}; # pu -param substation_fault {SUBSTATIONS}; -param substation_curative {SUBSTATIONS}; -param substation_country {SUBSTATIONS} symbolic; -param substation_id {SUBSTATIONS} symbolic; -param substation_description {SUBSTATIONS} symbolic; - - -# Check only time stamp 1 is in files -set TIME := setof{(t,s) in SUBSTATIONS}t; -check card(TIME) == 1; -check 1 in TIME; -check card({(t,s) in SUBSTATIONS: substation_Vnomi[t,s] >= epsilon_nominal_voltage}) > 1; - -# Voltage bounds -check{(t,s) in SUBSTATIONS: substation_Vmin[t,s] >= min_plausible_low_voltage_limit and substation_Vmax[t,s] >= min_plausible_low_voltage_limit}: -substation_Vmin[t,s] < substation_Vmax[t,s]; - -# Parameters min_plausible_low_voltage_limit and max_plausible_high_voltage_limit are used to force voltage to be in interval [min_plausible_low_voltage_limit;max_plausible_high_voltage_limit]. -# Default value is [0.5;1.5] although academics would use low limit equals to 0.9 or 0.95 -# Bounds below will be used for substations without bounds or with bad bounds -param minimal_voltage_lower_bound := -if card({(t,s) in SUBSTATIONS: substation_Vmin[t,s] > 0}) > 0 -then max(min_plausible_low_voltage_limit,min{(t,s) in SUBSTATIONS: substation_Vmin[t,s] > 0} substation_Vmin[t,s]) -else min_plausible_low_voltage_limit; -param maximal_voltage_upper_bound := -if card({(t,s) in SUBSTATIONS: substation_Vmin[t,s] > 0}) > 0 -then min(max_plausible_high_voltage_limit,max{(t,s) in SUBSTATIONS: substation_Vmax[t,s] > 0} substation_Vmax[t,s]) -else max_plausible_high_voltage_limit; -check minimal_voltage_lower_bound > 0; -check maximal_voltage_upper_bound > minimal_voltage_lower_bound; - - - -############################################################################### -# Overrides for voltage bounds of substations -############################################################################### -#ampl_network_substations_override.txt -set BOUND_OVERRIDES dimen 1 default {}; -param substation_new_Vmin {BOUND_OVERRIDES}; -param substation_new_Vmax {BOUND_OVERRIDES}; -param substation_new_checkId {BOUND_OVERRIDES} symbolic; - -# Consistency checks -check {(t,s) in SUBSTATIONS: s in BOUND_OVERRIDES}: substation_id[t,s] == substation_new_checkId[s]; -check {(t,s) in SUBSTATIONS: s in BOUND_OVERRIDES}: substation_new_Vmin[s] >= 0; -check {(t,s) in SUBSTATIONS: s in BOUND_OVERRIDES}: substation_new_Vmax[s] >= 0; -check {(t,s) in SUBSTATIONS: s in BOUND_OVERRIDES}: substation_new_Vmin[s] < substation_new_Vmax[s]; - - - -############################################################################### -# Voltage bounds that will really been used -############################################################################### -# Negative value for substation_Vmin or substation_Vmax means that the value is undefined -# In that case, minimal_voltage_lower_bound or maximal_voltage_upper_bound is used instead - -# Note that low and high override are taken into account only if -# substation_new_Vmin > minimal_voltage_lower_bound and substation_new_Vmax < maximal_voltage_upper_bound - -param voltage_lower_bound{(t,s) in SUBSTATIONS} := - max( minimal_voltage_lower_bound, - if s in BOUND_OVERRIDES then substation_new_Vmin[s] else substation_Vmin[t,s] - ); - -param voltage_upper_bound{(t,s) in SUBSTATIONS} := - if s in BOUND_OVERRIDES and substation_new_Vmax[s] <= voltage_lower_bound[t,s] then maximal_voltage_upper_bound - else if s in BOUND_OVERRIDES then min(maximal_voltage_upper_bound,substation_new_Vmax[s]) - else if substation_Vmax[t,s] <= voltage_lower_bound[t,s] then maximal_voltage_upper_bound - else min(maximal_voltage_upper_bound,substation_Vmax[t,s]); - -check {(t,s) in SUBSTATIONS}: voltage_lower_bound[t,s] < voltage_upper_bound[t,s]; - - - -############################################################################### -# Buses -############################################################################### -# ampl_network_buses.txt -set BUS dimen 2 ; # [variant, bus] -param bus_substation{BUS} integer; -param bus_CC {BUS} integer; # num of connex component. Computation only in CC number 0 (=main connex component) -param bus_V0 {BUS}; -param bus_angl0 {BUS}; -param bus_injA {BUS}; -param bus_injR {BUS}; -param bus_fault {BUS}; -param bus_curative {BUS}; -param bus_id {BUS} symbolic; - -# Consistency checks -check{(t,n) in BUS}: t in TIME; -check{(t,n) in BUS}: n >= -1; -check{(t,n) in BUS}: (t,bus_substation[t,n]) in SUBSTATIONS; - -param null_phase_bus; - - - -############################################################################### -# Generating units -############################################################################### -# ampl_network_generators.txt - -set UNIT dimen 3; # [variant, unit, bus] -param unit_potentialbus{UNIT} integer; -param unit_substation {UNIT} integer; -param unit_Pmin {UNIT}; -param unit_Pmax {UNIT}; -param unit_qP {UNIT}; -param unit_qp0 {UNIT}; -param unit_qp {UNIT}; -param unit_QP {UNIT}; -param unit_Qp0 {UNIT}; -param unit_Qp {UNIT}; -param unit_vregul {UNIT} symbolic; # Does unit do voltage regulation, or PQ bus? -param unit_Vc {UNIT}; # Voltage set point (in case of voltage regulation) -param unit_Pc {UNIT}; # Active power set point -param unit_Qc {UNIT}; # Rective power set point (in case no voltage regulation) -param unit_fault {UNIT}; -param unit_curative{UNIT}; -param unit_id {UNIT} symbolic; -param unit_name {UNIT} symbolic; # description -param unit_P0 {UNIT}; # Initial value of P (if relevant) -param unit_Q0 {UNIT}; # Initial value of Q (if relevant) - -# -# Consistency -# -check {(t,g,n) in UNIT}: t in TIME; -check {(t,g,n) in UNIT}: (t,n) in BUS or n==-1; -check {(t,g,n) in UNIT}: (t,unit_substation[t,g,n]) in SUBSTATIONS; -check {(t,g,n) in UNIT}: unit_Pmax[t,g,n] >= -Pnull; -check {(t,g,n) in UNIT}: unit_Pmax[t,g,n] >= unit_Pmin[t,g,n]; -# Checks below are useless since values will be corrected for units in UNITON -#check {(t,g,n) in UNIT}: unit_Qp[t,g,n] >= unit_qp[t,g,n]; -#check {(t,g,n) in UNIT}: unit_QP[t,g,n] >= unit_qP[t,g,n] ; - -# Global inital losses_ratio: value of (P-C-H)/(C+H) in data files -# Value is 0 if no losses -# Value 0.02 means % of losses -param global_initial_losses_ratio default 0.02; # Typical value value for transmission - - - -############################################################################### -# Loads -############################################################################### -# ampl_network_loads.txt - -set LOAD dimen 3; # [variant, load, bus] -param load_substation{LOAD} integer; -param load_PFix {LOAD}; -param load_QFix {LOAD}; -param load_fault {LOAD}; -param load_curative {LOAD}; -param load_id {LOAD} symbolic; -param load_name {LOAD} symbolic; -param load_p {LOAD}; -param load_q {LOAD}; - -# Consistency checks -check {(t,c,n) in LOAD}: t in TIME; -check {(t,c,n) in LOAD}: (t,n) in BUS or n==-1; -check {(t,c,n) in LOAD}: (t,load_substation[t,c,n]) in SUBSTATIONS; - - - -############################################################################### -# Shunts -############################################################################### -# ampl_network_shunts.txt - -set SHUNT dimen 3; # [variant, shunt, bus] -param shunt_possiblebus {SHUNT} integer; -param shunt_substation {SHUNT} integer; -param shunt_valmin {SHUNT}; # Susceptance B in p.u.: compute B*100*V^2 to get MVAr -param shunt_valmax {SHUNT}; # Susceptance B in p.u.: compute B*100*V^2 to get MVAr -param shunt_interPoints {SHUNT}; # Intermediate points: if there are 0 interPoint, it means that either min or max are possible -param shunt_valnom {SHUNT}; # Susceptance B in p.u.: compute B*100*V^2 to get MVAr. If value >= 0, this means reactive power generation -param shunt_fault {SHUNT}; -param shunt_curative {SHUNT}; -param shunt_id {SHUNT} symbolic; -param shunt_nom {SHUNT} symbolic; -param shunt_P0 {SHUNT}; -param shunt_Q0 {SHUNT}; # Reactive power load: valnom >= 0 means Q0 <= 0 -param shunt_sections_count{SHUNT} integer; - -# Consistency checks -check {(t,s,n) in SHUNT}: (t,n) in BUS or n==-1; -check {(t,s,n) in SHUNT}: n==-1 or shunt_possiblebus[t,s,n]==n; -check {(t,s,-1) in SHUNT}: (t,shunt_possiblebus[t,s,-1]) in BUS or shunt_possiblebus[t,s,-1]==-1; -check {(t,s,n) in SHUNT}: (t,shunt_substation[t,s,n]) in SUBSTATIONS; - -# Case of a reactance : check valmin < 0 and valmax=0 -check {(t,s,n) in SHUNT}: shunt_valmin[1,s,n] <= 0; -check {(t,s,n) in SHUNT : shunt_valmin[1,s,n] <= -Pnull / base100MVA}: shunt_valmax[1,s,n] <= Pnull / base100MVA; -# Case of a condo : check valmin = 0 and valmax>0 -check {(t,s,n) in SHUNT}: shunt_valmax[1,s,n] >= 0; -check {(t,s,n) in SHUNT : shunt_valmax[1,s,n] >= Pnull / base100MVA}: shunt_valmin[1,s,n] >= -Pnull / base100MVA; - - - -############################################################################### -# Static Var Compensator -############################################################################### -# ampl_network_static_var_compensators.txt - -set SVC dimen 3; # [variant, svc, bus] -param svc_possiblebus {SVC} integer; -param svc_substation {SVC} integer; -param svc_bmin {SVC}; # Susceptance B in p.u.: compute B*100*V^2 to get MVAr -param svc_bmax {SVC}; # Susceptance B in p.u.: compute B*100*V^2 to get MVAr -param svc_vregul {SVC} symbolic; # true if SVC is in voltage regulation mode -param svc_targetV {SVC}; # Voltage target for voltage regulation mode -param svc_targetQ {SVC}; -param svc_fault {SVC}; -param svc_curative {SVC}; -param svc_id {SVC} symbolic; -param svc_description {SVC} symbolic; -param svc_P0 {SVC}; -param svc_Q0 {SVC}; # Fixed value to be used if SVC is not in voltage regulation mode. If value >= 0, this means reactive power generation - -# Consistency checks -check {(t,svc,n) in SVC}: (t,n) in BUS or n==-1; -check {(t,svc,n) in SVC}: (t,svc_substation[t,svc,n]) in SUBSTATIONS; - - - -############################################################################### -# Batteries -############################################################################### -# ampl_network_batteries.txt -set BATTERY dimen 3; # [variant, battery, bus] -param battery_possiblebus{BATTERY} integer; -param battery_substation {BATTERY} integer; -param battery_p0 {BATTERY}; # current P of the battery, P0 <= 0 if batterie is charging -param battery_q0 {BATTERY}; -param battery_Pmin {BATTERY}; -param battery_Pmax {BATTERY}; -param battery_qP {BATTERY}; -param battery_qp0 {BATTERY}; -param battery_qp {BATTERY}; -param battery_QP {BATTERY}; -param battery_Qp0 {BATTERY}; -param battery_Qp {BATTERY}; -param battery_fault {BATTERY}; -param battery_curative{BATTERY}; -param battery_id {BATTERY} symbolic; -param battery_name {BATTERY} symbolic; -param battery_P0 {BATTERY}; -param battery_Q0 {BATTERY}; - -# Consistency checks -check {(t,b,n) in BATTERY} : (t,n) in BUS union {(t,-1)}; -check {(t,b,n) in BATTERY} : (t,battery_substation[t,b,n]) in SUBSTATIONS; -check {(t,b,n) in BATTERY: (t,n) in BUS} : battery_substation[t,b,n] == bus_substation[t,n]; -check {(t,b,n) in BATTERY} : battery_Pmin[t,b,n] <= battery_Pmax[t,b,n] ; -check {(t,b,n) in BATTERY} : abs(battery_p0[t,b,n]) <= PQmax; -check {(t,b,n) in BATTERY} : abs(battery_q0[t,b,n]) <= PQmax; - - - -############################################################################### -# Tables of taps -############################################################################### -# ampl_network_tct.txt -# Data in these tables are used for both ratio tap changers and phase taps changers - -set TAPS dimen 3; # [variant, num, tap] -param tap_ratio {TAPS}; -param tap_x {TAPS}; -param tap_angle {TAPS}; -param tap_fault {TAPS}; -param tap_curative {TAPS}; - -# Created data -set TAPTABLES := setof {(t,tab,tap) in TAPS} tab; - -# Consistency checks -check {(t,tab,tap) in TAPS}: tab > 0 && tap >= 0; - - - -############################################################################### -# Ratio tap changers -############################################################################### -# ampl_network_rtc.txt - -param regl_V_missing := -99999.0; -set REGL dimen 2; # [variant, num] -param regl_tap0 {REGL} integer; -param regl_table {REGL} integer; -param regl_onLoad {REGL} symbolic; -param regl_V {REGL} ; -param regl_fault {REGL}; -param regl_curative {REGL}; -param regl_id {REGL} symbolic; - -# Consistency checks -check {(t,r) in REGL}: regl_table[t,r] in TAPTABLES; -check {(t,r) in REGL}: (t,regl_table[t,r], regl_tap0[t,r]) in TAPS; - -param regl_ratio_min{(t,r) in REGL} := min{(t,regl_table[t,r],tap) in TAPS} tap_ratio[t,regl_table[t,r],tap]; -param regl_ratio_max{(t,r) in REGL} := max{(t,regl_table[t,r],tap) in TAPS} tap_ratio[t,regl_table[t,r],tap]; - - - -############################################################################### -# Phase tap changers -############################################################################### -# ampl_network_ptc.txt - -set DEPH dimen 2; # [variant, num] -param deph_tap0 {DEPH} integer; -param deph_table {DEPH} integer; -param deph_fault {DEPH}; -param deph_curative {DEPH}; -param deph_id {DEPH} symbolic; - -# Consistency checks -check {(t,d) in DEPH}: deph_table[t,d] in TAPTABLES; -check {(t,d) in DEPH}: (t,deph_table[t,d], deph_tap0[t,d]) in TAPS; - - - -############################################################################### -# Branches -############################################################################### -# ampl_network_branches.txt - -set BRANCH dimen 4; # [variant, branch, bus1, bus2] -param branch_subor {BRANCH} integer; -param branch_subex {BRANCH} integer; -param branch_3wt {BRANCH}; -param branch_R {BRANCH}; -param branch_X {BRANCH}; -param branch_Gor {BRANCH}; -param branch_Gex {BRANCH}; -param branch_Bor {BRANCH}; -param branch_Bex {BRANCH}; -param branch_cstratio {BRANCH}; # fixed ratio -param branch_ptrRegl {BRANCH} integer; # Number of ratio tap changer -param branch_ptrDeph {BRANCH} integer; # Number of phase tap changer -param branch_Por {BRANCH}; -param branch_Pex {BRANCH}; -param branch_Qor {BRANCH}; -param branch_Qex {BRANCH}; -param branch_patl1 {BRANCH}; -param branch_patl2 {BRANCH}; -param branch_merged {BRANCH} symbolic; -param branch_fault {BRANCH}; -param branch_curative {BRANCH}; -param branch_id {BRANCH} symbolic; -param branch_name {BRANCH} symbolic; - - -# Consistency checks -check {(t,qq,m,n) in BRANCH}: t in TIME; -check {(t,qq,m,n) in BRANCH}: - ( (t,m) in BUS or m==-1 ) - && ( (t,n) in BUS or n==-1 ) - && ( m != n || m == -1 ) # no problem if m==n==-1 - && qq > 0 - && (t,branch_subor[t,qq,m,n]) in SUBSTATIONS - && (t,branch_subex[t,qq,m,n]) in SUBSTATIONS; -check {(t,qq,m,n) in BRANCH}: (t,branch_ptrRegl[t,qq,m,n]) in REGL union {(1,-1)}; -check {(t,qq,m,n) in BRANCH}: (t,branch_ptrDeph[t,qq,m,n]) in DEPH union {(1,-1)}; - -# Admittances -#param branch_G {(t,qq,m,n) in BRANCH} = +branch_R[t,qq,m,n]/(branch_R[t,qq,m,n]^2+branch_X[t,qq,m,n]^2); -#param branch_B {(t,qq,m,n) in BRANCH} = -branch_X[t,qq,m,n]/(branch_R[t,qq,m,n]^2+branch_X[t,qq,m,n]^2); - - - -############################################################################### -# VSC converter station data -############################################################################### -# ampl_network_vsc_converter_stations.txt - -set VSCCONV dimen 3; # [variant, num, bus] -param vscconv_possiblebus {VSCCONV} integer; -param vscconv_substation {VSCCONV} integer; -param vscconv_Pmin {VSCCONV}; -param vscconv_Pmax {VSCCONV}; -param vscconv_qP {VSCCONV}; -param vscconv_qp0 {VSCCONV}; -param vscconv_qp {VSCCONV}; -param vscconv_QP {VSCCONV}; -param vscconv_Qp0 {VSCCONV}; -param vscconv_Qp {VSCCONV}; -param vscconv_vregul {VSCCONV} symbolic; -param vscconv_targetV {VSCCONV}; -param vscconv_targetQ {VSCCONV}; -param vscconv_lossFactor {VSCCONV}; -param vscconv_fault {VSCCONV}; -param vscconv_curative {VSCCONV}; -param vscconv_id {VSCCONV} symbolic; -param vscconv_description {VSCCONV} symbolic; -param vscconv_P0 {VSCCONV}; # P0 >= 0 means active power going from AC grid to DC line (homogeneous to a load) -param vscconv_Q0 {VSCCONV}; - -# Consistency checks -check {(t,cs,n) in VSCCONV}: (t,n) in BUS union {(1,-1)}; -check {(t,cs,n) in VSCCONV}: (t,vscconv_substation[t,cs,n]) in SUBSTATIONS; -check {(t,cs,n) in VSCCONV}: vscconv_Pmin[t,cs,n] <= vscconv_Pmax[t,cs,n]; -check {(t,cs,n) in VSCCONV}: vscconv_qp[t,cs,n] <= vscconv_Qp[t,cs,n]; -check {(t,cs,n) in VSCCONV}: vscconv_qp0[t,cs,n] <= vscconv_Qp0[t,cs,n]; -check {(t,cs,n) in VSCCONV}: vscconv_qP[t,cs,n] <= vscconv_QP[t,cs,n]; - - - -############################################################################### -# LCC converter station data -############################################################################### -# ampl_network_lcc_converter_stations.txt -#"variant" "num" "bus" "con. bus" "substation" "lossFactor (%PDC)" "powerFactor" "fault" "curative" "id" "description" "P (MW)" "Q (MVar)" - -set LCCCONV dimen 3; # [variant, num, bus] -param lccconv_possiblebus {LCCCONV} integer; -param lccconv_substation {LCCCONV} integer; -param lccconv_loss_factor {LCCCONV}; -param lccconv_power_factor{LCCCONV}; -param lccconv_fault {LCCCONV}; -param lccconv_curative {LCCCONV}; -param lccconv_id {LCCCONV} symbolic; -param lccconv_description {LCCCONV} symbolic; -param lccconv_P0 {LCCCONV}; -param lccconv_Q0 {LCCCONV}; - - - -############################################################################### -# HVDC -############################################################################### -# ampl_network_hvdc.txt - -set HVDC dimen 2; # [variant, num] -param hvdc_type {HVDC} integer; # 1->vscConverterStation, 2->lccConverterStation -param hvdc_conv1 {HVDC} integer; -param hvdc_conv2 {HVDC} integer; -param hvdc_r {HVDC}; -param hvdc_Vnom {HVDC}; -param hvdc_convertersMode {HVDC} symbolic; -param hvdc_targetP {HVDC}; -param hvdc_Pmax {HVDC}; -param hvdc_fault {HVDC}; -param hvdc_curative {HVDC}; -param hvdc_id {HVDC} symbolic; -param hvdc_description {HVDC} symbolic; - -# Consistency checks -check {(t,h) in HVDC}: hvdc_type[t,h] == 1 or hvdc_type[t,h] == 2; -check {(t,h) in HVDC}: hvdc_conv1[t,h] != hvdc_conv2[t,h]; -check {(t,h) in HVDC: hvdc_type[t,h] == 1}: hvdc_conv1[t,h] in setof{(t,n,bus) in VSCCONV}n; -check {(t,h) in HVDC: hvdc_type[t,h] == 1}: hvdc_conv2[t,h] in setof{(t,n,bus) in VSCCONV}n; -check {(t,h) in HVDC: hvdc_type[t,h] == 2}: hvdc_conv1[t,h] in setof{(t,n,bus) in LCCCONV}n; -check {(t,h) in HVDC: hvdc_type[t,h] == 2}: hvdc_conv2[t,h] in setof{(t,n,bus) in LCCCONV}n; -check {(t,h) in HVDC}: hvdc_Vnom[t,h] >= epsilon_nominal_voltage; -check {(t,h) in HVDC}: hvdc_convertersMode[t,h] == "SIDE_1_RECTIFIER_SIDE_2_INVERTER" or hvdc_convertersMode[t,h] == "SIDE_1_INVERTER_SIDE_2_RECTIFIER"; -check {(t,h) in HVDC}: hvdc_targetP[t,h] >= 0.0; -check {(t,h) in HVDC}: hvdc_targetP[t,h] <= hvdc_Pmax[t,h]; - - - -############################################################################### -# Controls for shunts decision -############################################################################### -# param_shunts.txt -# All shunts are considered fixed to their value in ampl_network_shunts.txt (set and parameters based on SHUNT above) -# Only shunts listed here will be changed by this reactive opf -set PARAM_SHUNT dimen 1 default {}; -param param_shunt_id{PARAM_SHUNT} symbolic; -check {(t,s,n) in SHUNT: s in PARAM_SHUNT}: shunt_id[t,s,n] == param_shunt_id[s]; - - - -############################################################################### -# Controls for reactive power of generating units -############################################################################### -# param_generators_reactive.txt -# All units are considered with variable Q, within bounds. -# Only units listed in this file will be considered with fixed reactive power value -#"num" "id" -set PARAM_UNIT_FIXQ dimen 1 default {}; -param param_unit_fixq_id{PARAM_UNIT_FIXQ} symbolic; -check {(t,g,n) in UNIT: g in PARAM_UNIT_FIXQ}: unit_id[t,g,n] == param_unit_fixq_id[g]; - - - -############################################################################### -# Controls for transformers -############################################################################### -# param_transformers.txt -# All transformers are considered with fixed ratio -# Only transformers listed in this file will be considered with variable ratio value -#"num" "id" -set PARAM_TRANSFORMERS_RATIO_VARIABLE dimen 1 default {}; -param param_transformers_ratio_variable_id{PARAM_TRANSFORMERS_RATIO_VARIABLE} symbolic; -check {(t,qq,m,n) in BRANCH: qq in PARAM_TRANSFORMERS_RATIO_VARIABLE}: branch_id[t,qq,m,n] == param_transformers_ratio_variable_id[qq]; - - -############################################################################### -# Buses with reactive slacks -############################################################################### -# param_buses_with_reactive_slack.txt -# If buses_with_reactive_slacks == "CONFIGURED" then only buses listed in this file will have reactive slacks attached in ACOPF -#"num" "id" -set PARAM_BUSES_WITH_REACTIVE_SLACK dimen 1 default {}; -param param_buses_with_reactive_slack_id{PARAM_BUSES_WITH_REACTIVE_SLACK} symbolic; -check {(t,n) in BUS: n in PARAM_BUSES_WITH_REACTIVE_SLACK}: bus_id[t,n] == param_buses_with_reactive_slack_id[n]; - - -############################################################################### -# Additional sets for equipments which are really working -############################################################################### - -# Elements in main connex component -set BUS2:= setof {(1,n) in BUS: - bus_CC[1,n] == 0 - and n >= 0 - and substation_Vnomi[1,bus_substation[1,n]] >= epsilon_nominal_voltage - } n; -set BRANCH2:= setof {(1,qq,m,n) in BRANCH: m in BUS2 and n in BUS2} (qq,m,n); - -set BUSCC dimen 1 default {}; -set BRANCHCC := {(qq,m,n) in BRANCH2: m in BUSCC and n in BUSCC}; -set LOADCC := setof {(1,c,n) in LOAD : n in BUSCC} (c,n); -set UNITCC := setof {(1,g,n) in UNIT : n in BUSCC} (g,n); -set BATTERYCC := setof {(1,b,n) in BATTERY : n in BUSCC} (b,n); - -# Busses with valid voltage value -set BUSVV := {n in BUSCC : bus_V0[1,n] >= min_plausible_low_voltage_limit}; - -# Units up and generating: -# Warning: units with Ptarget=0 are considered as out of order -set UNITON := {(g,n) in UNITCC : abs(unit_Pc[1,g,n]) >= Pnull}; - -# Branches with zero or near zero impedances -# Notice: module of Z is equal to square root of (R^2+X^2) -set BRANCHZNULL := {(qq,m,n) in BRANCHCC: branch_R[1,qq,m,n]^2+branch_X[1,qq,m,n]^2 <= Znull^2}; - -# Reactive -set SHUNTCC := {(1,s,n) in SHUNT: n in BUSCC or shunt_possiblebus[1,s,n] in BUSCC}; # We want to be able to reconnect shunts -set BRANCHCC_REGL := {(qq,m,n) in BRANCHCC diff BRANCHZNULL: branch_ptrRegl[1,qq,m,n] != -1 }; -set BRANCHCC_DEPH := {(qq,m,n) in BRANCHCC diff BRANCHZNULL: branch_ptrDeph[1,qq,m,n] != -1 }; -set SVCCC := {(1,svc,n) in SVC: n in BUSCC}; - -# -# Control parameters for shunts -# If no shunt in PARAM_SHUNT, it means that hey are all fixed -# -# Variable shunts -# Shunts wich are not connected (n=-1) but which are in PARAM_SHUNT are considered as connected to their possible bus, with variable reactance -set SHUNT_VAR := setof {(1,s,n) in SHUNT : - s in PARAM_SHUNT - and (s,n) in SHUNTCC # Remember n might be -1 if shunt_possiblebus[1,s,n] is in BUSCC - and abs(shunt_valmin[1,s,n])+abs(shunt_valmax[1,s,n]) >= Pnull / base100MVA # Useless to allow change if values are too small - } (s,shunt_possiblebus[1,s,n]); -# Shunts with fixed values -set SHUNT_FIX := setof {(1,s,n) in SHUNT: s not in PARAM_SHUNT and n in BUSCC} (s,n); -# If a shunt is not connected (n=-1) and it is not in PARAM_SHUNT, then it will not be -# reconnected by reactive opf. These shunts are not in SHUNT_VAR nor in SHUNT_FIX; they -# are simply ignored - -# -# Control parameters for SVC -# -# Simple: if regul==true then SVC is on, else it is off -set SVCON := {(svc,n) in SVCCC: svc_vregul[1,svc,n]=="true" and svc_bmin[1,svc,n]<=svc_bmax[1,svc,n]-Pnull/base100MVA}; - -# -# Control parameters for reactive power of units -# -# If unit_Qc is not consistent, then reactive power will be a variable -set UNIT_FIXQ := {(g,n) in UNITON: g in PARAM_UNIT_FIXQ and abs(unit_Qc[1,g,n])= vscconv_Pmin[t,v,n] - and vscconv_P0[t,v,n] <= vscconv_Pmax[t,v,n] - } (v,n); - -# -# LCC converter stations -# -set LCCCONVON := setof{(t,l,n) in LCCCONV: - n in BUSCC - and abs(lccconv_P0[1,l,n]) <= PQmax - and abs(lccconv_Q0[1,l,n]) <= PQmax - } (l,n); - - - -############################################################################### -# Corrected values for reactances -############################################################################### -# If in BRANCHZNULL, then set X to ZNULL -param branch_X_mod{(qq,m,n) in BRANCHCC} := - if (qq,m,n) in BRANCHZNULL then Znull - else branch_X[1,qq,m,n]; -check {(qq,m,n) in BRANCHCC}: abs(branch_X_mod[qq,m,n]) > 0; - - -############################################################################### -# Corrected values for units -############################################################################### -param corrected_unit_Pmin{UNITON} default defaultPmin; -param corrected_unit_Pmax{UNITON} default defaultPmax; -param corrected_unit_qP {UNITON} default defaultQmin; -param corrected_unit_qp {UNITON} default defaultQmin; -param corrected_unit_QP {UNITON} default defaultQmax; -param corrected_unit_Qp {UNITON} default defaultQmax; -param corrected_unit_Qmin{UNITON} default defaultQmin; -param corrected_unit_Qmax{UNITON} default defaultQmax; - - - -############################################################################### -# Maximum flows on branches -############################################################################### -param Fmax{(qq,m,n) in BRANCHCC} := - 1.732 * 0.001 - * max(substation_Vnomi[1,bus_substation[1,m]]*abs(branch_patl1[1,qq,m,n]),substation_Vnomi[1,bus_substation[1,n]]*abs(branch_patl2[1,qq,m,n])); - - - -############################################################################### -# Transformers and Phase shifter transformers parameters -############################################################################### - -# Variable reactance, depanding on tap -param branch_Xdeph{(qq,m,n) in BRANCHCC_DEPH} = tap_x[1,deph_table[1,branch_ptrDeph[1,qq,m,n]],deph_tap0[1,branch_ptrDeph[1,qq,m,n]]]; - -# Resistance variable selon la prise -# Comme on ne dispose pas de valeurs variables de R dans les tables des lois des TDs, on fait varier R proportionellement a X -param branch_Rdeph{(qq,m,n) in BRANCHCC_DEPH} = - if abs(branch_X_mod[qq,m,n]) >= Znull - then branch_R[1,qq,m,n]*branch_Xdeph[qq,m,n]/branch_X_mod[qq,m,n] - else branch_R[1,qq,m,n] - ; - -param branch_angper{(qq,m,n) in BRANCHCC} = - if (qq,m,n) in BRANCHCC_DEPH - then atan2(branch_Rdeph[qq,m,n], branch_Xdeph[qq,m,n]) - else atan2(branch_R[1,qq,m,n] , branch_X_mod[qq,m,n] ); - -param branch_admi {(qq,m,n) in BRANCHCC} = - if (qq,m,n) in BRANCHCC_DEPH - then 1./sqrt(branch_Rdeph[qq,m,n]^2 + branch_Xdeph[qq,m,n]^2 ) - else 1./sqrt(branch_R[1,qq,m,n]^2 + branch_X_mod[qq,m,n]^2 ); - -# Later in this file, a variable branch_Ror_var will be created, to replace branch_Ror when it is not variable -param branch_Ror {(qq,m,n) in BRANCHCC} = - ( if ((qq,m,n) in BRANCHCC_REGL) - then tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],regl_tap0[1,branch_ptrRegl[1,qq,m,n]]] - else 1.0 - ) - * ( if ((qq,m,n) in BRANCHCC_DEPH) - then tap_ratio[1,deph_table[1,branch_ptrDeph[1,qq,m,n]],deph_tap0[1,branch_ptrDeph[1,qq,m,n]]] - else 1.0 - ) - * (branch_cstratio[1,qq,m,n]); -param branch_Rex {(q,m,n) in BRANCHCC} = 1; # In IIDM, everything is in bus1 so ratio at bus2 is always 1 - -param branch_dephor {(qq,m,n) in BRANCHCC} = - if ((qq,m,n) in BRANCHCC_DEPH) - then tap_angle [1,deph_table[1,branch_ptrDeph[1,qq,m,n]],deph_tap0[1,branch_ptrDeph[1,qq,m,n]]] - else 0; -param branch_dephex {(qq,m,n) in BRANCHCC} = 0; # In IIDM, everything is in bus1 so dephase at bus2 is always 0 - - - - -############################################################################### -# -# List of all optimization problems which wil be solved successively -# -############################################################################### -# Variables are defined without reference to a particular optimization problem -# Constraints are to be defined with -set PROBLEM_CCOMP default {1}; -set PROBLEM_DCOPF default { }; -set PROBLEM_ACOPF default { }; -# After solving DCOPF, switch to ACOPF this way: -#let PROBLEM_CCOMP := { }; # Desactivation of CCOMP -#let PROBLEM_DCOPF := { }; # Desactivation of DCOPF -#let PROBLEM_ACOPF := {1}; # Activation of ACOPF - - - -############################################################################### -# -# Variables and contraints for connexity computation -# -############################################################################### -# Even if set BUS2 is only with busses in connex component (CC) number '0', for an OPF we -# have to do connexity computation using only AC branches, ie in only one single synchronous area. -# Indeed, HVDC branches may connect 2 synchronous areas; one might consider in that case that de grid is connex -# In our case we have to consider only buses which are connected to reference bus with AC branches -var teta_ccomputation{BUS2} >=0, <=1; -subject to ctr_null_phase_bus_cccomputation{PROBLEM_CCOMP}: teta_ccomputation[null_phase_bus] = 0; -subject to ctr_flow_cccomputation{PROBLEM_CCOMP, (qq,m,n) in BRANCH2}: teta_ccomputation[m]-teta_ccomputation[n]=0; -maximize cccomputation_objective: sum{n in BUS2} teta_ccomputation[n]; -# All busses AC-connected to null_phase_bus will have '0' as optimal value, other will have '1' - - - -############################################################################### -# -# 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 - -# 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]; - - -# -# 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] ) - ; - - - -############################################################################### -# -# Variables and contraints for ACOPF -# -############################################################################### -# Notice that some variables and constraints for DCOPF are also used for ACOPF - - -# -# Phase and modulus of voltage -# -# Complex voltage = V*exp(i*teta). (with i**2=-1) - -# Phase of voltage -var teta{BUSCC} <= teta_max, >= teta_min; -subject to ctr_null_phase_bus{PROBLEM_ACOPF}: teta[null_phase_bus] = 0; - -# Modulus of voltage -var V{n in BUSCC} - <= - if substation_Vnomi[1,bus_substation[1,n]] <= ignore_voltage_bounds then max_plausible_high_voltage_limit else - voltage_upper_bound[1,bus_substation[1,n]], - >= - if substation_Vnomi[1,bus_substation[1,n]] <= ignore_voltage_bounds then min_plausible_low_voltage_limit else - voltage_lower_bound[1,bus_substation[1,n]]; - - -# -# Generation -# -# General idea: generation is an input data, but as voltage may vary, generation may vary a little. -# Variations of generation is totally controlled by unique scalar variable alpha -# Before and after optimization, there is no waranty that P is within -# its "bounds" [corrected_unit_Pmin;corrected_unit_Pmax] -# - -# Active generation -var alpha <=1, >=-1; # If alpha==1 then all units are at Pmax -var P_bounded{(g,n) in UNITON} <= max(unit_Pc[1,g,n],corrected_unit_Pmax[g,n]), >= min(unit_Pc[1,g,n],corrected_unit_Pmin[g,n]); -# If coeff_alpha == 1 then all P are defined by the single variable alpha -# If coeff_alpha == 0 then all P are free within their respective bounds -# todo faire des tests avec les valeurs de coeff_alpha -var P{(g,n) in UNITON} = - if ( unit_Pc[1,g,n] < (corrected_unit_Pmax[g,n] - Pnull) and unit_Pc[1,g,n] > Pnull ) - then ( coeff_alpha * ( unit_Pc[1,g,n] + alpha*(corrected_unit_Pmax[g,n]- unit_Pc[1,g,n]) ) - + (1-coeff_alpha) * P_bounded[g,n] ) - else unit_Pc[1,g,n] ; - - -# -# Reactive generation -# -# todo: add trapeze or hexagone constraints for reactive power -var Q{(g,n) in UNITON} <= corrected_unit_Qmax[g,n], >= corrected_unit_Qmin[g,n]; - - -# -# Variable shunts -# -var shunt_var{(shunt,n) in SHUNT_VAR} - >= min{(1,shunt,k) in SHUNT} shunt_valmin[1,shunt,k], - <= max{(1,shunt,k) in SHUNT} shunt_valmax[1,shunt,k]; - - -# -# SVC reactive generation -# -var svc_qvar{(svc,n) in SVCON} >= svc_bmin[1,svc,n], <= svc_bmax[1,svc,n]; - - -# -# VSCCONV reactive generation -# -var vscconv_qvar{(v,n) in VSCCONVON} - >= min(vscconv_qP[1,v,n],vscconv_qp0[1,v,n],vscconv_qp[1,v,n]), - <= max(vscconv_QP[1,v,n],vscconv_Qp0[1,v,n],vscconv_Qp[1,v,n]); -# todo: add trapeze or hexagone constraints for reactive power - - -# -# Ratios of transformers -# -var branch_Ror_var{(qq,m,n) in BRANCHCC_REGL_VAR} - >= regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]], - <= regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]]; - -# -# Flows -# - -var Red_Tran_Act_Dir{(qq,m,n) in BRANCHCC } = - V[n] * branch_admi[qq,m,n] * sin(teta[m]-teta[n]+branch_dephor[qq,m,n]-branch_angper[qq,m,n]) - * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n]) - + V[m] * (branch_admi[qq,m,n]*sin(branch_angper[qq,m,n])+branch_Gor[1,qq,m,n]) - * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n])**2 - ; - -var Red_Tran_Rea_Dir{(qq,m,n) in BRANCHCC } = - - V[n] * branch_admi[qq,m,n] * cos(teta[m]-teta[n]+branch_dephor[qq,m,n]-branch_angper[qq,m,n]) - * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n]) - + V[m] * (branch_admi[qq,m,n]*cos(branch_angper[qq,m,n])-branch_Bor[1,qq,m,n]) - * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n])^2 - ; - -var Red_Tran_Act_Inv{(qq,m,n) in BRANCHCC } = - V[m] * branch_admi[qq,m,n] * sin(teta[n]-teta[m]-branch_dephor[qq,m,n]-branch_angper[qq,m,n]) - * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n]) - + V[n] * (branch_admi[qq,m,n]*sin(branch_angper[qq,m,n])+branch_Gex[1,qq,m,n]) - ; - -var Red_Tran_Rea_Inv{(qq,m,n) in BRANCHCC } = - - V[m] * branch_admi[qq,m,n] * cos(teta[n]-teta[m]-branch_dephor[qq,m,n]-branch_angper[qq,m,n]) - * (if (qq,m,n) in BRANCHCC_REGL_VAR then branch_Ror_var[qq,m,n]*branch_cstratio[1,qq,m,n] else branch_Ror[qq,m,n]) - + V[n] * (branch_admi[qq,m,n]*cos(branch_angper[qq,m,n])-branch_Bex[1,qq,m,n]) - ; - - -# -# Active Balance -# - -subject to ctr_balance_P{PROBLEM_ACOPF,k in BUSCC}: - # Flows - sum{(qq,k,n) in BRANCHCC} base100MVA * V[k] * Red_Tran_Act_Dir[qq,k,n] - + sum{(qq,m,k) in BRANCHCC} base100MVA * V[k] * Red_Tran_Act_Inv[qq,m,k] - # Generating units - - sum{(g,k) in UNITON} P[g,k] - # Batteries - - sum{(b,k) in BATTERYCC} battery_p0[1,b,k] - # Loads - + sum{(c,k) in LOADCC} load_PFix[1,c,k] # Fixed value - # VSC converters - + sum{(v,k) in VSCCONVON} vscconv_P0[1,v,k] # Fixed value - # LCC converters - + sum{(l,k) in LCCCONVON} lccconv_P0[1,l,k] # Fixed value - = 0; # No slack variables for active power. If data are really too bad, may not converge. - - -# -# Reactive Balance -# - -# Reactive balance slack variables at configured nodes -set BUSCC_SLACK := if buses_with_reactive_slacks == "ALL" then BUSCC - else if buses_with_reactive_slacks == "NO_GENERATION" then {n in BUSCC: (card{(g,n) in UNITON: (g,n) not in UNIT_FIXQ}==0 and card{(svc,n) in SVCON}==0 and card{(vscconv,n) in VSCCONVON}==0)} - else BUSCC inter PARAM_BUSES_WITH_REACTIVE_SLACK; # if = "CONFIGURED", buses given as parameter but in connex component -var slack1_shunt_B{BUSCC_SLACK} >= 0; -var slack2_shunt_B{BUSCC_SLACK} >= 0; -#subject to ctr_compl_slack_Q{PROBLEM_ACOPF,k in BUSCC_SLACK}: slack1_balance_Q[k] >= 0 complements slack2_balance_Q[k] >= 0; - -subject to ctr_balance_Q{PROBLEM_ACOPF,k in BUSCC}: - # Flows - sum{(qq,k,n) in BRANCHCC} base100MVA * V[k] * Red_Tran_Rea_Dir[qq,k,n] - + sum{(qq,m,k) in BRANCHCC} base100MVA * V[k] * Red_Tran_Rea_Inv[qq,m,k] - # Generating units - - sum{(g,k) in UNITON: (g,k) not in UNIT_FIXQ } Q[g,k] - - sum{(g,k) in UNIT_FIXQ} unit_Qc[1,g,k] - # Batteries - - sum{(b,k) in BATTERYCC} battery_q0[1,b,k] - # Loads - + sum{(c,k) in LOADCC} load_QFix[1,c,k] - # Shunts - - sum{(shunt,k) in SHUNT_FIX} base100MVA * shunt_valnom[1,shunt,k] * V[k]^2 - - sum{(shunt,k) in SHUNT_VAR} base100MVA * shunt_var[shunt,k] * V[k]^2 - # SVC - - sum{(svc,k) in SVCON} base100MVA * svc_qvar[svc,k] * V[k]^2 - # VSC converters - - sum{(v,k) in VSCCONVON} vscconv_qvar[v,k] - # LCC converters - + sum{(l,k) in LCCCONVON} lccconv_Q0[1,l,k] # Fixed value - # Slack variables - + if k in BUSCC_SLACK then - (- base100MVA * V[k]^2 * slack1_shunt_B[k] # Homogeneous to a generation of reactive power (condensator) - + base100MVA * V[k]^2 * slack2_shunt_B[k]) # homogeneous to a reactive load (self) - = 0; - - -# -# Definitions for objective function -# - -# Voltage target : ratio between Vmin and Vmax -var target_voltage_ratio = sum{n in BUSCC: substation_Vnomi[1,bus_substation[1,n]] > ignore_voltage_bounds} - ( V[n] - (1-ratio_voltage_target)*voltage_lower_bound[1,bus_substation[1,n]] + ratio_voltage_target*voltage_upper_bound[1,bus_substation[1,n]] )**2; - -# Voltage target : value V0 in input data -var target_voltage_data = sum{n in BUSVV} (V[n] - bus_V0[1,n])**2; - - -# -# Objective function and penalties -# -param penalty_invest_rea_pos := 10; -param penalty_invest_rea_neg := 10; -param penalty_units_reactive := 0.1; -param penalty_transfo_ratio := 0.1; - -param penalty_active_power_high := 1; -param penalty_active_power_low := 0.01; - -param penalty_voltage_target_high := 1; -param penalty_voltage_target_low := 0.01; - -minimize problem_acopf_objective: - sum{n in BUSCC_SLACK} ( - penalty_invest_rea_pos * base100MVA * slack1_shunt_B[n] - + penalty_invest_rea_neg * base100MVA * slack2_shunt_B[n] - ) - - # coeff_alpha == 1 : minimize sum of generation, all generating units vary with 1 unique variable alpha - # coeff_alpha == 0 : minimize sum of squared difference between target and value - + (if objective_choice==1 or objective_choice==2 then penalty_active_power_low else penalty_active_power_high) - * sum{(g,n) in UNITON} (coeff_alpha * P[g,n] + (1-coeff_alpha)*( (P[g,n]-unit_Pc[1,g,n])/max(1,abs(unit_Pc[1,g,n])) )**2 ) - - # Voltage for busses, ratio between Vmin and Vmax - + (if objective_choice==1 then penalty_voltage_target_high else penalty_voltage_target_low) - * target_voltage_ratio - - # Voltage target : value V0 in input data - + (if objective_choice==2 then penalty_voltage_target_high else penalty_voltage_target_low) - * target_voltage_data - - # Reactive power of units - + penalty_units_reactive * sum{(g,n) in UNITON} (Q[g,n]/max(1,abs(corrected_unit_Qmin[g,n]),abs(corrected_unit_Qmax[g,n])))**2 - - # Ratio of transformers - + penalty_transfo_ratio * sum{(qq,m,n) in BRANCHCC_REGL_VAR} (branch_Ror[qq,m,n]-branch_Ror_var[qq,m,n])**2 - ; - # diff --git a/open-reac/src/main/resources/openreac/reactiveopf.run b/open-reac/src/main/resources/openreac/reactiveopf.run index f69be358..4fe497ff 100644 --- a/open-reac/src/main/resources/openreac/reactiveopf.run +++ b/open-reac/src/main/resources/openreac/reactiveopf.run @@ -1,1159 +1,396 @@ -############################################################################### -# -# Copyright (c) 2022 2023, 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/. -# -############################################################################### - -############################################################################### -# Reactive OPF -# Author: Jean Maeght 2022 2023 -# Author: Manuel Ruiz 2023 2024 -############################################################################### - - - -############################################################################### -# -# General overview -# -# Goal of this reactive OPF is to propose values for all voltage and reactive -# equipment and controllers of the grid: -# - voltage set point of generating units, -# - shunts, -# - transformers ratios, -# - and maybe others... -# -# In a grid developemnt study, you decide new equipments, new generating units, -# new substations, new loads, you set values for active and reactive loads, -# you set values for active power generation and HVDC flows. -# Then if you wish to do AC powerflow simulations with N-1 analysis, you need -# all voltage and reactive set points and this reactive OPF is your solution. -# -# Notice that this reactive OPF: -# - will _not_ decide active power of generating units and HVDC branches, -# - does _not_ take into account current nor power limits on branches, -# - does really use upper and lower limits for voltage, so be carefull with them. -# -############################################################################### - - - -############################################################################### -# Controls for shunts -############################################################################### -# -# Default behavior is: all shunts are constant, fixed to their value in ampl_network_shunts.txt -# Set of shunts which can be modified and/or connected is defined in param_shunts.txt -# Among this variable shunts, if a shunt is not connected (bus==-1) but bus_possible is -# well defined, then this shunt may be used by opf -# -# *** Format of param_shunt: 2 columns #num id -# - - - -############################################################################### -# Controls for reactive power of generating units -############################################################################### -# Notice that "unit"=="generating unit"=="generator" in this code -# -# Default behavior is: all reactive power of units are variable -# If file param_generators_reactive.txt is non empty, then all unit listed in -# this file have a constant value for reactive power, equal to unit_Qc. -# This value unit_Qc is used even if out of bounds Qmin Qmax of this unit -# If unit_Qc is not consistent (larger than PQmax), then reactive power will be a variable -# -# *** Format of param_generators_reactive: 2 columns #num id -# -# (Another way to fix reactive values is also posible: set minimum and -# maximum reactive power bounds to equal value) - - - -############################################################################### -# Controls for ratios of transformers -############################################################################### -# -# Default behavior is: no ratio of transformer are variable -# If file param_transformers.txt is non empty, then all transformers listed in -# this file have a variable value. -# -# *** Format of param_transformers.txt: 2 columns #num id -# - - - -############################################################################### -# Controls for static var compensators -############################################################################### -# All SVC which are connected and svc_regul==true are variables -# No additional parameter file needed - - - -############################################################################### -# VSC converter stations -############################################################################### -# Active power P is used as a fixed load -# Voltage and reactve power are variables -# No additional parameter file needed - - - -############################################################################### -# LCC converter stations -############################################################################### -# Active power P and reactive power Q are used as a fixed values -# No additional parameter file needed - - - -############################################################################### -# Batteries -############################################################################### -# Active power battery_p0 and reactive power battery_q0 are used as a fixed values -# No additional parameter file needed - - - -############################################################################### -# Overrides for voltage bounds -############################################################################### -# In case user wants to replace voltage bounds by other values, here is an -# optional file where user may define new bounds for some (or all) substations. -# -# *** Format of ampl_network_substations_override.txt: 4 columns #"num" "minV (pu)" "maxV (pu)" "id" -# - - - -############################################################################### -# Crash indicator -# If execution of this .run ampl file terminates before writing results, -# then status CRASH is already written in indicators' file -############################################################################### -# Close any files which might have been opened previously -close; -printf "final_status CRASH\n" > reactiveopf_results_indic.txt; -close; - - - -############################################################################### -# Start -############################################################################### -# Clean parameters, variables, constraints and any former models pre-existing -reset; - -# Print date of start of calculation -param ctime_start symbolic := ctime(); -printf "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; -printf "*** Start of file reactiveopf.run at %s\n",ctime_start; - -# Global status -# Possible values : CRASH OK NOK UNKNOWN -param final_status symbolic default "UNKNOWN"; - - - -############################################################################### -# Linux or windows? -############################################################################### -param operatingSystem symbolic default "unknown"; -param nullDevice symbolic default "unknown"; # null device to avoid printing when knitro log = 0 -if length($OS) > 0 then { - let operatingSystem := "windows"; - let nullDevice := "NUL"; -} -if length($SHELL) > 0 then { - let operatingSystem := "linux"; - let nullDevice := "/dev/null"; -} - - - -############################################################################### -# Management of optional input files -############################################################################### -# AMPL is able to manage empty files; in that case, sets and parameters are well -# initialized to empty sets or tables; so the minimum we need is empty file. -# Maybe this is not the best way to manage optional parameter files... -if operatingSystem == "linux" then { - shell "if [ ! -f param_algo.txt ]; then touch param_algo.txt ;fi"; - shell "if [ ! -f param_shunts.txt ]; then touch param_shunts.txt ;fi"; - shell "if [ ! -f param_generators_reactive.txt ]; then touch param_generators_reactive.txt ;fi"; - shell "if [ ! -f param_transformers.txt ]; then touch param_transformers.txt ;fi"; - shell "if [ ! -f param_buses_with_reactive_slack.txt ]; then touch param_buses_with_reactive_slack.txt ;fi"; - shell "if [ ! -f ampl_network_substations_override.txt ]; then touch ampl_network_substations_override.txt ;fi"; - shell "chmod a+rX . * 2>/dev/null"; -} -if operatingSystem == "windows" then { - shell "if not exist param_algo.txt echo #empty > param_algo.txt"; - shell "if not exist param_shunts.txt echo #empty > param_shunts.txt"; - shell "if not exist param_generators_reactive.txt echo #empty > param_generators_reactive.txt"; - shell "if not exist param_transformers.txt echo #empty > param_transformers.txt"; - shell "if not exist param_buses_with_reactive_slack.txt echo #empty > param_buses_with_reactive_slack.txt"; - shell "if not exist ampl_network_substations_override.txt echo #empty > ampl_network_substations_override.txt"; -} -# If operating system is not linux nor windows, then these optional files are -# not optional anymore: you need to provide at least empty files - - - -############################################################################### -# -# General options -# -############################################################################### - - - -############################################################################### -# Logs, controls and associated parameters -############################################################################### - -# -# Read main algorithm controls in file -# -printf "\n** Reading algorithmic controls and parameters in file\n"; -model; -set PARAM_ALGO_KEYS; -param PARAM_ALGO_VALUES{PARAM_ALGO_KEYS} symbolic; -data; -param: PARAM_ALGO_KEYS: PARAM_ALGO_VALUES := include param_algo.txt; -model; -display PARAM_ALGO_VALUES; - -# Log level of ampl printing -set LOG_LEVELS ordered = {"ERROR", "WARNING", "INFO", "DEBUG"}; # different values of log level for ampl exec -param log_level_ampl symbolic default "INFO"; # default value of log level -if "log_level_ampl" in PARAM_ALGO_KEYS then let log_level_ampl := PARAM_ALGO_VALUES["log_level_ampl"]; - -# Sets used to print or not. A void set avoid printing -param log_index := ord0(log_level_ampl, LOG_LEVELS); -set LOG_DEBUG := if log_index >= 4 then{1} else {}; -set LOG_INFO := if log_index >= 3 then{1} else {}; -set LOG_WARNING := if log_index >= 2 then{1} else {}; -set LOG_ERROR := if log_index >= 1 then{1} else {}; -printf{LOG_INFO} "Parameter: log level of ampl := %s\n", log_level_ampl; -check log_level_ampl in LOG_LEVELS; - -# Log level of knitro printing -param log_level_knitro integer default 2; -if "log_level_knitro" in PARAM_ALGO_KEYS then let log_level_knitro := num(PARAM_ALGO_VALUES["log_level_knitro"]); -set LOG_KNITRO := if log_level_knitro >= 1 then{1} else {}; -printf{LOG_INFO} "Parameter: log level of knitro := %i\n", log_level_knitro; -check log_level_knitro in {0, 1, 2}; - -# Absolute parameter : base 100MVA. -# Never change this unless you really know what you do -param base100MVA := 100; - -# Choice of objective function -param objective_choice integer default 0; -if "objective_choice" in PARAM_ALGO_KEYS then let objective_choice := num(PARAM_ALGO_VALUES["objective_choice"]); -printf{LOG_INFO} "Parameter: choice for objective function := %Q (%s)\n",objective_choice, - if objective_choice==2 then "voltage targets are provided values" - else if objective_choice==1 then "voltage targets are Vmin+ratio*(Vmax-Vmin)" - else "active power minimization"; - -# If voltage target is ratio between Vmin and Vmax -param ratio_voltage_target default 0.5; -if "ratio_voltage_target" in PARAM_ALGO_KEYS then let ratio_voltage_target := num(PARAM_ALGO_VALUES["ratio_voltage_target"]); -check ratio_voltage_target >= 0 and ratio_voltage_target <= 1; -if objective_choice==1 -then printf{LOG_INFO} "Parameter: ratio for voltage target is := %f (%.2f%%)\n",ratio_voltage_target,ratio_voltage_target*100; - -# coeff_alpha == 1 : minimize sum of generation, all generating units vary with 1 unique variable alpha -# coeff_alpha == 0 : minimize sum of squared difference between target and value -param coeff_alpha default 1.0; -if "coeff_alpha" in PARAM_ALGO_KEYS then let coeff_alpha := num(PARAM_ALGO_VALUES["coeff_alpha"]); -printf{LOG_INFO} "Parameter: coeff_alpha to choose wether generation vary homogeneously (coeff_alpha=1) or independantly (coeff_alpha=0) is := %.2f\n",coeff_alpha; -check coeff_alpha >=0 and coeff_alpha <= 1; - -# Limit for detecting zero value for power -param Pnull default 0.01; # MW -if "Pnull" in PARAM_ALGO_KEYS then let Pnull := num(PARAM_ALGO_VALUES["Pnull"]); -printf{LOG_INFO} "Parameter: threshold to decide wether an active or reactive power value is zero Pnull:=%Q (MW or Mvar or MVA)\n",Pnull; -check Pnull > 0 and Pnull < 1; - -# Parameter for detection of branches with zero impedance -param Znull default 1e-4; -if "Znull" in PARAM_ALGO_KEYS then let Znull := num(PARAM_ALGO_VALUES["Znull"]); -printf{LOG_INFO} "Parameter: threshold to detect zero impedance branch Znull:=%Q pu\n",Znull; -check Znull > 0 and Znull < 0.1; - -# Minimum consistency value for minimum voltage in kV -# All busses with nominal voltage lower than epsilon_nominal_voltage will be ignored -# This value has to be >0 -param epsilon_nominal_voltage default 1.0; -if "epsilon_nominal_voltage" in PARAM_ALGO_KEYS then let epsilon_nominal_voltage := num(PARAM_ALGO_VALUES["epsilon_nominal_voltage"]); -printf{LOG_INFO} "Parameter: for consistency checks of minimum nominal voltages epsilon_nominal_voltage:= %Q kV\n",epsilon_nominal_voltage; -check epsilon_nominal_voltage > 0; - -# Minimum plausible value for voltage low limits in PU -# This value should be < 1 -param min_plausible_low_voltage_limit default 0.5; -if "min_plausible_low_voltage_limit" in PARAM_ALGO_KEYS then let min_plausible_low_voltage_limit := num(PARAM_ALGO_VALUES["min_plausible_low_voltage_limit"]); -printf{LOG_INFO} "Parameter: for consistency of voltage bounds, min_plausible_low_voltage_limit:= %Q pu\n",min_plausible_low_voltage_limit; -check min_plausible_low_voltage_limit > 0; - -# Maximum plausible value for voltage high limits in PU -param max_plausible_high_voltage_limit default 1.5; -if "max_plausible_high_voltage_limit" in PARAM_ALGO_KEYS then let max_plausible_high_voltage_limit := num(PARAM_ALGO_VALUES["max_plausible_high_voltage_limit"]); -printf{LOG_INFO} "Parameter: for consistency of voltage bounds, max_plausible_high_voltage_limit:= %Q pu\n",max_plausible_high_voltage_limit; -check max_plausible_high_voltage_limit > min_plausible_low_voltage_limit; - -# Ignore voltage bounds for buses with nominal voltage lower than this parameter -# For all busses with nominal voltage lower than ignore_voltage_bounds, voltage bonds will be ignored -# and replaced by [min_plausible_low_voltage_limit ; max_plausible_high_voltage_limit] -param ignore_voltage_bounds default 0; -if "ignore_voltage_bounds" in PARAM_ALGO_KEYS then let ignore_voltage_bounds := num(PARAM_ALGO_VALUES["ignore_voltage_bounds"]); -if ignore_voltage_bounds >= epsilon_nominal_voltage -then printf{LOG_INFO} "Parameter: for all busses with nominal voltage <= ignore_voltage_bounds=%.1f, voltage bounds are ignored and replaced by [%.3f;%.3f]\n",ignore_voltage_bounds,min_plausible_low_voltage_limit,max_plausible_high_voltage_limit; -check ignore_voltage_bounds >= 0; - -param buses_with_reactive_slacks symbolic default "ALL"; -if "buses_with_reactive_slacks" in PARAM_ALGO_KEYS then let buses_with_reactive_slacks := PARAM_ALGO_VALUES["buses_with_reactive_slacks"]; -printf{LOG_INFO} "Parameter: choice for buses with reactive slacks in ACOPF := %Q (%s)\n", buses_with_reactive_slacks, - if buses_with_reactive_slacks == "ALL" then "every bus in connex component." - else if buses_with_reactive_slacks == "NO_GENERATION" then "buses without generation (no generator, svc or vsc)" - else if buses_with_reactive_slacks == "CONFIGURED" then "buses given as parameters in param_buses_with_reactive_slack.txt"; -check buses_with_reactive_slacks in {"CONFIGURED", "NO_GENERATION", "ALL"}; - -# Consistency maximal value for P and Q -# Any Pmax Pmin Qmax Qmin of generating unit with abolute value larger than PQmax is discarded -# Largest nuclear plant in Europe are less than 2000GW. Value 9000 might be a problem for large hydro dams in the world (22GW) -param PQmax default 9000; -if "PQmax" in PARAM_ALGO_KEYS then let PQmax := num(PARAM_ALGO_VALUES["PQmax"]); -printf{LOG_INFO} "Parameter: maximum for generating units parameters Pmin Pmax Qmin Qmax = %Q MW or Mvar\n",PQmax; - -param defaultPmax default 1000; # MW -if "defaultPmax" in PARAM_ALGO_KEYS then let defaultPmax := num(PARAM_ALGO_VALUES["defaultPmax"]); -printf{LOG_INFO} "Parameter: %s = %Q MW\n","defaultPmax",defaultPmax; - -param defaultPmin default 0; # MW -if "defaultPmin" in PARAM_ALGO_KEYS then let defaultPmin := num(PARAM_ALGO_VALUES["defaultPmin"]); -printf{LOG_INFO} "Parameter: %s = %Q MW\n","defaultPmin",defaultPmin; - -param defaultQmaxPmaxRatio default 0.3; # Mvar/MW -if "defaultQmaxPmaxRatio" in PARAM_ALGO_KEYS then let defaultQmaxPmaxRatio := num(PARAM_ALGO_VALUES["defaultQmaxPmaxRatio"]); -printf{LOG_INFO} "Parameter: %s = %Q Mvar/MW\n","defaultQmaxPmaxRatio",defaultQmaxPmaxRatio; - -param defaultQmin := -defaultQmaxPmaxRatio * defaultPmax; -printf{LOG_INFO} "Parameter: %s = %Q Mvar\n","defaultQmin",defaultQmin; - -param defaultQmax := defaultQmaxPmaxRatio * defaultPmax; -printf{LOG_INFO} "Parameter: %s = %Q Mvar\n","defaultQmax",defaultQmax; - -param minimalQPrange default 1; # MW or Mvar; if domain is smaller, Q or P is fixed -if "minimalQPrange" in PARAM_ALGO_KEYS then let minimalQPrange := num(PARAM_ALGO_VALUES["minimalQPrange"]); -printf{LOG_INFO} "Parameter: %s = %Q MW or Mvar\n","minimalQPrange",minimalQPrange; - -# Scaling values for variables/constraints of the ACOPF -param default_variable_scaling_factor default 1; -if "default_variable_scaling_factor" in PARAM_ALGO_KEYS then let default_variable_scaling_factor := num(PARAM_ALGO_VALUES["default_variable_scaling_factor"]); -printf{LOG_INFO} "Parameter: default scaling factor for variables := %.3f\n",default_variable_scaling_factor; -check default_variable_scaling_factor > 0; - -param default_constraint_scaling_factor default 1; -if "default_constraint_scaling_factor" in PARAM_ALGO_KEYS then let default_constraint_scaling_factor := num(PARAM_ALGO_VALUES["default_constraint_scaling_factor"]); -printf{LOG_INFO} "Parameter: default scaling factor for constraints := %.3f\n",default_constraint_scaling_factor; -check default_constraint_scaling_factor >= 0; - -param reactive_slack_variable_scaling_factor default 1; -if "reactive_slack_variable_scaling_factor" in PARAM_ALGO_KEYS then let reactive_slack_variable_scaling_factor := num(PARAM_ALGO_VALUES["reactive_slack_variable_scaling_factor"]); -printf{LOG_INFO} "Parameter: scaling factor for reactive slack variables := %.3f\n",reactive_slack_variable_scaling_factor; -check reactive_slack_variable_scaling_factor > 0; - -param transformer_ratio_variable_scaling_factor default 1; -if "transformer_ratio_variable_scaling_factor" in PARAM_ALGO_KEYS then let transformer_ratio_variable_scaling_factor := num(PARAM_ALGO_VALUES["transformer_ratio_variable_scaling_factor"]); -printf{LOG_INFO} "Parameter: scaling factor for tranformer ratio variables := %.3f\n",transformer_ratio_variable_scaling_factor; -check transformer_ratio_variable_scaling_factor > 0; - -param shunt_variable_scaling_factor default 1e-1; -if "shunt_variable_scaling_factor" in PARAM_ALGO_KEYS then let shunt_variable_scaling_factor := num(PARAM_ALGO_VALUES["shunt_variable_scaling_factor"]); -printf{LOG_INFO} "Parameter: scaling factor for shunt variables := %.3f\n",shunt_variable_scaling_factor; -check shunt_variable_scaling_factor > 0; - -############################################################################### -# Solver choice and options -############################################################################### -option solver knitroampl; -option dual_initial_guesses 0; -option presolve 10; -option show_boundtol 0; -option solver_msg (log_level_knitro); - -suffix cfeastol IN; -suffix xfeastol IN; - -suffix cscalefactor IN; -suffix xscalefactor IN; -suffix objscalefactor IN; - -suffix usercomp IN; -suffix intvarstrategy IN; - -suffix knitro_feaserror OUT; -suffix knitro_opterror OUT; -suffix knitro_neval OUT; -suffix knitro_niter OUT; - - - -############################################################################### -# Global variables -############################################################################### - -# DCOPF status -param dcopf_status symbolic default "UNKNOWN"; - -# Gobal variables for writing and messages -param fileOut symbolic default "dummy.txt"; -param errorMessage symbolic default "empty error message"; - -# Messages to be written in final indicator file -param messageInfo symbolic default "empty information message"; -set messagesInfo default {}; - -# Number of iterations for AC OPF -param nb_iter_last integer default 0; -param nb_iter_total integer default 0; - -# Additional dummy parameters, used for local computation -# Remenber you cannot declare new variable in loop or "if" -param temp1; -param temp2; -param temp3; -param tempo; -param tempstr symbolic default "empty string"; - - - -############################################################################### -# Inclusions files .mod and .dat -############################################################################### -model "reactiveopf.mod"; -data "reactiveopf.dat"; - - - -############################################################################### -# This command "check" means that all checks in .mod file are done right now -############################################################################### -check; - - - -############################################################################### -# -# Computation of "slack bus" or reference bus -# -############################################################################### -# This is not really a slack bus since this reactive OPF will change values -# of generation proportionally, to ensure global balance generation=losses+load -# So this "slack node" is used only for zero phase constraint -# This reference bus is also used to choose on which connect component computation si performed -printf{LOG_INFO} "\nComputation of bus with largest number of branches connected, in order to fix phase to 0 and to choose on which connex component reacive OPF will run\n"; -let temp1 := min(300,max{n in BUS2} substation_Vnomi[1,bus_substation[1,n]]); -let null_phase_bus := min{n in BUS2} n; -let tempo := 0; -for {n in BUS2 : substation_Vnomi[1,bus_substation[1,n]] >= temp1 * 0.9} - let tempo := max (tempo, card({(qq,mm,n) in BRANCH2} union {(qq,n,nn) in BRANCH2})); -for {n in BUS2 : substation_Vnomi[1,bus_substation[1,n]] >= temp1 * 0.9 && card({(qq,mm,n) in BRANCH2} union {(qq,n,nn) in BRANCH2}) == tempo} - let null_phase_bus := n; -if ( tempo > 0 ) then - printf{LOG_INFO} "Bus %QkV with most branches: %Q in substation %s/%s with %Q connected branches\n", - substation_Vnomi[1,bus_substation[1,null_phase_bus]], - null_phase_bus, - substation_id[1,bus_substation[1,null_phase_bus]], - substation_description[1,bus_substation[1,null_phase_bus]], - tempo; -if ( tempo == 0 ) then - printf{LOG_WARNING} "Bus with most branches: not found. Take first bus (=%Q) for phase=0 constraint\n",null_phase_bus; - - - -############################################################################### -# -# Connexity checks and computation of connex components -# -############################################################################### -let PROBLEM_CCOMP := {1}; -let PROBLEM_DCOPF := { }; -let PROBLEM_ACOPF := { }; - -############################################################################### -# Solve -############################################################################### - -let tempstr := ctime(); -printf{LOG_KNITRO} "\n######################################################################\n"; -printf{LOG_KNITRO} "** CCcomp solve: start (%s)\n\n",tempstr; - -option presolve 0; -option knitro_options ("outlev=3");; - -# TODO : remove suffix printing -if (log_level_knitro <= 1) then { - solve cccomputation_objective > (nullDevice); -} else { - solve cccomputation_objective; -} - -printf{LOG_KNITRO} "\n** CCcomp solve: end (%s -> %s)\n",tempstr,ctime(); -printf{LOG_KNITRO} "######################################################################\n\n"; - -############################################################################### -# Analysis of solve_result_num -############################################################################### - -if solve_result_num > 103 or card({n in BUS2: teta_ccomputation[n].val > 0.01 and teta_ccomputation[n].val < 0.99})>0 -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. - let errorMessage := "Optimization for connex component computation failed"; - let final_status := "NOK"; - include reactiveopfexit.run; -} -option presolve 10; - -############################################################################### -# Definition of BUSCC below was the purpose of this optimization -############################################################################### - -printf{LOG_INFO} "\n######################################################################\n"; -printf{LOG_INFO} "** CCcomp results\n"; - -let BUSCC := {n in BUS2: teta_ccomputation[n].val <= 0.01}; -for{n in BUS2 diff BUSCC} - printf{LOG_WARNING} "Bus %Q in substation %Q (Vnomi=%.2fkV, country=%Q) is out of main AC CC\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]]; -printf{LOG_INFO} "Nb of busses in AC+DC CC: %i\n",card(BUS2); -printf{LOG_INFO} "Nb of busses in CC %Q: %i\n",bus_id[1,null_phase_bus],card(BUSCC); -printf{LOG_INFO} "Nb of busses in other CCs: %Q\n",card(BUS2)-card(BUSCC); -printf "\n"; - - -############################################################################### -# A few information -############################################################################### - -if 1 in LOG_INFO then { - display - maximal_voltage_upper_bound, minimal_voltage_lower_bound, - card(SUBSTATIONS),card(BUS),card(BUS2),card(BUSCC),card(BUS2 diff BUSCC),card(BUSVV),card(BUSCC_SLACK),card(BUSCC diff BUSCC_SLACK), - card(BRANCH),card(BRANCHCC),card(BRANCHZNULL),card(BRANCHCC diff BRANCHZNULL), - card(UNIT),card(UNITCC),card(UNITON),card(UNITON diff UNIT_FIXQ),card(UNIT_FIXQ), - card(LOAD),card(LOADCC), - card(SHUNTCC),card(SHUNT_FIX),card(SHUNT_VAR), - card(SVC),card(SVCCC),card(SVCON), - card(VSCCONV),card(VSCCONVON), - card(LCCCONV),card(LCCCONVON) -; -} - -# Is the case power globally power balanced? -let temp1 := sum{(c,n) in LOADCC} load_PFix[1,c,n]; -let temp2 := sum{(g,n) in UNITON} unit_Pc[1,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]); -let global_initial_losses_ratio := (temp2-temp1-temp3)/(temp1+temp3); - -printf{LOG_INFO} "HVDC injections (homogeneous to loads):\n"; -for {(v,n) in VSCCONVON} - printf{LOG_INFO} "VSC converter %Q in %Q: P0=%.1fMW is fixed, Q is variable\n", - vscconv_id[1,v,n],substation_id[1,bus_substation[1,n]],vscconv_P0[1,v,n]; -for {(l,n) in LCCCONVON} - printf{LOG_INFO} "LCC converter %Q in %Q: P0=%.1fMW is fixed, Q0=%.1fMvar is fixed\n", - lccconv_id[1,l,n],substation_id[1,bus_substation[1,n]],lccconv_P0[1,l,n],lccconv_Q0[1,l,n]; -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} " (including batteries for %.1f MW\n", sum{(b,n) in BATTERYCC} battery_p0[1,b,n]; -printf{LOG_INFO} "Balance (P-C-H)/C: %.2f %% (global_initial_losses_ratio=%f)\n\n", (temp2-temp1-temp3)/temp1*100,global_initial_losses_ratio; - -# Branches with low current limits (but keep in mind they are not used; this is just for information) -let temp1 := min{(qq,m,n) in BRANCHCC} Fmax[qq,m,n]; -for {(qq,m,n) in BRANCHCC : Fmax[qq,m,n] <= temp1 * 1.5} - printf{LOG_INFO} "Branch %Q Fmax=%.2fMW is small ; Vnom1=%ikV Vnom2=%ikV patl1=%iA patl2=%iA (Fmax not used, this is just for information)\n", - branch_id[1,qq,m,n],Fmax[qq,m,n],substation_Vnomi[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,n]],branch_patl1[1,qq,m,n],branch_patl1[1,qq,m,n]; - -# Abnormally low nominal voltages -for {(t,n) in BUS: substation_Vnomi[1,bus_substation[1,n]] < epsilon_nominal_voltage} - printf{LOG_WARNING} "Warning: bus %Q in substation %Q has nominal voltage %.2fkV < %QkV -> bus is ignored\n", - bus_id[1,n], substation_id[1,bus_substation[1,n]], substation_Vnomi[1,bus_substation[1,n]], epsilon_nominal_voltage; - -# Voltage bounds -let temp1 := min{(t,s) in SUBSTATIONS: substation_Vmin[t,s] > 0} substation_Vmin[t,s]; -for {(t,s) in SUBSTATIONS: substation_Vmin[t,s] > 0 and substation_Vmin[t,s] <= temp1*1.01} - printf{LOG_INFO} "Substations %Q with lowest voltage lower bound Vnom=%ikV Vmin=%.3fpu\n",substation_id[t,s],substation_Vnomi[t,s],substation_Vmin[t,s]; -let temp1 := max{(t,s) in SUBSTATIONS: substation_Vmax[t,s] > 0} substation_Vmax[t,s]; -for {(t,s) in SUBSTATIONS: substation_Vmax[t,s] > 0 and substation_Vmax[t,s] >= temp1*0.99} - printf{LOG_INFO} "Substations %Q with highest voltage upper bound Vnom=%ikV Vmax=%.3fpu\n",substation_id[t,s],substation_Vnomi[t,s],substation_Vmax[t,s]; -printf{LOG_INFO} "If voltage lower bounds are missing or too small, they are set to %.3fpu\n",minimal_voltage_lower_bound; -printf{LOG_INFO} "If voltage upper bounds are missing or too high, they are set to %.3fpu\n",maximal_voltage_upper_bound; -let temp1 := card({n in BUSCC: substation_Vnomi[1,bus_substation[1,n]] <= ignore_voltage_bounds}); -if temp1 > 0 then -printf{LOG_WARNING} "Voltage bounds for substations with nominal voltage <= %ikV are set to [%.3fpu;%.3fpu] (%i busses)\n", - ignore_voltage_bounds,minimal_voltage_lower_bound,maximal_voltage_upper_bound,temp1; -printf{LOG_INFO} "Maximal diameter of voltage interval: %.3f\n",max({(t,s) in SUBSTATIONS}(voltage_upper_bound[t,s] - voltage_lower_bound[t,s])); -printf{LOG_INFO} "Minimal diameter of voltage interval: %.3f\n",min({(t,s) in SUBSTATIONS}(voltage_upper_bound[t,s] - voltage_lower_bound[t,s])); - -############################################################################### -# Consistency of transformers ratios -############################################################################### - -let temp1 := min{(t,r) in REGL} regl_ratio_min[1,r]; -let temp2 := max{(t,r) in REGL} regl_ratio_max[1,r]; -printf{LOG_INFO} "Minimal transformer ratio : %.3f\n",temp1; -printf{LOG_INFO} "Maximal transformer ratio : %.3f\n",temp2; -for {(qq,m,n) in BRANCHCC_REGL: qq in PARAM_TRANSFORMERS_RATIO_VARIABLE - and not regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]] < regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]]} -{ - let messageInfo := sprintf ( - "Transformer %Q %Q(%ikV)->%Q(%ikV) cstratio=%.3f ratio_min=%.3f ratio_max=%.3f should have variable ratio but min and max are equal", - branch_id[1,qq,m,n], - substation_id[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,m]], - substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], - branch_cstratio[1,qq,m,n], - regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]],regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]]); - printf{LOG_WARNING} "%s\n",messageInfo; - let messagesInfo := messagesInfo union {messageInfo}; -} -for {(qq,m,n) in BRANCHCC_REGL: regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]] <= temp1 * 1.01 - or regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]] >= temp2 * 0.99 } -{ - printf{LOG_INFO} "Transformer %Q ratio_min=%.3f ratio_max=%.3f\n", - branch_id[1,qq,m,n], - regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]], - regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]] -} -# Looking for unconsistencies -let tempo := 0; # If non zero, major inconsistency detected -for {(qq,m,n) in BRANCHCC_REGL: substation_Vnomi[1,bus_substation[1,m]] > 30 and substation_Vnomi[1,bus_substation[1,n]] > 30 and 1=0} { - let temp1 := regl_ratio_min[1,branch_ptrRegl[1,qq,m,n]]; - let temp2 := regl_ratio_max[1,branch_ptrRegl[1,qq,m,n]]; - if voltage_lower_bound[1,bus_substation[1,m]]*temp1*branch_cstratio[1,qq,m,n] > voltage_upper_bound[1,bus_substation[1,n]] - then { - if substation_Vnomi[1,bus_substation[1,m]] > ignore_voltage_bounds - and substation_Vnomi[1,bus_substation[1,n]] > ignore_voltage_bounds - then let tempo := 1; - let messageInfo := sprintf ( - "ERROR INFEASIBLE transformer %Q %Q(%ikV)->%Q(%ikV) cstratio=%.3f ratio_min=%.3f ratio_max=%.3f : Vmin1=%.3f * ratio_min > Vmax2=%.3f", - branch_id[1,qq,m,n], - substation_id[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,m]], - substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], - branch_cstratio[1,qq,m,n],temp1,temp2, - voltage_lower_bound[1,bus_substation[1,m]], - voltage_upper_bound[1,bus_substation[1,n]]); - printf{LOG_ERROR} "%s\n",messageInfo; - let messagesInfo := messagesInfo union {messageInfo}; - } - if voltage_upper_bound[1,bus_substation[1,m]]*temp2*branch_cstratio[1,qq,m,n] < voltage_lower_bound[1,bus_substation[1,n]] - then { - if substation_Vnomi[1,bus_substation[1,m]] > ignore_voltage_bounds - and substation_Vnomi[1,bus_substation[1,n]] > ignore_voltage_bounds - then let tempo := 1; - let messageInfo := sprintf ( - "ERROR INFEASIBLE transformer %Q %Q(%ikV)->%Q(%ikV) cstratio=%.3f ratio_min=%.3f ratio_max=%.3f : Vmax1=%.3f * ratio_max < Vmin2=%.3f", - branch_id[1,qq,m,n], - substation_id[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,m]], - substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], - branch_cstratio[1,qq,m,n],temp1,temp2, - voltage_upper_bound[1,bus_substation[1,m]], - voltage_lower_bound[1,bus_substation[1,n]]); - printf{LOG_ERROR} "%s\n",messageInfo; - let messagesInfo := messagesInfo union {messageInfo}; - } -} -# Consistency for transformers with fixed ratio -for {(qq,m,n) in BRANCHCC_REGL_FIX: substation_Vnomi[1,bus_substation[1,m]] > 30 and substation_Vnomi[1,bus_substation[1,n]] > 30 and 1=0} { - let temp1 := tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],regl_tap0[1,branch_ptrRegl[1,qq,m,n]]]; - if voltage_lower_bound[1,bus_substation[1,m]]*temp1*branch_cstratio[1,qq,m,n] > voltage_upper_bound[1,bus_substation[1,n]] - then { - if substation_Vnomi[1,bus_substation[1,m]] > ignore_voltage_bounds - and substation_Vnomi[1,bus_substation[1,n]] > ignore_voltage_bounds - then let tempo := 1; - let messageInfo := sprintf ( - "ERROR INFEASIBLE transformer %Q %Q(%ikV)->%Q(%ikV) cstratio=%.3f fixed_ratio=%.3f : Vmin1=%.3f * ratio > Vmax2=%.3f", - branch_id[1,qq,m,n], - substation_id[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,m]], - substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], - branch_cstratio[1,qq,m,n],temp1, - voltage_lower_bound[1,bus_substation[1,m]], - voltage_upper_bound[1,bus_substation[1,n]]); - printf{LOG_ERROR} "%s\n",messageInfo; - let messagesInfo := messagesInfo union {messageInfo}; - } - if voltage_upper_bound[1,bus_substation[1,m]]*temp1*branch_cstratio[1,qq,m,n] < voltage_lower_bound[1,bus_substation[1,n]] - then { - if substation_Vnomi[1,bus_substation[1,m]] > ignore_voltage_bounds - and substation_Vnomi[1,bus_substation[1,n]] > ignore_voltage_bounds - then let tempo := 1; - let messageInfo := sprintf ( - "ERROR INFEASIBLE transformer %Q %Q(%ikV)->%Q(%ikV) cstratio=%.3f fixed_ratio=%.3f : Vmax1=%.3f * ratio < Vmin2=%.3f", - branch_id[1,qq,m,n], - substation_id[1,bus_substation[1,m]],substation_Vnomi[1,bus_substation[1,m]], - substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], - branch_cstratio[1,qq,m,n],temp1, - voltage_upper_bound[1,bus_substation[1,m]], - voltage_lower_bound[1,bus_substation[1,n]]); - printf{LOG_ERROR} "%s\n",messageInfo; - let messagesInfo := messagesInfo union {messageInfo}; - } -} -if tempo > 0.5 then { - let errorMessage := "ERROR INFEASIBLE some voltages bounds and not feasible with transformers ratios"; - let final_status := "NOK"; - include reactiveopfexit.run; -} - - - -############################################################################### -# Correction of units' P and Q domains -############################################################################### -printf{LOG_WARNING} "\nWARNING Correction of P/Q units domains:\n"; -for {(g,n) in UNITON} { - - if abs(unit_Pmax[1,g,n]) >= PQmax then { - let corrected_unit_Pmax[g,n] := max(defaultPmax,unit_Pc[1,g,n]); - printf{LOG_WARNING} "%Q for %Q is %Q -> corrected to %Q\n","unit_Pmax",unit_id[1,g,n],unit_Pmax[1,g,n],corrected_unit_Pmax[g,n]; - } - else let corrected_unit_Pmax[g,n] := unit_Pmax[1,g,n]; - - if abs(unit_Pmin[1,g,n]) >= PQmax then { - let corrected_unit_Pmin[g,n] := min(defaultPmin,unit_Pc[1,g,n]); - printf{LOG_WARNING} "%Q for %Q is %Q -> corrected to %Q\n","unit_Pmin",unit_id[1,g,n],unit_Pmin[1,g,n],corrected_unit_Pmin[g,n]; - } - else let corrected_unit_Pmin[g,n] := unit_Pmin[1,g,n]; - - if abs(corrected_unit_Pmax[g,n]-corrected_unit_Pmin[g,n]) <= minimalQPrange then { - if abs(unit_Pc[1,g,n]) > 1 then - printf{LOG_WARNING} "Unit %Q has Pmin=%.1f and Pmax=%.1f too close -> we set Pmin=Pmax=Pc=%Q\n", - unit_id[1,g,n],corrected_unit_Pmin[g,n],corrected_unit_Pmax[g,n],unit_Pc[1,g,n]; - let corrected_unit_Pmin[g,n] := unit_Pc[1,g,n]; - let corrected_unit_Pmax[g,n] := unit_Pc[1,g,n]; - } - - if abs(unit_qp[1,g,n]) >= PQmax then { - let corrected_unit_qp[g,n] := -defaultQmaxPmaxRatio * corrected_unit_Pmax[g,n]; - printf{LOG_DEBUG} "%Q for %Q is %Q -> corrected to %Q\n","unit_qp",unit_id[1,g,n],unit_qp[1,g,n],corrected_unit_qp[g,n]; - } - else let corrected_unit_qp[g,n] := unit_qp[1,g,n]; - - if abs(unit_qP[1,g,n]) >= PQmax then { - let corrected_unit_qP[g,n] := -defaultQmaxPmaxRatio * corrected_unit_Pmax[g,n]; - printf{LOG_DEBUG} "%Q for %Q is %Q -> corrected to %Q\n","unit_qP",unit_id[1,g,n],unit_qP[1,g,n],corrected_unit_qP[g,n]; - } - else let corrected_unit_qP[g,n] := unit_qP[1,g,n]; - - if abs(unit_Qp[1,g,n]) >= PQmax then { - let corrected_unit_Qp[g,n] := defaultQmaxPmaxRatio * corrected_unit_Pmax[g,n]; - printf{LOG_DEBUG} "%Q for %Q is %Q -> corrected to %Q\n","unit_Qp",unit_id[1,g,n],unit_Qp[1,g,n],corrected_unit_Qp[g,n]; - } - else let corrected_unit_Qp[g,n] := unit_Qp[1,g,n]; - - if abs(unit_QP[1,g,n]) >= PQmax then { - let corrected_unit_QP[g,n] := defaultQmaxPmaxRatio * corrected_unit_Pmax[g,n]; - printf{LOG_DEBUG} "%Q for %Q is %Q -> corrected to %Q\n","unit_QP",unit_id[1,g,n],unit_QP[1,g,n],corrected_unit_QP[g,n]; - } - else let corrected_unit_QP[g,n] := unit_QP[1,g,n]; - - if corrected_unit_qp[g,n] > corrected_unit_Qp[g,n] then { - printf{LOG_WARNING} "Warning unit %Q : unit_qp > unit_Qp -> we invert them",unit_id[1,g,n]; - let tempo := corrected_unit_qp[g,n]; - let corrected_unit_qp[g,n] := corrected_unit_Qp[g,n]; - let corrected_unit_Qp[g,n] := tempo; - } - - if corrected_unit_qP[g,n] > corrected_unit_QP[g,n] then { - printf{LOG_WARNING} "Warning unit %Q : unit_qP > unit_QP -> we invert them",unit_id[1,g,n]; - let tempo := corrected_unit_qP[g,n]; - let corrected_unit_qP[g,n] := corrected_unit_QP[g,n]; - let corrected_unit_QP[g,n] := tempo; - } - - if abs(corrected_unit_qP[g,n]-corrected_unit_QP[g,n]) <= minimalQPrange - and abs(corrected_unit_qp[g,n]-corrected_unit_Qp[g,n]) <= minimalQPrange - and abs(corrected_unit_QP[g,n]-corrected_unit_qp[g,n]) <= minimalQPrange - then { - let tempo := 0.25*(corrected_unit_qP[g,n]+corrected_unit_QP[g,n]+corrected_unit_qp[g,n]+corrected_unit_Qp[g,n]); - printf{LOG_DEBUG} "Unit %Q has reactive diagram too small -> we set qp=qP=Qp=QP=%Q (Pc=%Q)\n", - unit_id[1,g,n],tempo,unit_Pc[1,g,n]; - let corrected_unit_qP[g,n] := tempo; - let corrected_unit_QP[g,n] := tempo; - let corrected_unit_qp[g,n] := tempo; - let corrected_unit_Qp[g,n] := tempo; - } - - let corrected_unit_Qmin[g,n] := min(corrected_unit_qP[g,n],corrected_unit_qp[g,n]); - let corrected_unit_Qmax[g,n] := min(corrected_unit_QP[g,n],corrected_unit_Qp[g,n]); - - if unit_Pc[1,g,n] > corrected_unit_Pmax[g,n] or unit_Pc[1,g,n] < corrected_unit_Pmin[g,n] - then printf{LOG_WARNING} "Warning unit %Q Pc=%Q not in bounds [ Pmin=%Q ; Pmax=%Q ]\n", - unit_id[1,g,n],unit_Pc[1,g,n],corrected_unit_Pmin[g,n],corrected_unit_Pmax[g,n]; - - if abs(corrected_unit_Qmin[g,n] - corrected_unit_Qmax[g,n]) >= minimalQPrange - and ( corrected_unit_Qmin[g,n] > 0 or corrected_unit_Qmax[g,n] < 0 ) - then printf{LOG_WARNING} "Warning unit %Q: 0 not in bounds [ Qmin=%Q ; Qmax=%Q ]\n", - unit_id[1,g,n],corrected_unit_Qmin[g,n],corrected_unit_Qmax[g,n]; -} - -printf{LOG_INFO} "\nFew information on P/Q units domains:\n"; -printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_Pmin[1,g,n]),"unit_Pmin",max({(g,n) in UNITON} unit_Pmin[1,g,n]); -printf{LOG_INFO} "Active generation: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_Pc[1,g,n]), "unit_Pc", max({(g,n) in UNITON} unit_Pc[1,g,n]); -printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_Pmax[1,g,n]),"unit_Pmax",max({(g,n) in UNITON} unit_Pmax[1,g,n]); -printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_qP[1,g,n]), "unit_qP", max({(g,n) in UNITON} unit_qP[1,g,n]); -printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_qp[1,g,n]), "unit_qp", max({(g,n) in UNITON} unit_qp[1,g,n]); -printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_QP[1,g,n]), "unit_QP", max({(g,n) in UNITON} unit_QP[1,g,n]); -printf{LOG_INFO} "Raw extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} unit_Qp[1,g,n]), "unit_Qp", max({(g,n) in UNITON} unit_Qp[1,g,n]); - -printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_Pmin[g,n]),"corrected_unit_Pmin",max({(g,n) in UNITON} corrected_unit_Pmin[g,n]); -printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_Pmax[g,n]),"corrected_unit_Pmax",max({(g,n) in UNITON} corrected_unit_Pmax[g,n]); -printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_qP[g,n]), "corrected_unit_qP", max({(g,n) in UNITON} corrected_unit_qP[g,n]); -printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_qp[g,n]), "corrected_unit_qp", max({(g,n) in UNITON} corrected_unit_qp[g,n]); -printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_QP[g,n]), "corrected_unit_QP", max({(g,n) in UNITON} corrected_unit_QP[g,n]); -printf{LOG_INFO} "Corrected extremal values: %Q <= %Q <= %Q\n",min({(g,n) in UNITON} corrected_unit_Qp[g,n]), "corrected_unit_Qp", max({(g,n) in UNITON} corrected_unit_Qp[g,n]); - - - -############################################################################### -# -# Optimisation DC OPF (for phase initialization and data consistency check) -# -############################################################################### -let PROBLEM_CCOMP := { }; -let PROBLEM_DCOPF := {1}; -let PROBLEM_ACOPF := { }; - - -############################################################################### -# Solve -############################################################################### - -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_acopf_objective; -} - -let nb_iter_last := problem_acopf_objective.numiters; -let nb_iter_total := nb_iter_total + nb_iter_last; - -printf{LOG_KNITRO} "\n** ACopf solve: end (%s -> %s)\n",tempstr,ctime(); -printf{LOG_KNITRO} "######################################################################\n\n"; - - -param slack1_balance_Q{n in BUSCC_SLACK}; -param slack2_balance_Q{n in BUSCC_SLACK}; -for {n in BUSCC_SLACK} { - let slack1_balance_Q[n] := base100MVA * V[n]^2 * slack1_shunt_B[n].val; - let slack2_balance_Q[n] := base100MVA * V[n]^2 * slack2_shunt_B[n].val; -} - -############################################################################### -# Analysis of solve_result_num -############################################################################### - -# <= 103 : feasible -# 200 convergence to unfeasible -# > 200 : failure -param output_results binary default 0; -if solve_result_num == 200 -then { - let output_results := 0; - let messageInfo := "Acopf optimization was ***not*** successfull - Convergence to an infeasible solution"; - printf{LOG_ERROR} "%s\n", messageInfo; - let messagesInfo := messagesInfo union {messageInfo}; - let final_status := "NOK"; -} -else if solve_result_num > 103 -then { - let output_results := 0; - let messageInfo := "Acopf optimization was ***not*** successfull - no solution found"; - printf{LOG_ERROR} "%s\n", messageInfo; - let messagesInfo := messagesInfo union {messageInfo}; - let final_status := "NOK"; -} -else { - let output_results := 1; - let final_status := "OK"; -} - - -############################################################################### -# Displays after solving -############################################################################### - -printf{LOG_INFO} "\n######################################################################\n"; -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])), - min({n in BUSCC}V[n]),max({n in BUSCC}V[n]) - ; - -let temp1 := max({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])); -let temp2 := min({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])); - -for {(qq,m,n) in BRANCHCC: (teta[m]-teta[n])>temp1*0.99 or (teta[m]-teta[n]) Pnull -then { - - if 1 in LOG_INFO then - display - sum{n in BUSCC_SLACK} slack1_balance_Q[n], - sum{n in BUSCC_SLACK} slack2_balance_Q[n], - max{n in BUSCC_SLACK} slack1_balance_Q[n], - max{n in BUSCC_SLACK} slack2_balance_Q[n], - card({n in BUSCC_SLACK: slack2_balance_Q[n]+slack1_balance_Q[n]>Pnull}); - - if output_results > 0 then - if card({n in BUSCC_SLACK: slack1_balance_Q[n]+slack2_balance_Q[n] > Pnull}) > 0 then printf{LOG_WARNING} "WARNING buses with non zero reactive slack :\n"; - for {n in BUSCC_SLACK: slack1_balance_Q[n]+slack2_balance_Q[n] > Pnull} - printf{LOG_WARNING} "Bus %Q in substation %Q (%ikV) has non zero reactive slacks %.1f %.1f, Vmin=%.3f Vopt=%.3f Vmax=%.3f \n", - bus_id[1,n],substation_id[1,bus_substation[1,n]],substation_Vnomi[1,bus_substation[1,n]], - slack1_balance_Q[n],slack2_balance_Q[n], - voltage_lower_bound[1,bus_substation[1,n]],V[n],voltage_upper_bound[1,bus_substation[1,n]]; -} - - - -############################################################################### -# Writing results and indicators -############################################################################### -include reactiveopfoutput.run; - -# Write voltage information in debug file -let fileOut := "debug_bus.csv"; -printf{LOG_DEBUG} "#bus_id;Vnom;V;Vlb;Vub;Vmin_mod;Vmax_mod;Vmin_OK;Vmax_OK;Vmin_ori;Vmax_ori;sQ1;sQ2;\n" > (fileOut); -for {n in BUSCC} - printf{LOG_DEBUG} "%s;%i;%.4f;%.4f;%.4f;%.4f;%.4f;%s;%s;%.4f;%.4f;%.2f;%.2f;\n", - '"' & bus_id[1,n] & '"', - substation_Vnomi[1,bus_substation[1,n]], - V[n],V[n].lb,V[n].ub, - voltage_lower_bound[1,bus_substation[1,n]], - voltage_upper_bound[1,bus_substation[1,n]], - if V[n]voltage_upper_bound[1,bus_substation[1,n]] then "NOK" else "OK", - substation_Vmin[1,bus_substation[1,n]],substation_Vmax[1,bus_substation[1,n]], - if n in BUSCC_SLACK then max(slack1_balance_Q[n]-slack2_balance_Q[n],0) else -1, - if n in BUSCC_SLACK then max(slack2_balance_Q[n]-slack1_balance_Q[n],0) else -1 - > (fileOut); -close (fileOut); - -# Write units which are not in uniton (debug only) -let fileOut := "reactiveopf_results_generators_Pnull.csv"; -printf{LOG_DEBUG} "#variant;num;bus;vRegul;V(pu);targetP(MW);targetQ(Mvar);P(MW);Q(MW);id;bus_id;\n" > (fileOut); -for {(g,n) in UNITCC diff UNITON} - printf{LOG_DEBUG} "%i;%i;%i;%Q;%.3f;%.3f;%.3f;%.3f;%.3f;%s;%s;\n", - 1,g,n, - unit_vregul[1,g,n], - V[n], - unit_Pc[1,g,n], - unit_Qc[1,g,n], - unit_P0[1,g,n], - unit_Q0[1,g,n], - '"' & unit_id[1,g,n] & '"', - '"' & bus_id[1,n] & '"' - > (fileOut); -close (fileOut); - - -############################################################################### -# End of file -############################################################################### -printf "\n"; -printf "*** End of file reactiveopf.run at %s : Optimization %ssuccessfull\n", ctime(), if output_results>0 then "" else "un"; -printf "*** Elapsed time since start : %f(s)", _ampl_elapsed_time; +############################################################################### +# +# 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 +############################################################################### + + + +############################################################################### +# +# General overview +# +# Goal of this reactive OPF is to propose values for all voltage and reactive +# equipment and controllers of the grid: +# - voltage set point of generating units, +# - shunts, +# - transformers ratios, +# - and maybe others... +# +# In a grid developemnt study, you decide new equipments, new generating units, +# new substations, new loads, you set values for active and reactive loads, +# you set values for active power generation and HVDC flows. +# Then if you wish to do AC powerflow simulations with N-1 analysis, you need +# all voltage and reactive set points and this reactive OPF is your solution. +# +# Notice that this reactive OPF: +# - will _not_ decide active power of generating units and HVDC branches, +# - does _not_ take into account current nor power limits on branches, +# - does really use upper and lower limits for voltage, so be carefull with them. +# +############################################################################### + + +############################################################################### +# Crash indicator +# If execution of this .run ampl file terminates before writing results, +# then status CRASH is already written in indicators' file +############################################################################### +# Close any files which might have been opened previously +close; +printf "final_status CRASH\n" > reactiveopf_results_indic.txt; +close; + + + +############################################################################### +# Start +############################################################################### +# Clean parameters, variables, constraints and any former models pre-existing +reset; + +# Print date of start of calculation +param ctime_start symbolic := ctime(); +printf "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ns"; +printf "*** Start of file reactiveopf.run at %s\n",ctime_start; + +# Global status +# Possible values : CRASH OK NOK UNKNOWN +param final_status symbolic default "UNKNOWN"; + + + +############################################################################### +# Linux or windows? +############################################################################### +param operatingSystem symbolic default "unknown"; +param nullDevice symbolic default "unknown"; # null device to avoid printing when knitro log = 0 +if length($OS) > 0 then { + let operatingSystem := "windows"; + let nullDevice := "NUL"; +} +if length($SHELL) > 0 then { + let operatingSystem := "linux"; + let nullDevice := "/dev/null"; +} + + + +############################################################################### +# Management of optional input files +############################################################################### +# AMPL is able to manage empty files; in that case, sets and parameters are well +# initialized to empty sets or tables; so the minimum we need is empty file. +# Maybe this is not the best way to manage optional parameter files... +if operatingSystem == "linux" then { + shell "if [ ! -f param_algo.txt ]; then touch param_algo.txt ;fi"; + shell "if [ ! -f param_shunts.txt ]; then touch param_shunts.txt ;fi"; + shell "if [ ! -f param_generators_reactive.txt ]; then touch param_generators_reactive.txt ;fi"; + shell "if [ ! -f param_transformers.txt ]; then touch param_transformers.txt ;fi"; + shell "if [ ! -f param_buses_with_reactive_slack.txt ]; then touch param_buses_with_reactive_slack.txt ;fi"; + shell "if [ ! -f ampl_network_substations_override.txt ]; then touch ampl_network_substations_override.txt ;fi"; + shell "chmod a+rX . * 2>/dev/null"; +} +if operatingSystem == "windows" then { + shell "if not exist param_algo.txt echo #empty > param_algo.txt"; + shell "if not exist param_shunts.txt echo #empty > param_shunts.txt"; + shell "if not exist param_generators_reactive.txt echo #empty > param_generators_reactive.txt"; + shell "if not exist param_transformers.txt echo #empty > param_transformers.txt"; + shell "if not exist param_buses_with_reactive_slack.txt echo #empty > param_buses_with_reactive_slack.txt"; + shell "if not exist ampl_network_substations_override.txt echo #empty > ampl_network_substations_override.txt"; +} +# If operating system is not linux nor windows, then these optional files are +# not optional anymore: you need to provide at least empty files + + + +############################################################################### +# +# General options +# +############################################################################### + + + +############################################################################### +# Logs, controls and associated parameters +############################################################################### + +# +# Read main algorithm controls in file +# +printf "\n** Reading algorithmic controls and parameters in file\n"; +model; +set PARAM_ALGO_KEYS; +param PARAM_ALGO_VALUES{PARAM_ALGO_KEYS} symbolic; +data; +param: PARAM_ALGO_KEYS: PARAM_ALGO_VALUES := include param_algo.txt; +model; +display PARAM_ALGO_VALUES; + +# Log level of ampl printing +set LOG_LEVELS ordered = {"ERROR", "WARNING", "INFO", "DEBUG"}; # different values of log level for ampl exec +param log_level_ampl symbolic default "INFO"; # default value of log level +if "log_level_ampl" in PARAM_ALGO_KEYS then let log_level_ampl := PARAM_ALGO_VALUES["log_level_ampl"]; + +# Sets used to print or not. A void set avoid printing +param log_index := ord0(log_level_ampl, LOG_LEVELS); +set LOG_DEBUG := if log_index >= 4 then{1} else {}; +set LOG_INFO := if log_index >= 3 then{1} else {}; +set LOG_WARNING := if log_index >= 2 then{1} else {}; +set LOG_ERROR := if log_index >= 1 then{1} else {}; +printf{LOG_INFO} "Parameter: log level of ampl := %s\n", log_level_ampl; +check log_level_ampl in LOG_LEVELS; + +# Log level of knitro printing +param log_level_knitro integer default 2; +if "log_level_knitro" in PARAM_ALGO_KEYS then let log_level_knitro := num(PARAM_ALGO_VALUES["log_level_knitro"]); +set LOG_KNITRO := if log_level_knitro >= 1 then{1} else {}; +printf{LOG_INFO} "Parameter: log level of knitro := %i\n", log_level_knitro; +check log_level_knitro in {0, 1, 2}; + +# Absolute parameter : base 100MVA. +# Never change this unless you really know what you do +param base100MVA := 100; + +# Choice of objective function +param objective_choice integer default 0; +if "objective_choice" in PARAM_ALGO_KEYS then let objective_choice := num(PARAM_ALGO_VALUES["objective_choice"]); +printf{LOG_INFO} "Parameter: choice for objective function := %Q (%s)\n",objective_choice, + if objective_choice==2 then "voltage targets are provided values" + else if objective_choice==1 then "voltage targets are Vmin+ratio*(Vmax-Vmin)" + else "active power minimization"; + +# If voltage target is ratio between Vmin and Vmax +param ratio_voltage_target default 0.5; +if "ratio_voltage_target" in PARAM_ALGO_KEYS then let ratio_voltage_target := num(PARAM_ALGO_VALUES["ratio_voltage_target"]); +check ratio_voltage_target >= 0 and ratio_voltage_target <= 1; +if objective_choice==1 +then printf{LOG_INFO} "Parameter: ratio for voltage target is := %f (%.2f%%)\n",ratio_voltage_target,ratio_voltage_target*100; + +# coeff_alpha == 1 : minimize sum of generation, all generating units vary with 1 unique variable alpha +# coeff_alpha == 0 : minimize sum of squared difference between target and value +param coeff_alpha default 1.0; +if "coeff_alpha" in PARAM_ALGO_KEYS then let coeff_alpha := num(PARAM_ALGO_VALUES["coeff_alpha"]); +printf{LOG_INFO} "Parameter: coeff_alpha to choose wether generation vary homogeneously (coeff_alpha=1) or independantly (coeff_alpha=0) is := %.2f\n",coeff_alpha; +check coeff_alpha >=0 and coeff_alpha <= 1; + +# Limit for detecting zero value for power +param Pnull default 0.01; # MW +if "Pnull" in PARAM_ALGO_KEYS then let Pnull := num(PARAM_ALGO_VALUES["Pnull"]); +printf{LOG_INFO} "Parameter: threshold to decide wether an active or reactive power value is zero Pnull:=%Q (MW or Mvar or MVA)\n",Pnull; +check Pnull > 0 and Pnull < 1; + +# Parameter for detection of branches with zero impedance +param Znull default 1e-4; +if "Znull" in PARAM_ALGO_KEYS then let Znull := num(PARAM_ALGO_VALUES["Znull"]); +printf{LOG_INFO} "Parameter: threshold to detect zero impedance branch Znull:=%Q pu\n",Znull; +check Znull > 0 and Znull < 0.1; + +# Minimum consistency value for minimum voltage in kV +# All busses with nominal voltage lower than epsilon_nominal_voltage will be ignored +# This value has to be >0 +param epsilon_nominal_voltage default 1.0; +if "epsilon_nominal_voltage" in PARAM_ALGO_KEYS then let epsilon_nominal_voltage := num(PARAM_ALGO_VALUES["epsilon_nominal_voltage"]); +printf{LOG_INFO} "Parameter: for consistency checks of minimum nominal voltages epsilon_nominal_voltage:= %Q kV\n",epsilon_nominal_voltage; +check epsilon_nominal_voltage > 0; + +# Minimum plausible value for voltage low limits in PU +# This value should be < 1 +param min_plausible_low_voltage_limit default 0.5; +if "min_plausible_low_voltage_limit" in PARAM_ALGO_KEYS then let min_plausible_low_voltage_limit := num(PARAM_ALGO_VALUES["min_plausible_low_voltage_limit"]); +printf{LOG_INFO} "Parameter: for consistency of voltage bounds, min_plausible_low_voltage_limit:= %Q pu\n",min_plausible_low_voltage_limit; +check min_plausible_low_voltage_limit > 0; + +# Maximum plausible value for voltage high limits in PU +param max_plausible_high_voltage_limit default 1.5; +if "max_plausible_high_voltage_limit" in PARAM_ALGO_KEYS then let max_plausible_high_voltage_limit := num(PARAM_ALGO_VALUES["max_plausible_high_voltage_limit"]); +printf{LOG_INFO} "Parameter: for consistency of voltage bounds, max_plausible_high_voltage_limit:= %Q pu\n",max_plausible_high_voltage_limit; +check max_plausible_high_voltage_limit > min_plausible_low_voltage_limit; + +# Ignore voltage bounds for buses with nominal voltage lower than this parameter +# For all busses with nominal voltage lower than ignore_voltage_bounds, voltage bonds will be ignored +# and replaced by [min_plausible_low_voltage_limit ; max_plausible_high_voltage_limit] +param ignore_voltage_bounds default 0; +if "ignore_voltage_bounds" in PARAM_ALGO_KEYS then let ignore_voltage_bounds := num(PARAM_ALGO_VALUES["ignore_voltage_bounds"]); +if ignore_voltage_bounds >= epsilon_nominal_voltage +then printf{LOG_INFO} "Parameter: for all busses with nominal voltage <= ignore_voltage_bounds=%.1f, voltage bounds are ignored and replaced by [%.3f;%.3f]\n",ignore_voltage_bounds,min_plausible_low_voltage_limit,max_plausible_high_voltage_limit; +check ignore_voltage_bounds >= 0; + +param buses_with_reactive_slacks symbolic default "ALL"; +if "buses_with_reactive_slacks" in PARAM_ALGO_KEYS then let buses_with_reactive_slacks := PARAM_ALGO_VALUES["buses_with_reactive_slacks"]; +printf{LOG_INFO} "Parameter: choice for buses with reactive slacks in ACOPF := %Q (%s)\n", buses_with_reactive_slacks, + if buses_with_reactive_slacks == "ALL" then "every bus in connex component." + else if buses_with_reactive_slacks == "NO_GENERATION" then "buses without generation (no generator, svc or vsc)" + else if buses_with_reactive_slacks == "CONFIGURED" then "buses given as parameters in param_buses_with_reactive_slack.txt"; +check buses_with_reactive_slacks in {"CONFIGURED", "NO_GENERATION", "ALL"}; + +# Consistency maximal value for P and Q +# Any Pmax Pmin Qmax Qmin of generating unit with abolute value larger than PQmax is discarded +# Largest nuclear plant in Europe are less than 2000GW. Value 9000 might be a problem for large hydro dams in the world (22GW) +param PQmax default 9000; +if "PQmax" in PARAM_ALGO_KEYS then let PQmax := num(PARAM_ALGO_VALUES["PQmax"]); +printf{LOG_INFO} "Parameter: maximum for generating units parameters Pmin Pmax Qmin Qmax = %Q MW or Mvar\n",PQmax; + +param defaultPmax default 1000; # MW +if "defaultPmax" in PARAM_ALGO_KEYS then let defaultPmax := num(PARAM_ALGO_VALUES["defaultPmax"]); +printf{LOG_INFO} "Parameter: %s = %Q MW\n","defaultPmax",defaultPmax; + +param defaultPmin default 0; # MW +if "defaultPmin" in PARAM_ALGO_KEYS then let defaultPmin := num(PARAM_ALGO_VALUES["defaultPmin"]); +printf{LOG_INFO} "Parameter: %s = %Q MW\n","defaultPmin",defaultPmin; + +param defaultQmaxPmaxRatio default 0.3; # Mvar/MW +if "defaultQmaxPmaxRatio" in PARAM_ALGO_KEYS then let defaultQmaxPmaxRatio := num(PARAM_ALGO_VALUES["defaultQmaxPmaxRatio"]); +printf{LOG_INFO} "Parameter: %s = %Q Mvar/MW\n","defaultQmaxPmaxRatio",defaultQmaxPmaxRatio; + +param defaultQmin := -defaultQmaxPmaxRatio * defaultPmax; +printf{LOG_INFO} "Parameter: %s = %Q Mvar\n","defaultQmin",defaultQmin; + +param defaultQmax := defaultQmaxPmaxRatio * defaultPmax; +printf{LOG_INFO} "Parameter: %s = %Q Mvar\n","defaultQmax",defaultQmax; + +param minimalQPrange default 1; # MW or Mvar; if domain is smaller, Q or P is fixed +if "minimalQPrange" in PARAM_ALGO_KEYS then let minimalQPrange := num(PARAM_ALGO_VALUES["minimalQPrange"]); +printf{LOG_INFO} "Parameter: %s = %Q MW or Mvar\n","minimalQPrange",minimalQPrange; + +# Scaling values for variables/constraints of the ACOPF +param default_variable_scaling_factor default 1; +if "default_variable_scaling_factor" in PARAM_ALGO_KEYS then let default_variable_scaling_factor := num(PARAM_ALGO_VALUES["default_variable_scaling_factor"]); +printf{LOG_INFO} "Parameter: default scaling factor for variables := %.3f\n",default_variable_scaling_factor; +check default_variable_scaling_factor > 0; + +param default_constraint_scaling_factor default 1; +if "default_constraint_scaling_factor" in PARAM_ALGO_KEYS then let default_constraint_scaling_factor := num(PARAM_ALGO_VALUES["default_constraint_scaling_factor"]); +printf{LOG_INFO} "Parameter: default scaling factor for constraints := %.3f\n",default_constraint_scaling_factor; +check default_constraint_scaling_factor >= 0; + +param reactive_slack_variable_scaling_factor default 1; +if "reactive_slack_variable_scaling_factor" in PARAM_ALGO_KEYS then let reactive_slack_variable_scaling_factor := num(PARAM_ALGO_VALUES["reactive_slack_variable_scaling_factor"]); +printf{LOG_INFO} "Parameter: scaling factor for reactive slack variables := %.3f\n",reactive_slack_variable_scaling_factor; +check reactive_slack_variable_scaling_factor > 0; + +param transformer_ratio_variable_scaling_factor default 1; +if "transformer_ratio_variable_scaling_factor" in PARAM_ALGO_KEYS then let transformer_ratio_variable_scaling_factor := num(PARAM_ALGO_VALUES["transformer_ratio_variable_scaling_factor"]); +printf{LOG_INFO} "Parameter: scaling factor for tranformer ratio variables := %.3f\n",transformer_ratio_variable_scaling_factor; +check transformer_ratio_variable_scaling_factor > 0; + +param shunt_variable_scaling_factor default 1e-1; +if "shunt_variable_scaling_factor" in PARAM_ALGO_KEYS then let shunt_variable_scaling_factor := num(PARAM_ALGO_VALUES["shunt_variable_scaling_factor"]); +printf{LOG_INFO} "Parameter: scaling factor for shunt variables := %.3f\n",shunt_variable_scaling_factor; +check shunt_variable_scaling_factor > 0; + +############################################################################### +# Solver choice and options +############################################################################### +option solver knitroampl; +option dual_initial_guesses 0; +option presolve 10; +option show_boundtol 0; +option solver_msg (log_level_knitro); + +suffix cfeastol IN; +suffix xfeastol IN; + +suffix cscalefactor IN; +suffix xscalefactor IN; +suffix objscalefactor IN; + +suffix usercomp IN; +suffix intvarstrategy IN; + +suffix knitro_feaserror OUT; +suffix knitro_opterror OUT; +suffix knitro_neval OUT; +suffix knitro_niter OUT; + + + +############################################################################### +# Global variables +############################################################################### + +# DCOPF status +param dcopf_status symbolic default "UNKNOWN"; + +# Gobal variables for writing and messages +param fileOut symbolic default "dummy.txt"; +param errorMessage symbolic default "empty error message"; + +# Messages to be written in final indicator file +param messageInfo symbolic default "empty information message"; +set messagesInfo default {}; + +# Number of iterations for AC OPF +param nb_iter_last integer default 0; +param nb_iter_total integer default 0; + +# Additional dummy parameters, used for local computation +# Remenber you cannot declare new variable in loop or "if" +param temp1; +param temp2; +param temp3; +param tempo; +param tempstr symbolic default "empty string"; + + + +############################################################################### +# Inclusions files .mod and .dat +############################################################################### +model "iidm_importer.mod"; +model "or_param_importer.mod"; +data "reactiveopf.dat"; + + +############################################################################### +# This command "check" means that all checks in .mod file are done right now +############################################################################### +check; + +model "commons.mod"; + +############################################################################### +# Compute reference bus and main connex component +############################################################################### +model "connected_component.mod"; +include "connected_component.run"; + +############################################################################### +# Optimisation DC OPF (for phase initialization and data consistency check) +############################################################################### +model "dcopf.mod"; +include "dcopf.run"; + + +############################################################################### +# Optimisation AC OPF +############################################################################### +model "acopf.mod"; +check; +include "acopf_preprocessing.run"; +include "acopf.run"; + + +############################################################################### +# Writing results and indicators +############################################################################### +include reactiveopfoutput.run; + + +############################################################################### +# End of file +############################################################################### +printf "\n"; +printf "*** End of file reactiveopf.run at %s : Optimization %ssuccessfull\n", ctime(), if output_results>0 then "" else "un"; +printf "*** Elapsed time since start : %f(s)", _ampl_elapsed_time; diff --git a/open-reac/src/main/resources/openreac/reactiveopfexit.run b/open-reac/src/main/resources/openreac/reactiveopfexit.run index 4e7a8fc3..279349f6 100644 --- a/open-reac/src/main/resources/openreac/reactiveopfexit.run +++ b/open-reac/src/main/resources/openreac/reactiveopfexit.run @@ -1,78 +1,80 @@ -############################################################################### -# -# Copyright (c) 2022 2023, 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/. -# -############################################################################### - -############################################################################### -# Reactive OPF -# Author: Jean Maeght 2022 2023 -# Author: Manuel Ruiz 2023 2024 -############################################################################### - -# Exit procedure - -# Indicatros file -let fileOut := "reactiveopf_results_indic.txt"; - -# Final status and error message -printf "%s %s\n","final_status", final_status > (fileOut); -if length(errorMessage) > 0 then { - printf "%s %Q\n","errorMessage",errorMessage > (fileOut); - printf "%s\n",errorMessage; -} -printf "%s %Q\n","ctime_start",ctime_start > (fileOut); - -# Other messages -if card(messagesInfo) > 0 then { - let temp1:=1; - for { message in messagesInfo } { - printf "messageInfo%i %Q\n",temp1,message > (fileOut); - let temp1:=temp1+1; - } -} - -# Other indicators -printf "\n" > (fileOut); -printf "%s %s\n","dcopf_status",dcopf_status > (fileOut); -printf "%s %s\n","operatingSystem",operatingSystem > (fileOut); -if length($OS) > 0 then { - printf "%s %Q\n","OS",$OS > (fileOut); # Windows - printf "%s %Q\n","COMPUTERNAME",$COMPUTERNAME > (fileOut); -} -if length($SHELL) > 0 then { - printf "%s %Q\n","SHELL",$SHELL > (fileOut); # Linux - printf "%s %Q\n","HOSTNAME",$HOSTNAME > (fileOut); -} -printf "%s %Q\n","directory",_cd > (fileOut); - -# Algorithmic parameters -printf "\n" > (fileOut); -printf "%s %s\n","log_level_ampl",log_level_ampl > (fileOut); -printf "%s %i\n","log_level_knitro",log_level_knitro > (fileOut); -printf "%s %f\n","Pnull",Pnull > (fileOut); -printf "%s %f\n","Znull",Znull > (fileOut); -printf "%s %f\n","epsilon_nominal_voltage",epsilon_nominal_voltage > (fileOut); -printf "%s %f\n","min_plausible_low_voltage_limit",min_plausible_low_voltage_limit > (fileOut); -printf "%s %f\n","max_plausible_high_voltage_limit",max_plausible_high_voltage_limit > (fileOut); -printf "%s %f\n","ignore_voltage_bounds",ignore_voltage_bounds > (fileOut); -printf "%s %s\n","buses_with_reactive_slacks",buses_with_reactive_slacks > (fileOut); -printf "%s %f\n","PQmax",PQmax > (fileOut); -printf "%s %f\n","defaultPmax",defaultPmax > (fileOut); -printf "%s %f\n","defaultPmin",defaultPmin > (fileOut); -printf "%s %f\n","defaultQmaxPmaxRatio",defaultQmaxPmaxRatio > (fileOut); -printf "%s %f\n","defaultQmin",defaultQmin > (fileOut); -printf "%s %f\n","defaultQmax",defaultQmax > (fileOut); -printf "%s %f\n","minimalQPrange",minimalQPrange > (fileOut); -printf "%s %f\n","default_variable_scaling_factor",default_variable_scaling_factor > (fileOut); -printf "%s %f\n","default_constraint_scaling_factor",default_constraint_scaling_factor > (fileOut); -printf "%s %f\n","reactive_slack_variable_scaling_factor",reactive_slack_variable_scaling_factor > (fileOut); -printf "%s %f\n","transformer_ratio_variable_scaling_factor",transformer_ratio_variable_scaling_factor > (fileOut); -printf "%s %f\n","shunt_variable_scaling_factor",shunt_variable_scaling_factor > (fileOut); -close (fileOut); - -printf "\n*** End of file reactiveopfexit.run : %s\n",ctime(); -exit; +############################################################################### +# +# 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 +############################################################################### + +# Exit procedure + +# Indicatros file +let fileOut := "reactiveopf_results_indic.txt"; + +# Final status and error message +printf "%s %s\n","final_status", final_status > (fileOut); +if length(errorMessage) > 0 then { + printf "%s %Q\n","errorMessage",errorMessage > (fileOut); + printf "%s\n",errorMessage; +} +printf "%s %Q\n","ctime_start",ctime_start > (fileOut); + +# Other messages +if card(messagesInfo) > 0 then { + let temp1:=1; + for { message in messagesInfo } { + printf "messageInfo%i %Q\n",temp1,message > (fileOut); + let temp1:=temp1+1; + } +} + +# Other indicators +printf "\n" > (fileOut); +printf "%s %s\n","dcopf_status",dcopf_status > (fileOut); +printf "%s %s\n","operatingSystem",operatingSystem > (fileOut); +if length($OS) > 0 then { + printf "%s %Q\n","OS",$OS > (fileOut); # Windows + printf "%s %Q\n","COMPUTERNAME",$COMPUTERNAME > (fileOut); +} +if length($SHELL) > 0 then { + printf "%s %Q\n","SHELL",$SHELL > (fileOut); # Linux + printf "%s %Q\n","HOSTNAME",$HOSTNAME > (fileOut); +} +printf "%s %Q\n","directory",_cd > (fileOut); + +# Algorithmic parameters +printf "\n" > (fileOut); +printf "%s %s\n","log_level_ampl",log_level_ampl > (fileOut); +printf "%s %i\n","log_level_knitro",log_level_knitro > (fileOut); +printf "%s %f\n","Pnull",Pnull > (fileOut); +printf "%s %f\n","Znull",Znull > (fileOut); +printf "%s %f\n","epsilon_nominal_voltage",epsilon_nominal_voltage > (fileOut); +printf "%s %f\n","min_plausible_low_voltage_limit",min_plausible_low_voltage_limit > (fileOut); +printf "%s %f\n","max_plausible_high_voltage_limit",max_plausible_high_voltage_limit > (fileOut); +printf "%s %f\n","ignore_voltage_bounds",ignore_voltage_bounds > (fileOut); +printf "%s %s\n","buses_with_reactive_slacks",buses_with_reactive_slacks > (fileOut); +printf "%s %f\n","PQmax",PQmax > (fileOut); +printf "%s %f\n","defaultPmax",defaultPmax > (fileOut); +printf "%s %f\n","defaultPmin",defaultPmin > (fileOut); +printf "%s %f\n","defaultQmaxPmaxRatio",defaultQmaxPmaxRatio > (fileOut); +printf "%s %f\n","defaultQmin",defaultQmin > (fileOut); +printf "%s %f\n","defaultQmax",defaultQmax > (fileOut); +printf "%s %f\n","minimalQPrange",minimalQPrange > (fileOut); +printf "%s %f\n","default_variable_scaling_factor",default_variable_scaling_factor > (fileOut); +printf "%s %f\n","default_constraint_scaling_factor",default_constraint_scaling_factor > (fileOut); +printf "%s %f\n","reactive_slack_variable_scaling_factor",reactive_slack_variable_scaling_factor > (fileOut); +printf "%s %f\n","transformer_ratio_variable_scaling_factor",transformer_ratio_variable_scaling_factor > (fileOut); +printf "%s %f\n","shunt_variable_scaling_factor",shunt_variable_scaling_factor > (fileOut); + +close (fileOut); + +printf "\n*** End of file reactiveopfexit.run : %s\n",ctime(); +exit; diff --git a/open-reac/src/main/resources/openreac/reactiveopfoutput.run b/open-reac/src/main/resources/openreac/reactiveopfoutput.run index ecfc2bcd..10b5edeb 100644 --- a/open-reac/src/main/resources/openreac/reactiveopfoutput.run +++ b/open-reac/src/main/resources/openreac/reactiveopfoutput.run @@ -1,342 +1,378 @@ -############################################################################### -# -# Copyright (c) 2022 2023, 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/. -# -############################################################################### - -############################################################################### -# Reactive OPF -# Author: Jean Maeght 2022 2023 -# Author: Manuel Ruiz 2023 2024 -############################################################################### - - - -############################################################################### -# -# Writing results for shunts -# -############################################################################### -if final_status == "OK" then { - - let fileOut := "reactiveopf_results_shunts.csv"; - printf "#variant;num;bus;b(pu);Q(Mvar);section;\n" > (fileOut); - # Shunts which were already connected, with variable value - printf{(s,n) in SHUNT_VAR: (1,s,n) in SHUNT} "%i;%i;%i;%.3f;%.3f;%i;\n", - 1,s,n, - shunt_var[s,n], - base100MVA * shunt_var[s,n] * V[n]^2, - 0 #shunt_sections_count[1,s,n] # don't know what this is, so write 0 - > (fileOut); - # Shunts which were not connected, and which have been reconnected by reactiveopf, with variable value - printf {(s,n) in SHUNT_VAR: (1,s,-1) in SHUNT} "%i;%i;%i;%.3f;%.3f;%i;\n", - 1,s,n,shunt_var[s,n],base100MVA * shunt_var[s,n] * V[n]^2, - 0 #shunt_sections_count[1,s,-1] # don't know what this is, so write 0 - > (fileOut); - close (fileOut); - -} - - - -############################################################################### -# -# Writing results for SVC -# -############################################################################### -if final_status == "OK" then { - -let fileOut := "reactiveopf_results_static_var_compensators.csv"; -printf "#variant;num;bus;vRegul;V(pu);Q(Mvar);\n" > (fileOut); -printf{(s,n) in SVCON} "%i;%i;%i;%Q;%.3f;%.1f;\n", - 1,s,n, - svc_vregul[1,s,n], - V[n], - base100MVA * svc_qvar[s,n] * V[n]^2 - > (fileOut); -close (fileOut); - -} - - - -############################################################################### -# -# Writing results for units -# -############################################################################### -if final_status == "OK" then { - -let fileOut := "reactiveopf_results_generators.csv"; -printf "#variant;num;bus;vRegul;V(pu);targetP(MW);targetQ(Mvar);P(MW);Q(MW);\n" > (fileOut); - -# Units running -printf{(g,n) in UNITON} "%i;%i;%i;%Q;%.3f;%.1f;%.1f;%.1f;%.1f;\n", - 1,g,n, - unit_vregul[1,g,n], - V[n], - unit_Pc[1,g,n], - if (g,n) in UNIT_FIXQ then unit_Qc[1,g,n] else Q[g,n], - -P[g,n], # sign convention is strange, but this '-' is mandatory - if (g,n) in UNIT_FIXQ then -unit_Qc[1,g,n] else -Q[g,n] # sign convention is strange, but these '-' are mandatory - > (fileOut); - -# Units connected to the grid but not running -printf{(g,n) in UNITCC diff UNITON} "%i;%i;%i;%Q;%.3f;%i;%i;%i;%i;\n", - 1,g,n, - 'false', - V[n], - 0, - 0, - 0, - 0 - > (fileOut); -close (fileOut); - -} - - - -############################################################################### -# -# Writing results for VSC converters -# -############################################################################### -if final_status == "OK" then { - -let fileOut := "reactiveopf_results_vsc_converter_stations.csv"; -printf "#variant;num;bus;vRegul;targetV(pu);targetQ(Mvar);P(MW);Q(Mvar);\n" > (fileOut); -printf{(v,n) in VSCCONVON} "%i;%i;%i;%Q;%.3f;%.1f;%.1f;%.1f;\n", - 1,v,n, - vscconv_vregul[1,v,n], - V[n], - vscconv_qvar[v,n], - vscconv_P0[1,v,n], - vscconv_qvar[v,n] - > (fileOut); -close (fileOut); - -} - - - -############################################################################### -# -# Writing results for transformers -# -############################################################################### -if final_status == "OK" then { - -let fileOut := "reactiveopf_results_rtc.csv"; -printf "#variant;num;tap;\n" > (fileOut); -for{(qq,m,n) in BRANCHCC_REGL_VAR} { - let temp1 := - min{(1,regl_table[1,branch_ptrRegl[1,qq,m,n]],tap) in TAPS} - abs(branch_Ror_var[qq,m,n]-tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],tap]); - let temp2 := - min{(1,regl_table[1,branch_ptrRegl[1,qq,m,n]],tap) in TAPS: - abs(branch_Ror_var[qq,m,n]-tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],tap])<=1.00001*temp1}tap; - if 0 and card(BRANCHCC_REGL_VAR)<=10 then - printf "REGL=%Q ptrRegl=%i regl_table=%i Ror_var=%f min=%f tap=%i tap_ratio=%f err=%f\n", - branch_id[1,qq,m,n],branch_ptrRegl[1,qq,m,n],regl_table[1,branch_ptrRegl[1,qq,m,n]], - branch_Ror_var[qq,m,n],temp1, - temp2, - tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],temp2], - abs(branch_Ror_var[qq,m,n]-tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],temp2]) - ; - printf "%i;%i;%i;\n", - 1,qq,temp2 - > (fileOut); -} -close (fileOut); - -} - -# Useful during tests to create list of transformers -if 0 then { - for{(qq,m,n) in BRANCHCC_REGL: - substation_Vnomi[1,bus_substation[1,m]]>21 and substation_Vnomi[1,bus_substation[1,m]]<300 and - substation_Vnomi[1,bus_substation[1,n]]>21 and substation_Vnomi[1,bus_substation[1,n]]<300 and - (substation_Vnomi[1,bus_substation[1,m]]>120 or substation_Vnomi[1,bus_substation[1,n]]>120) and - (substation_Vnomi[1,bus_substation[1,m]]<120 or substation_Vnomi[1,bus_substation[1,n]]<120)}{ - printf{LOG_DEBUG} "1 %i %i %i %Q\n",qq,m,n,branch_id[1,qq,m,n] > param_transformers.txtt; - } -} - -############################################################################### -# -# Writing results for reactive slacks -# -############################################################################### -if final_status == "OK" -and card({n in BUSCC_SLACK: slack1_balance_Q[n]>Pnull or slack2_balance_Q[n]>Pnull}) > 0 -then { - -let fileOut := "reactiveopf_results_reactive_slacks.csv"; -printf "#variant;bus;slack_condensator(Mvar);slack_self(Mvar);id;substation;\n" > (fileOut); -printf{n in BUSCC_SLACK: slack1_balance_Q[n]>Pnull or slack2_balance_Q[n]>Pnull} - "%i;%i;%.2f;%.2f;%s;%s;\n", - 1,n, - if slack1_balance_Q[n]>Pnull then slack1_balance_Q[n] else 0, - if slack2_balance_Q[n]>Pnull then slack2_balance_Q[n] else 0, - '"' & bus_id[1,n] & '"', - '"' & substation_id[1,bus_substation[1,n]] & '"' - > (fileOut); -close (fileOut); - -} - - - -############################################################################### -# -# Writing results for buses states -# -############################################################################### -if final_status == "OK" then { - - let fileOut := "reactiveopf_results_voltages.csv"; - printf "#variant;bus;V(pu);theta(rad);id;\n" > (fileOut); - printf {n in BUSCC} "%i;%i;%.3f;%.3f;%s;\n", - 1, n, V[n], teta[n], '"' & bus_id[1,n] & '"' - > (fileOut); - close (fileOut); - -} - - - -############################################################################### -# -# Writing results for LCC converters -# -############################################################################### -# No results to be written since they are used with fixed P and Q red in ampl_network_lcc_converter_stations.txt - - - -############################################################################### -# -# Writing indicator file -# -############################################################################### -let fileOut := "reactiveopf_results_indic.txt"; - -printf "%s %s\n","final_status",final_status > (fileOut); -printf "%s %s\n","dcopf_status",dcopf_status > (fileOut); - -printf "\n" > (fileOut); -printf "%s %Q\n","ctime_start",ctime_start > (fileOut); -printf "%s %i\n","last_solve_result_num",solve_result_num > (fileOut); -printf "%s %i\n","nb_iter_last",nb_iter_last > (fileOut); -printf "%s %i\n","nb_iter_total",nb_iter_total > (fileOut); -printf "%s %f\n","_ampl_elapsed_time",_ampl_elapsed_time > (fileOut); -printf "%s %f\n","_total_solve_time",_total_solve_time > (fileOut); -printf "%s %i\n","total_time",_total_solve_time+_ampl_elapsed_time > (fileOut); - -printf "\n" > (fileOut); -printf "%s %s\n","operatingSystem",operatingSystem > (fileOut); -if length($OS) > 0 then { - printf "%s %Q\n","OS",$OS > (fileOut); # Windows - printf "%s %Q\n","COMPUTERNAME",$COMPUTERNAME > (fileOut); -} -if length($SHELL) > 0 then { - printf "%s %Q\n","SHELL",$SHELL > (fileOut); # Linux - printf "%s %Q\n","HOSTNAME",$HOSTNAME > (fileOut); -} -printf "%s %Q\n","directory",_cd > (fileOut); - -printf "\n" > (fileOut); -printf "%s %s\n","log_level_ampl",log_level_ampl > (fileOut); -printf "%s %i\n","log_level_knitro",log_level_knitro > (fileOut); -printf "%s %i\n","objective_choice",objective_choice > (fileOut); -printf "%s %f\n","ratio_voltage_target",ratio_voltage_target > (fileOut); -printf "%s %f\n","coeff_alpha",coeff_alpha > (fileOut); -printf "%s %f\n","Pnull",Pnull > (fileOut); -printf "%s %f\n","Znull",Znull > (fileOut); -printf "%s %f\n","epsilon_nominal_voltage",epsilon_nominal_voltage > (fileOut); -printf "%s %f\n","min_plausible_low_voltage_limit",min_plausible_low_voltage_limit > (fileOut); -printf "%s %f\n","max_plausible_high_voltage_limit",max_plausible_high_voltage_limit > (fileOut); -printf "%s %f\n","ignore_voltage_bounds",ignore_voltage_bounds > (fileOut); -printf "%s %s\n","buses_with_reactive_slacks",buses_with_reactive_slacks > (fileOut); -printf "%s %f\n","PQmax",PQmax > (fileOut); -printf "%s %f\n","defaultPmax",defaultPmax > (fileOut); -printf "%s %f\n","defaultPmin",defaultPmin > (fileOut); -printf "%s %f\n","defaultQmaxPmaxRatio",defaultQmaxPmaxRatio > (fileOut); -printf "%s %f\n","defaultQmin",defaultQmin > (fileOut); -printf "%s %f\n","defaultQmax",defaultQmax > (fileOut); -printf "%s %f\n","minimalQPrange",minimalQPrange > (fileOut); -printf "%s %f\n","default_variable_scaling_factor",default_variable_scaling_factor > (fileOut); -printf "%s %f\n","default_constraint_scaling_factor",default_constraint_scaling_factor > (fileOut); -printf "%s %f\n","reactive_slack_variable_scaling_factor",reactive_slack_variable_scaling_factor > (fileOut); -printf "%s %f\n","transformer_ratio_variable_scaling_factor",transformer_ratio_variable_scaling_factor > (fileOut); -printf "%s %f\n","shunt_variable_scaling_factor",shunt_variable_scaling_factor > (fileOut); - -printf "\n" > (fileOut); -printf "%s %i\n","nb_substations",card(SUBSTATIONS) > (fileOut); -printf "%s %i\n","nb_bus_in_data_file",card(BUS) > (fileOut); -printf "%s %i\n","nb_bus_in_ACDC_CC",card(BUS2) > (fileOut); -printf "%s %i\n","nb_bus_in_AC_CC",card(BUSCC) > (fileOut); -printf "%s %i\n","nb_bus_in_ACDC_but_out_AC_CC",card(BUS2 diff BUSCC) > (fileOut); -printf "%s %i\n","nb_bus_with_voltage_value",card(BUSVV) > (fileOut); -printf "%s %i\n","nb_bus_with_reactive_slacks",card(BUSCC_SLACK) > (fileOut); -printf "%s %i\n","nb_bus_without_reactive_slacks",card(BUSCC diff BUSCC_SLACK) > (fileOut); -printf "%s %i\n","nb_branch_in_data_file",card(BRANCH) > (fileOut); -printf "%s %i\n","nb_branch_in_AC_CC",card(BRANCHCC) > (fileOut); -printf "%s %i\n","nb_branch_with_nonsmall_impedance",card(BRANCHCC diff BRANCHZNULL) > (fileOut); -printf "%s %i\n","nb_branch_with_zero_or_small_impedance",card(BRANCHZNULL) > (fileOut); -printf "%s %i\n","nb_unit_in_data_file",card(UNIT) > (fileOut); -printf "%s %i\n","nb_unit_in_AC_CC",card(UNITCC) > (fileOut); -printf "%s %i\n","nb_unit_up_and_running",card(UNITON) > (fileOut); -printf "%s %i\n","nb_unit_with_variable_reactive_power",card(UNITON diff UNIT_FIXQ) > (fileOut); -printf "%s %i\n","nb_unit_with_fixed_reactive_power",card(UNIT_FIXQ) > (fileOut); -printf "%s %i\n","nb_load_in_data_file",card(LOAD) > (fileOut); -printf "%s %i\n","nb_load_in_AC_CC",card(LOADCC) > (fileOut); -printf "%s %i\n","nb_shunt_in_data_file",card(SHUNT) > (fileOut); -printf "%s %i\n","nb_shunt_connectable_or_in_AC_CC",card(SHUNTCC) > (fileOut); -printf "%s %i\n","nb_shunt_with_fixed_value",card(SHUNT_FIX) > (fileOut); -printf "%s %i\n","nb_shunt_with_variable_value",card(SHUNT_VAR) > (fileOut); -printf "%s %i\n","nb_transformers_with_variable_ratio",card(BRANCHCC_REGL_VAR) > (fileOut); -printf "%s %i\n","nb_transformers_with_fixed_ratio",card(BRANCHCC_REGL_FIX) > (fileOut); -printf "%s %i\n","nb_svc_in_data_file",card(SVC) > (fileOut); -printf "%s %i\n","nb_svc_in_AC_CC",card(SVCCC) > (fileOut); -printf "%s %i\n","nb_svc_up_and_operating",card(SVCON) > (fileOut); -printf "%s %i\n","nb_vsc_converter_in_data_file",card(VSCCONV) > (fileOut); -printf "%s %i\n","nb_vsc_converter_up_and_running",card(VSCCONVON) > (fileOut); -printf "%s %i\n","nb_lcc_converter_in_data_file",card(LCCCONV) > (fileOut); -printf "%s %i\n","nb_lcc_converter_up_and_running",card(LCCCONVON) > (fileOut); -printf "%s %i\n","nb_batteries",card(BATTERYCC) > (fileOut); -printf "%s %.1f\n","sum_batteries_pmax",sum{(b,k) in BATTERYCC} battery_Pmax[1,b,k] > (fileOut); -printf "%s %.1f\n","sum_batteries_pmin",sum{(b,k) in BATTERYCC} battery_Pmin[1,b,k] > (fileOut); - -printf "\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_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_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_ac %2f\n",min({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])) > (fileOut); - -printf "\n" > (fileOut); -printf "%s %i\n","nb_reactive_slacks",card({n in BUSCC_SLACK: slack1_balance_Q[n]>Pnull or slack2_balance_Q[n]>Pnull}) > (fileOut); -printf "%s %i\n","nb_slacks_condensator",card({n in BUSCC_SLACK: slack1_balance_Q[n]>Pnull}) > (fileOut); -printf "%s %.1f\n","sum_slacks_condensator",sum{n in BUSCC_SLACK} slack1_balance_Q[n] > (fileOut); -printf "%s %i\n","nb_slacks_self",card({n in BUSCC_SLACK: slack2_balance_Q[n]>Pnull}) > (fileOut); -printf "%s %.1f\n","sum_slacks_self",sum{n in BUSCC_SLACK} slack2_balance_Q[n] > (fileOut); - -# All messages added in messages container -if card(messagesInfo) > 0 then { - let temp1:=1; - for { message in messagesInfo } { - printf "messageInfo%i %Q\n",temp1,message > (fileOut); - let temp1:=temp1+1; - } -} -close (fileOut); +############################################################################### +# +# 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 +############################################################################### + + + +############################################################################### +# +# Writing results for shunts +# +############################################################################### +if final_status == "OK" then { + + let fileOut := "reactiveopf_results_shunts.csv"; + printf "#variant;num;bus;b(pu);Q(Mvar);section;\n" > (fileOut); + # Shunts which were already connected, with variable value + printf{(s,n) in SHUNT_VAR: (1,s,n) in SHUNT} "%i;%i;%i;%.3f;%.3f;%i;\n", + 1,s,n, + shunt_var[s,n], + base100MVA * shunt_var[s,n] * V[n]^2, + 0 #shunt_sections_count[1,s,n] # don't know what this is, so write 0 + > (fileOut); + # Shunts which were not connected, and which have been reconnected by reactiveopf, with variable value + printf {(s,n) in SHUNT_VAR: (1,s,-1) in SHUNT} "%i;%i;%i;%.3f;%.3f;%i;\n", + 1,s,n,shunt_var[s,n],base100MVA * shunt_var[s,n] * V[n]^2, + 0 #shunt_sections_count[1,s,-1] # don't know what this is, so write 0 + > (fileOut); + close (fileOut); + +} + + + +############################################################################### +# +# Writing results for SVC +# +############################################################################### +if final_status == "OK" then { + +let fileOut := "reactiveopf_results_static_var_compensators.csv"; +printf "#variant;num;bus;vRegul;V(pu);Q(Mvar);\n" > (fileOut); +printf{(s,n) in SVCON} "%i;%i;%i;%Q;%.3f;%.1f;\n", + 1,s,n, + svc_vregul[1,s,n], + V[n], + base100MVA * svc_qvar[s,n] * V[n]^2 + > (fileOut); +close (fileOut); + +} + + + +############################################################################### +# +# Writing results for units +# +############################################################################### +if final_status == "OK" then { + +let fileOut := "reactiveopf_results_generators.csv"; +printf "#variant;num;bus;vRegul;V(pu);targetP(MW);targetQ(Mvar);P(MW);Q(MW);\n" > (fileOut); + +# Units running +printf{(g,n) in UNITON} "%i;%i;%i;%Q;%.3f;%.1f;%.1f;%.1f;%.1f;\n", + 1,g,n, + unit_vregul[1,g,n], + V[n], + unit_Pc[1,g,n], + if (g,n) in UNIT_FIXQ then unit_Qc[1,g,n] else Q[g,n], + -P[g,n], # sign convention is strange, but this '-' is mandatory + if (g,n) in UNIT_FIXQ then -unit_Qc[1,g,n] else -Q[g,n] # sign convention is strange, but these '-' are mandatory + > (fileOut); + +# Units connected to the grid but not running +printf{(g,n) in UNITCC diff UNITON} "%i;%i;%i;%Q;%.3f;%i;%i;%i;%i;\n", + 1,g,n, + 'false', + V[n], + 0, + 0, + 0, + 0 + > (fileOut); +close (fileOut); + +} + + + +############################################################################### +# +# Writing results for VSC converters +# +############################################################################### +if final_status == "OK" then { + +let fileOut := "reactiveopf_results_vsc_converter_stations.csv"; +printf "#variant;num;bus;vRegul;targetV(pu);targetQ(Mvar);P(MW);Q(Mvar);\n" > (fileOut); +printf{(v,n) in VSCCONVON} "%i;%i;%i;%Q;%.3f;%.1f;%.1f;%.1f;\n", + 1,v,n, + vscconv_vregul[1,v,n], + V[n], + vscconv_qvar[v,n], + vscconv_P0[1,v,n], + vscconv_qvar[v,n] + > (fileOut); +close (fileOut); + +} + + + +############################################################################### +# +# Writing results for transformers +# +############################################################################### +if final_status == "OK" then { + +let fileOut := "reactiveopf_results_rtc.csv"; +printf "#variant;num;tap;\n" > (fileOut); +for{(qq,m,n) in BRANCHCC_REGL_VAR} { + let temp1 := + min{(1,regl_table[1,branch_ptrRegl[1,qq,m,n]],tap) in TAPS} + abs(branch_Ror_var[qq,m,n]-tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],tap]); + let temp2 := + min{(1,regl_table[1,branch_ptrRegl[1,qq,m,n]],tap) in TAPS: + abs(branch_Ror_var[qq,m,n]-tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],tap])<=1.00001*temp1}tap; + if 0 and card(BRANCHCC_REGL_VAR)<=10 then + printf "REGL=%Q ptrRegl=%i regl_table=%i Ror_var=%f min=%f tap=%i tap_ratio=%f err=%f\n", + branch_id[1,qq,m,n],branch_ptrRegl[1,qq,m,n],regl_table[1,branch_ptrRegl[1,qq,m,n]], + branch_Ror_var[qq,m,n],temp1, + temp2, + tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],temp2], + abs(branch_Ror_var[qq,m,n]-tap_ratio[1,regl_table[1,branch_ptrRegl[1,qq,m,n]],temp2]) + ; + printf "%i;%i;%i;\n", + 1,qq,temp2 + > (fileOut); +} +close (fileOut); + +} + +# Useful during tests to create list of transformers +if 0 then { + for{(qq,m,n) in BRANCHCC_REGL: + substation_Vnomi[1,bus_substation[1,m]]>21 and substation_Vnomi[1,bus_substation[1,m]]<300 and + substation_Vnomi[1,bus_substation[1,n]]>21 and substation_Vnomi[1,bus_substation[1,n]]<300 and + (substation_Vnomi[1,bus_substation[1,m]]>120 or substation_Vnomi[1,bus_substation[1,n]]>120) and + (substation_Vnomi[1,bus_substation[1,m]]<120 or substation_Vnomi[1,bus_substation[1,n]]<120)}{ + printf{LOG_DEBUG} "1 %i %i %i %Q\n",qq,m,n,branch_id[1,qq,m,n] > param_transformers.txtt; + } +} + +############################################################################### +# +# Writing results for reactive slacks +# +############################################################################### +if final_status == "OK" +and card({n in BUSCC_SLACK: slack1_balance_Q[n]>Pnull or slack2_balance_Q[n]>Pnull}) > 0 +then { + +let fileOut := "reactiveopf_results_reactive_slacks.csv"; +printf "#variant;bus;slack_condensator(Mvar);slack_self(Mvar);id;substation;\n" > (fileOut); +printf{n in BUSCC_SLACK: slack1_balance_Q[n]>Pnull or slack2_balance_Q[n]>Pnull} + "%i;%i;%.2f;%.2f;%s;%s;\n", + 1,n, + if slack1_balance_Q[n]>Pnull then slack1_balance_Q[n] else 0, + if slack2_balance_Q[n]>Pnull then slack2_balance_Q[n] else 0, + '"' & bus_id[1,n] & '"', + '"' & substation_id[1,bus_substation[1,n]] & '"' + > (fileOut); +close (fileOut); + +} + + + +############################################################################### +# +# Writing results for buses states +# +############################################################################### +if final_status == "OK" then { + + let fileOut := "reactiveopf_results_voltages.csv"; + printf "#variant;bus;V(pu);theta(rad);id;\n" > (fileOut); + printf {n in BUSCC} "%i;%i;%.3f;%.3f;%s;\n", + 1, n, V[n], teta[n], '"' & bus_id[1,n] & '"' + > (fileOut); + close (fileOut); + +} + + + +############################################################################### +# +# Writing results for LCC converters +# +############################################################################### +# No results to be written since they are used with fixed P and Q red in ampl_network_lcc_converter_stations.txt + + + +############################################################################### +# +# Writing indicator file +# +############################################################################### +let fileOut := "reactiveopf_results_indic.txt"; + +printf "%s %s\n","final_status",final_status > (fileOut); +printf "%s %s\n","dcopf_status",dcopf_status > (fileOut); + +printf "\n" > (fileOut); +printf "%s %Q\n","ctime_start",ctime_start > (fileOut); +printf "%s %i\n","last_solve_result_num",solve_result_num > (fileOut); +printf "%s %i\n","nb_iter_last",nb_iter_last > (fileOut); +printf "%s %i\n","nb_iter_total",nb_iter_total > (fileOut); +printf "%s %f\n","_ampl_elapsed_time",_ampl_elapsed_time > (fileOut); +printf "%s %f\n","_total_solve_time",_total_solve_time > (fileOut); +printf "%s %i\n","total_time",_total_solve_time+_ampl_elapsed_time > (fileOut); + +printf "\n" > (fileOut); +printf "%s %s\n","operatingSystem",operatingSystem > (fileOut); +if length($OS) > 0 then { + printf "%s %Q\n","OS",$OS > (fileOut); # Windows + printf "%s %Q\n","COMPUTERNAME",$COMPUTERNAME > (fileOut); +} +if length($SHELL) > 0 then { + printf "%s %Q\n","SHELL",$SHELL > (fileOut); # Linux + printf "%s %Q\n","HOSTNAME",$HOSTNAME > (fileOut); +} +printf "%s %Q\n","directory",_cd > (fileOut); + +printf "\n" > (fileOut); +printf "%s %s\n","log_level_ampl",log_level_ampl > (fileOut); +printf "%s %i\n","log_level_knitro",log_level_knitro > (fileOut); +printf "%s %i\n","objective_choice",objective_choice > (fileOut); +printf "%s %f\n","ratio_voltage_target",ratio_voltage_target > (fileOut); +printf "%s %f\n","coeff_alpha",coeff_alpha > (fileOut); +printf "%s %f\n","Pnull",Pnull > (fileOut); +printf "%s %f\n","Znull",Znull > (fileOut); +printf "%s %f\n","epsilon_nominal_voltage",epsilon_nominal_voltage > (fileOut); +printf "%s %f\n","min_plausible_low_voltage_limit",min_plausible_low_voltage_limit > (fileOut); +printf "%s %f\n","max_plausible_high_voltage_limit",max_plausible_high_voltage_limit > (fileOut); +printf "%s %f\n","ignore_voltage_bounds",ignore_voltage_bounds > (fileOut); +printf "%s %s\n","buses_with_reactive_slacks",buses_with_reactive_slacks > (fileOut); +printf "%s %f\n","PQmax",PQmax > (fileOut); +printf "%s %f\n","defaultPmax",defaultPmax > (fileOut); +printf "%s %f\n","defaultPmin",defaultPmin > (fileOut); +printf "%s %f\n","defaultQmaxPmaxRatio",defaultQmaxPmaxRatio > (fileOut); +printf "%s %f\n","defaultQmin",defaultQmin > (fileOut); +printf "%s %f\n","defaultQmax",defaultQmax > (fileOut); +printf "%s %f\n","minimalQPrange",minimalQPrange > (fileOut); +printf "%s %f\n","default_variable_scaling_factor",default_variable_scaling_factor > (fileOut); +printf "%s %f\n","default_constraint_scaling_factor",default_constraint_scaling_factor > (fileOut); +printf "%s %f\n","reactive_slack_variable_scaling_factor",reactive_slack_variable_scaling_factor > (fileOut); +printf "%s %f\n","transformer_ratio_variable_scaling_factor",transformer_ratio_variable_scaling_factor > (fileOut); +printf "%s %f\n","shunt_variable_scaling_factor",shunt_variable_scaling_factor > (fileOut); + +printf "\n" > (fileOut); +printf "%s %i\n","nb_substations",card(SUBSTATIONS) > (fileOut); +printf "%s %i\n","nb_bus_in_data_file",card(BUS) > (fileOut); +printf "%s %i\n","nb_bus_in_ACDC_CC",card(BUS2) > (fileOut); +printf "%s %i\n","nb_bus_in_AC_CC",card(BUSCC) > (fileOut); +printf "%s %i\n","nb_bus_in_ACDC_but_out_AC_CC",card(BUS2 diff BUSCC) > (fileOut); +printf "%s %i\n","nb_bus_with_voltage_value",card(BUSVV) > (fileOut); +printf "%s %i\n","nb_bus_with_reactive_slacks",card(BUSCC_SLACK) > (fileOut); +printf "%s %i\n","nb_bus_without_reactive_slacks",card(BUSCC diff BUSCC_SLACK) > (fileOut); +printf "%s %i\n","nb_branch_in_data_file",card(BRANCH) > (fileOut); +printf "%s %i\n","nb_branch_in_AC_CC",card(BRANCHCC) > (fileOut); +printf "%s %i\n","nb_branch_with_nonsmall_impedance",card(BRANCHCC diff BRANCHZNULL) > (fileOut); +printf "%s %i\n","nb_branch_with_zero_or_small_impedance",card(BRANCHZNULL) > (fileOut); +printf "%s %i\n","nb_unit_in_data_file",card(UNIT) > (fileOut); +printf "%s %i\n","nb_unit_in_AC_CC",card(UNITCC) > (fileOut); +printf "%s %i\n","nb_unit_up_and_running",card(UNITON) > (fileOut); +printf "%s %i\n","nb_unit_with_variable_reactive_power",card(UNITON diff UNIT_FIXQ) > (fileOut); +printf "%s %i\n","nb_unit_with_fixed_reactive_power",card(UNIT_FIXQ) > (fileOut); +printf "%s %i\n","nb_load_in_data_file",card(LOAD) > (fileOut); +printf "%s %i\n","nb_load_in_AC_CC",card(LOADCC) > (fileOut); +printf "%s %i\n","nb_shunt_in_data_file",card(SHUNT) > (fileOut); +printf "%s %i\n","nb_shunt_connectable_or_in_AC_CC",card(SHUNTCC) > (fileOut); +printf "%s %i\n","nb_shunt_with_fixed_value",card(SHUNT_FIX) > (fileOut); +printf "%s %i\n","nb_shunt_with_variable_value",card(SHUNT_VAR) > (fileOut); +printf "%s %i\n","nb_transformers_with_variable_ratio",card(BRANCHCC_REGL_VAR) > (fileOut); +printf "%s %i\n","nb_transformers_with_fixed_ratio",card(BRANCHCC_REGL_FIX) > (fileOut); +printf "%s %i\n","nb_svc_in_data_file",card(SVC) > (fileOut); +printf "%s %i\n","nb_svc_in_AC_CC",card(SVCCC) > (fileOut); +printf "%s %i\n","nb_svc_up_and_operating",card(SVCON) > (fileOut); +printf "%s %i\n","nb_vsc_converter_in_data_file",card(VSCCONV) > (fileOut); +printf "%s %i\n","nb_vsc_converter_up_and_running",card(VSCCONVON) > (fileOut); +printf "%s %i\n","nb_lcc_converter_in_data_file",card(LCCCONV) > (fileOut); +printf "%s %i\n","nb_lcc_converter_up_and_running",card(LCCCONVON) > (fileOut); +printf "%s %i\n","nb_batteries",card(BATTERYCC) > (fileOut); +printf "%s %.1f\n","sum_batteries_pmax",sum{(b,k) in BATTERYCC} battery_Pmax[1,b,k] > (fileOut); +printf "%s %.1f\n","sum_batteries_pmin",sum{(b,k) in BATTERYCC} battery_Pmin[1,b,k] > (fileOut); + +printf "\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_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_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_ac %2f\n",min({(qq,m,n) in BRANCHCC} (teta[m]-teta[n])) > (fileOut); + +printf "\n" > (fileOut); +printf "%s %i\n","nb_reactive_slacks",card({n in BUSCC_SLACK: slack1_balance_Q[n]>Pnull or slack2_balance_Q[n]>Pnull}) > (fileOut); +printf "%s %i\n","nb_slacks_condensator",card({n in BUSCC_SLACK: slack1_balance_Q[n]>Pnull}) > (fileOut); +printf "%s %.1f\n","sum_slacks_condensator",sum{n in BUSCC_SLACK} slack1_balance_Q[n] > (fileOut); +printf "%s %i\n","nb_slacks_self",card({n in BUSCC_SLACK: slack2_balance_Q[n]>Pnull}) > (fileOut); +printf "%s %.1f\n","sum_slacks_self",sum{n in BUSCC_SLACK} slack2_balance_Q[n] > (fileOut); + +# All messages added in messages container +if card(messagesInfo) > 0 then { + let temp1:=1; + for { message in messagesInfo } { + printf "messageInfo%i %Q\n",temp1,message > (fileOut); + let temp1:=temp1+1; + } +} +close (fileOut); + +# Write voltage information in debug file +let fileOut := "debug_bus.csv"; +printf{LOG_DEBUG} "#bus_id;Vnom;V;Vlb;Vub;Vmin_mod;Vmax_mod;Vmin_OK;Vmax_OK;Vmin_ori;Vmax_ori;sQ1;sQ2;\n" > (fileOut); +for {n in BUSCC} + printf{LOG_DEBUG} "%s;%i;%.4f;%.4f;%.4f;%.4f;%.4f;%s;%s;%.4f;%.4f;%.2f;%.2f;\n", + '"' & bus_id[1,n] & '"', + substation_Vnomi[1,bus_substation[1,n]], + V[n],V[n].lb,V[n].ub, + voltage_lower_bound[1,bus_substation[1,n]], + voltage_upper_bound[1,bus_substation[1,n]], + if V[n]voltage_upper_bound[1,bus_substation[1,n]] then "NOK" else "OK", + substation_Vmin[1,bus_substation[1,n]],substation_Vmax[1,bus_substation[1,n]], + if n in BUSCC_SLACK then max(slack1_balance_Q[n]-slack2_balance_Q[n],0) else -1, + if n in BUSCC_SLACK then max(slack2_balance_Q[n]-slack1_balance_Q[n],0) else -1 + > (fileOut); +close (fileOut); + +# Write units which are not in uniton (debug only) +let fileOut := "reactiveopf_results_generators_Pnull.csv"; +printf{LOG_DEBUG} "#variant;num;bus;vRegul;V(pu);targetP(MW);targetQ(Mvar);P(MW);Q(MW);id;bus_id;\n" > (fileOut); +for {(g,n) in UNITCC diff UNITON} + printf{LOG_DEBUG} "%i;%i;%i;%Q;%.3f;%.3f;%.3f;%.3f;%.3f;%s;%s;\n", + 1,g,n, + unit_vregul[1,g,n], + V[n], + unit_Pc[1,g,n], + unit_Qc[1,g,n], + unit_P0[1,g,n], + unit_Q0[1,g,n], + '"' & unit_id[1,g,n] & '"', + '"' & bus_id[1,n] & '"' + > (fileOut); +close (fileOut);