diff --git a/SUNSET-oper.sh b/SUNSET-oper.sh new file mode 100755 index 0000000000000000000000000000000000000000..e7f73e4813f6319098ab5e862733ddbe4978a266 --- /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 + if [ -z "$code_dir" ]; then + code_dir=./ + fi +} + +function get_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[@]} + 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} + 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 + + ## 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; + 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 $@ +# Retrieve startdate +get_startdate +# Launch Workflow +launch_auto diff --git a/recipe_maker.R b/recipe_maker.R new file mode 100644 index 0000000000000000000000000000000000000000..58105d7f1c8be3e2b431a7104f610f1d364fac74 --- /dev/null +++ b/recipe_maker.R @@ -0,0 +1,52 @@ +#! /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=] [--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. + +Arguments: + recipe_template path to the recipe template." + +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 +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) { + recipe$Run$auto_conf$expid <- arguments$expid +} + +recipe_name <- paste0(basename(file_path_sans_ext(arguments$recipe_template)), + "_oper_", start_date) +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)) diff --git a/recipe_oper_test.yml b/recipe_oper_test.yml new file mode 100644 index 0000000000000000000000000000000000000000..ed5137c405ee9d5a49ffcdba83b0d704360f4531 --- /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 + +