All Downloads are FREE. Search and download functionalities are using the official Maven repository.

openreac.reactiveopf.run Maven / Gradle / Ivy

The newest version!
###############################################################################
#
# 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;




© 2015 - 2024 Weber Informatics LLC | Privacy Policy