From c666c2d9b396a6bd572ab92511b418e48e92bcba Mon Sep 17 00:00:00 2001 From: vagudets Date: Fri, 25 Oct 2024 16:14:33 +0200 Subject: [PATCH 1/6] Add crontab wrapper script and recipe maker --- crontab-wrapper.sh | 117 +++++++++++++++++++++++++++++++++++++++++++++ recipe_maker.R | 43 +++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 crontab-wrapper.sh create mode 100644 recipe_maker.R diff --git a/crontab-wrapper.sh b/crontab-wrapper.sh new file mode 100644 index 00000000..f162baf7 --- /dev/null +++ b/crontab-wrapper.sh @@ -0,0 +1,117 @@ +#!/bin/bash +source /etc/profile.d/modules.sh +#set -eu +#set -v + +function usage { + echo "Usage: $0 -r= -e= -str= -sd=YYYYMMDD -h= " + echo " " + echo " -e, --expid: EXPID" + echo " [MANDATORY]" + echo " -r, --recipe: Recipe template" + echo " [MANDATORY]" + echo " -h, --horizon: Forecast horizon: 'subseasonal', 'seasonal', or 'decadal'" + echo " [MANDATORY]" + echo " -sd, --start_date: Start date (YYYYMMDD) of the forecast in YYYYMMDD" + echo " format. If -str is hcst, any year can be used." + echo " The default value is the current date." + echo " " +} +function parse_args { + for i in "$@"; do + case $i in + -e=*|--expid=*) + export expid=`echo $1 | sed -e 's/^[^=]*=//g'` + shift + ;; + -r=*|--recipe=*) + export recipe_template=`echo $1 | sed -e 's/^[^=]*=//g'` + shift + ;; + -sd=*|--start_date=*) + export start_date=`echo $1 | sed -e 's/^[^=]*=//g'` + shift + ;; + # -str=*|--stream=*) + # stream="${i#*=}" + # shift # past argument=value + # ;; + ## TODO: Is this needed? + -h=*|--horizon=*) + horizon="${i#*=}" + shift # past argument=value + ;; + -h|--help) + usage + shift # past argument with no value + ;; + *) + ;; + esac + done + if [ -z "$start_date" ]; then + start_date=$(date +%Y%m%d) + fi +} + +function check_startdate { + for dl_date in ${start_date[@]}; do + if [[ $horizon == "subseasonal" ]];then + week_day=$(date --date="$DL_DATE" +%a) + # Check date and stream + if [[ ${week_day} == Thu ]]; then + if [[ ${stream} == "fcst" ]]; then + sdate+=($dl_date) + elif [[ ${stream} == "hcst" ]]; then + sdate+=($(date --date="$dl_date +14 day" +%Y%m%d)) + else + echo "Stream neither fcst nor hcst" + exit 1 + fi + elif [[ ${week_day} == Mon && ${stream} == "hcst" ]]; then + sdate+=($(date --date="$dl_date +14 day" +%Y%m%d)) + else + usage + exit 0 + fi + else + sdate=${dl_date:0:6}01 + fi + done +} + +function launch_auto { + code_dir=./ + # code_dir="/esarchive/autosubmit/${expid}/conf/" + + source ${code_dir}/MODULES + launch_args=$(Rscript ${code_dir}/recipe_maker.R ${recipe_template} --sd=${sdate} --expid=${expid}) + + ## LAST LINE EDITED + echo "Launching operational..." + echo "Recipe template: ${recipe_template}" + echo "Main script: ${script}" + echo "Start date: ${sdate}" + echo "Using EXPID: ${expid}" + echo "[INFO] Running SUNSET launcher from ${code_dir}" + # sed -i 's/^DATELIST =.*/DATELIST = '"$(echo ${SDATE[@]})"'/' expdef_${EXPID}.conf + # sed -i 's/^STREAM =.*/STREAM = '${STREAM}'/' proj_${EXPID}.conf + bash ${code_dir}/launch_SUNSET.sh ${launch_args} + ssh $(whoami)@bscesautosubmit01.bsc.es "module load autosubmit/4.0.98-foss-2015a-Python-3.7.3; + autosubmit create ${expid} --noplot; + autosubmit refresh ${expid}; + # create must be done each time + autosubmit monitor ${expid}; + # Save for logging purposes (specify -fs to filter + # jobs when ensemble, -o {pdf,png,ps,svg} for different plot format files) + nohup autosubmit run -v ${expid} &" +} +######### +# MAIN +######### +parse_args $@ + +check_startdate +# +## Launch Workflow +launch_auto diff --git a/recipe_maker.R b/recipe_maker.R new file mode 100644 index 00000000..e78f0f7a --- /dev/null +++ b/recipe_maker.R @@ -0,0 +1,43 @@ +#! /usr/bin/env Rscript + +doc <- "Read an SUNSET recipe template and write a new recipe with the +specified start date, data stream (hcst or fcst) and Autosubmit expid, +in order to easily use SUNSET for operational analysis and verification. + +Usage: + recipe_maker.R [--sd=] [--stream=] [--expid=] + +Options: + -h --help Show usage. + --sd= Start date. + --stream= Stream (hcst or fcst). [default: fcst] + --expid= Autosubmit experiment ID. + +Arguments: + recipe_template path to the recipe template." + +library(docopt) +library(tools) +suppressMessages(source("tools/libs.R")) + +arguments <- docopt(doc = doc) + +recipe <- read_yaml(arguments$recipe_template) + +## TODO: Add exception for subseasonal case +recipe$Analysis$Time$sdate <- substring(arguments$sd, 5, 8) +if (arguments$stream == "fcst") { + recipe$Analysis$Time$fcst_year <- substring(arguments$sd, 1, 4) +} + +if (recipe$Run$autosubmit) { + recipe$Run$auto_conf$expid <- arguments$expid +} + +recipe_name <- paste0(basename(file_path_sans_ext(arguments$recipe_template)), + "_oper_", format(Sys.Date(), '%Y%m%d')) +recipe_file <- paste0(dirname(arguments$recipe_template), "/", recipe_name, ".yml") + +write_yaml(recipe, file = recipe_file) + +cat(paste(recipe_file, recipe$Run$auto_conf$script)) -- GitLab From 0e2aed7fe4749b053cb3d9c7a979338ce992250b Mon Sep 17 00:00:00 2001 From: vagudets Date: Fri, 25 Oct 2024 16:24:00 +0200 Subject: [PATCH 2/6] Fix typo --- crontab-wrapper.sh | 2 +- recipe_oper_test.yml | 90 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 recipe_oper_test.yml diff --git a/crontab-wrapper.sh b/crontab-wrapper.sh index f162baf7..af449c27 100644 --- a/crontab-wrapper.sh +++ b/crontab-wrapper.sh @@ -57,7 +57,7 @@ function parse_args { function check_startdate { for dl_date in ${start_date[@]}; do if [[ $horizon == "subseasonal" ]];then - week_day=$(date --date="$DL_DATE" +%a) + week_day=$(date --date="$dl_date" +%a) # Check date and stream if [[ ${week_day} == Thu ]]; then if [[ ${stream} == "fcst" ]]; then diff --git a/recipe_oper_test.yml b/recipe_oper_test.yml new file mode 100644 index 00000000..ed5137c4 --- /dev/null +++ b/recipe_oper_test.yml @@ -0,0 +1,90 @@ +Description: + Author: An-Chi Ho + Info: Compute Skills and Plot Scorecards with Autosubmit + +Analysis: + Horizon: seasonal + Variables: + - {name: tas, freq: monthly_mean} + Datasets: + System: # multiple systems for single model, split if Multimodel = F + - {name: ECMWF-SEAS5.1} + - {name: Meteo-France-System7} + Multimodel: + execute: False # single option + Reference: + - {name: ERA5} + Time: + sdate: # list, split + - '0101' + fcst_year: + hcst_start: '1993' # single option + hcst_end: '2003' # single option + ftime_min: 1 # single option + ftime_max: 6 # single option + Region: # multiple lists, split? Add region name if length(Region) > 1 + - {name: "global", latmin: -90, latmax: 90, lonmin: 0, lonmax: 359.9} + Regrid: + method: bilinear + type: to_system + Workflow: + Anomalies: + compute: yes + cross_validation: no + save: 'none' + Calibration: + method: raw + save: 'none' + Skill: + metric: mean_bias EnsCorr rps rpss crps crpss EnsSprErr # list, don't split + cross_validation: yes + save: 'all' + Statistics: + metric: cov std n_eff spread + save: 'all' + Probabilities: + percentiles: [[1/3, 2/3]] + save: 'none' + Scorecards: + execute: no # yes/no + regions: + Extra-tropical NH: {lon.min: 0, lon.max: 360, lat.min: 30, lat.max: 90} + Tropics: {lon.min: 0, lon.max: 360, lat.min: -30, lat.max: 30} + Extra-tropical SH : {lon.min: 0, lon.max: 360, lat.min: -30, lat.max: -90} + start_months: 'all' + metric: mean_bias enscorr rpss crpss enssprerr + metric_aggregation: 'score' + inf_to_na: TRUE # Optional, bool: set inf values in data to NA, default is FALSE table_label: NULL + fileout_label: NULL + col1_width: NULL + col2_width: NULL + calculate_diff: FALSE + ncores: 8 + remove_NAs: no # bool, don't split + Output_format: Scorecards # string, don't split + +################################################################################ +## Run CONFIGURATION +################################################################################ +Run: + Loglevel: INFO + Terminal: yes + filesystem: esarchive + output_dir: /esarchive/scratch/vagudets/auto-s2s-outputs/ + code_dir: /home/Earth/vagudets/git/auto-s2s/ + autosubmit: yes + # fill only if using autosubmit + auto_conf: + script: use_cases/ex1_2_autosubmit_scorecards/ex1_2-script.R # replace with the path to your script + expid: a6wq # replace with your EXPID + hpc_user: bsc032762 # replace with your hpc username + wallclock: 03:00 # hh:mm + processors_per_job: 16 + platform: nord3v2 + custom_directives: ['#SBATCH --exclusive'] + email_notifications: yes # enable/disable email notifications. Change it if you want to. + email_address: victoria.agudetse@bsc.es # replace with your email address + notify_completed: yes # notify me by email when a job finishes + notify_failed: no # notify me by email when a job fails + + -- GitLab From b80f06abb770ae51e59f9a2f6092d0e850212f31 Mon Sep 17 00:00:00 2001 From: vagudets Date: Fri, 14 Feb 2025 17:09:17 +0100 Subject: [PATCH 3/6] Add startdate to oper recipe name; include support for subseasonal --- recipe_maker.R | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/recipe_maker.R b/recipe_maker.R index e78f0f7a..58105d7f 100644 --- a/recipe_maker.R +++ b/recipe_maker.R @@ -5,11 +5,12 @@ specified start date, data stream (hcst or fcst) and Autosubmit expid, in order to easily use SUNSET for operational analysis and verification. Usage: - recipe_maker.R [--sd=] [--stream=] [--expid=] + recipe_maker.R [--sd=] [--horizon=] [--stream=] [--expid=] Options: -h --help Show usage. --sd= Start date. + --horizon= Forecast horizon (seasonal, subseasonal or decadal). --stream= Stream (hcst or fcst). [default: fcst] --expid= Autosubmit experiment ID. @@ -18,16 +19,24 @@ Arguments: library(docopt) library(tools) +## TODO: Maybe we don't need to load everything suppressMessages(source("tools/libs.R")) +options(error=function()traceback(2)) arguments <- docopt(doc = doc) +start_date <- arguments$sd recipe <- read_yaml(arguments$recipe_template) ## TODO: Add exception for subseasonal case -recipe$Analysis$Time$sdate <- substring(arguments$sd, 5, 8) -if (arguments$stream == "fcst") { - recipe$Analysis$Time$fcst_year <- substring(arguments$sd, 1, 4) +if (arguments$horizon %in% c("seasonal", "decadal")) { + recipe$Analysis$Time$sdate <- substring(start_date, 5, 8) + if (arguments$stream == "fcst") { + recipe$Analysis$Time$fcst_year <- substring(start_date, 1, 4) + } +} else if (arguments$horizon == "subseasonal") { + recipe$Analysis$Time$sdate <- start_date + recipe$Analysis$Time$fcst_year <- substring(start_date, 1, 4) } if (recipe$Run$autosubmit) { @@ -35,7 +44,7 @@ if (recipe$Run$autosubmit) { } recipe_name <- paste0(basename(file_path_sans_ext(arguments$recipe_template)), - "_oper_", format(Sys.Date(), '%Y%m%d')) + "_oper_", start_date) recipe_file <- paste0(dirname(arguments$recipe_template), "/", recipe_name, ".yml") write_yaml(recipe, file = recipe_file) -- GitLab From 20a95bffff638fe5cd590f080db2d9395a1b02e4 Mon Sep 17 00:00:00 2001 From: vagudets Date: Fri, 14 Feb 2025 17:10:15 +0100 Subject: [PATCH 4/6] Add script to run recipes operationally --- SUNSET-oper.sh | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100755 SUNSET-oper.sh diff --git a/SUNSET-oper.sh b/SUNSET-oper.sh new file mode 100755 index 00000000..5fc24410 --- /dev/null +++ b/SUNSET-oper.sh @@ -0,0 +1,114 @@ +#!/bin/bash +source /etc/profile.d/modules.sh + +#set -eu +#set -v + +function usage { + echo "Usage: $0 -e= -str= -sd=YYYYMMDD -h= " + echo " " + echo " -e, --expid: EXPID" + echo " [MANDATORY]" + echo " -r, --recipe: Recipe template" + echo " [MANDATORY]" + echo " -h, --horizon: Forecast horizon: 'subseasonal', 'seasonal', or 'decadal'" + echo " [MANDATORY]" + echo " -sd, --start_date: Start date (YYYYMMDD) of the forecast in YYYYMMDD" + echo " format. If -str is hcst, any year can be used." + echo " The default value is the current date." + echo " -cd, --code_dir: Directory where the SUNSET code is stored." + echo " The default value is the current working directory." + echo " " +} + + +function parse_args { + for i in "$@"; do + case $i in + -e=*|--expid=*) + export expid=`echo $1 | sed -e 's/^[^=]*=//g'` + shift + ;; + -r=*|--recipe=*) + export recipe_template=`echo $1 | sed -e 's/^[^=]*=//g'` + shift + ;; + -sd=*|--start_date=*) + export start_date=`echo $1 | sed -e 's/^[^=]*=//g'` + shift + ;; + -cd=*|--code_dir=*) + export code_dir=`echo $1 | sed -e 's/^[^=]*=//g'` + shift + ;; + -h=*|--horizon=*) + horizon="${i#*=}" + shift # past argument=value + ;; + -h|--help) + usage + shift # past argument with no value + ;; + *) + ;; + esac + done + if [ -z "$start_date" ]; then + start_date=$(date +%Y%m%d) + fi +} + +function check_startdate { + for dl_date in ${start_date[@]}; do + if [[ $horizon == "subseasonal" ]];then + week_day=$(date --date="$dl_date" +%a) + # Check date and stream + if [[ ${week_day} == Thu ]]; then + sdate=($dl_date) + else + sdate=$(date --date "last Thursday" +%Y%m%d) + fi + else + sdate=${dl_date:0:6}01 + fi + done +} + +function launch_auto { + + code_dir=${code_dir[@]} + # code_dir="/esarchive/autosubmit/${expid}/conf/" + ## LAST LINE EDITED + echo "Launching operational:" + echo "EXECUTION DATE = ${dl_date[@]}" + echo "STARTDATE = ${sdate[@]}" + echo "Using EXPID = ${expid}" + echo "[INFO] Running SUNSET launcher from ${code_dir}" + + cd ${code_dir} + source MODULES + launcher_args=$(Rscript recipe_maker.R ${recipe_template} --sd=${sdate[@]} --horizon=${horizon} --expid=${expid}) + bash ${code_dir}/launch_SUNSET.R ${launcher_args} --disable_unique_ID + + ## Set up ssh to AS machine; or do it directly as part of launch_SUNSET.R? + username=$(whoami) + ssh ${username}@bscesautosubmit01.bsc.es "module load autosubmit/4.0.98-foss-2015a-Python-3.7.3; + autosubmit create ${expid} --noplot; + autosubmit refresh ${expid}; + # create must be done each time + autosubmit monitor ${expid}; + # Save for logging purposes (specify -fs to filter + # jobs when ensemble, -o {pdf,png,ps,svg} for different plot format files) + nohup autosubmit run -v ${expid} &" +} + +######### +# MAIN +######### + +parse_args $@ + +check_startdate +# +## Launch Workflow +launch_auto -- GitLab From c5740a1f841fd1995b73bc91bd0d6d0b89f4544a Mon Sep 17 00:00:00 2001 From: vagudets Date: Tue, 18 Feb 2025 09:50:13 +0100 Subject: [PATCH 5/6] Update SUNSET-oper.sh launcher --- SUNSET-oper.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/SUNSET-oper.sh b/SUNSET-oper.sh index 5fc24410..e7f73e48 100755 --- a/SUNSET-oper.sh +++ b/SUNSET-oper.sh @@ -56,9 +56,12 @@ function parse_args { if [ -z "$start_date" ]; then start_date=$(date +%Y%m%d) fi + if [ -z "$code_dir" ]; then + code_dir=./ + fi } -function check_startdate { +function get_startdate { for dl_date in ${start_date[@]}; do if [[ $horizon == "subseasonal" ]];then week_day=$(date --date="$dl_date" +%a) @@ -77,12 +80,10 @@ function check_startdate { function launch_auto { code_dir=${code_dir[@]} - # code_dir="/esarchive/autosubmit/${expid}/conf/" - ## LAST LINE EDITED - echo "Launching operational:" - echo "EXECUTION DATE = ${dl_date[@]}" - echo "STARTDATE = ${sdate[@]}" - echo "Using EXPID = ${expid}" + echo "*** Launching operational: ***" + echo "[INFO] CURRENT TIME: $(date)" + echo "[INFO] STARTDATE: ${sdate[@]}" + echo "[INFO] Using EXPID: ${expid}" echo "[INFO] Running SUNSET launcher from ${code_dir}" cd ${code_dir} @@ -90,7 +91,7 @@ function launch_auto { launcher_args=$(Rscript recipe_maker.R ${recipe_template} --sd=${sdate[@]} --horizon=${horizon} --expid=${expid}) bash ${code_dir}/launch_SUNSET.R ${launcher_args} --disable_unique_ID - ## Set up ssh to AS machine; or do it directly as part of launch_SUNSET.R? + ## TODO: Set up ssh to AS machine; or do it directly as part of launch_SUNSET.R? username=$(whoami) ssh ${username}@bscesautosubmit01.bsc.es "module load autosubmit/4.0.98-foss-2015a-Python-3.7.3; autosubmit create ${expid} --noplot; @@ -107,8 +108,7 @@ function launch_auto { ######### parse_args $@ - -check_startdate -# -## Launch Workflow +# Retrieve startdate +get_startdate +# Launch Workflow launch_auto -- GitLab From b348510db50edd20b6519a48811186b2cbf5a06a Mon Sep 17 00:00:00 2001 From: vagudets Date: Tue, 18 Feb 2025 09:50:32 +0100 Subject: [PATCH 6/6] Remove redundant script --- crontab-wrapper.sh | 117 --------------------------------------------- 1 file changed, 117 deletions(-) delete mode 100644 crontab-wrapper.sh diff --git a/crontab-wrapper.sh b/crontab-wrapper.sh deleted file mode 100644 index af449c27..00000000 --- a/crontab-wrapper.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/bin/bash -source /etc/profile.d/modules.sh -#set -eu -#set -v - -function usage { - echo "Usage: $0 -r= -e= -str= -sd=YYYYMMDD -h= " - echo " " - echo " -e, --expid: EXPID" - echo " [MANDATORY]" - echo " -r, --recipe: Recipe template" - echo " [MANDATORY]" - echo " -h, --horizon: Forecast horizon: 'subseasonal', 'seasonal', or 'decadal'" - echo " [MANDATORY]" - echo " -sd, --start_date: Start date (YYYYMMDD) of the forecast in YYYYMMDD" - echo " format. If -str is hcst, any year can be used." - echo " The default value is the current date." - echo " " -} -function parse_args { - for i in "$@"; do - case $i in - -e=*|--expid=*) - export expid=`echo $1 | sed -e 's/^[^=]*=//g'` - shift - ;; - -r=*|--recipe=*) - export recipe_template=`echo $1 | sed -e 's/^[^=]*=//g'` - shift - ;; - -sd=*|--start_date=*) - export start_date=`echo $1 | sed -e 's/^[^=]*=//g'` - shift - ;; - # -str=*|--stream=*) - # stream="${i#*=}" - # shift # past argument=value - # ;; - ## TODO: Is this needed? - -h=*|--horizon=*) - horizon="${i#*=}" - shift # past argument=value - ;; - -h|--help) - usage - shift # past argument with no value - ;; - *) - ;; - esac - done - if [ -z "$start_date" ]; then - start_date=$(date +%Y%m%d) - fi -} - -function check_startdate { - for dl_date in ${start_date[@]}; do - if [[ $horizon == "subseasonal" ]];then - week_day=$(date --date="$dl_date" +%a) - # Check date and stream - if [[ ${week_day} == Thu ]]; then - if [[ ${stream} == "fcst" ]]; then - sdate+=($dl_date) - elif [[ ${stream} == "hcst" ]]; then - sdate+=($(date --date="$dl_date +14 day" +%Y%m%d)) - else - echo "Stream neither fcst nor hcst" - exit 1 - fi - elif [[ ${week_day} == Mon && ${stream} == "hcst" ]]; then - sdate+=($(date --date="$dl_date +14 day" +%Y%m%d)) - else - usage - exit 0 - fi - else - sdate=${dl_date:0:6}01 - fi - done -} - -function launch_auto { - code_dir=./ - # code_dir="/esarchive/autosubmit/${expid}/conf/" - - source ${code_dir}/MODULES - launch_args=$(Rscript ${code_dir}/recipe_maker.R ${recipe_template} --sd=${sdate} --expid=${expid}) - - ## LAST LINE EDITED - echo "Launching operational..." - echo "Recipe template: ${recipe_template}" - echo "Main script: ${script}" - echo "Start date: ${sdate}" - echo "Using EXPID: ${expid}" - echo "[INFO] Running SUNSET launcher from ${code_dir}" - # sed -i 's/^DATELIST =.*/DATELIST = '"$(echo ${SDATE[@]})"'/' expdef_${EXPID}.conf - # sed -i 's/^STREAM =.*/STREAM = '${STREAM}'/' proj_${EXPID}.conf - bash ${code_dir}/launch_SUNSET.sh ${launch_args} - ssh $(whoami)@bscesautosubmit01.bsc.es "module load autosubmit/4.0.98-foss-2015a-Python-3.7.3; - autosubmit create ${expid} --noplot; - autosubmit refresh ${expid}; - # create must be done each time - autosubmit monitor ${expid}; - # Save for logging purposes (specify -fs to filter - # jobs when ensemble, -o {pdf,png,ps,svg} for different plot format files) - nohup autosubmit run -v ${expid} &" -} -######### -# MAIN -######### -parse_args $@ - -check_startdate -# -## Launch Workflow -launch_auto -- GitLab