From 2cd6a589305a9ac9d3a9a0d2136e66e42f09d3bf Mon Sep 17 00:00:00 2001 From: "Henry R. Winterbottom" <49202169+HenryWinterbottom-NOAA@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:05:20 -0700 Subject: [PATCH 1/9] Moves UFS WM configuration files to `COM_CONF` (#2054) The UFS weather-model (WM) files are place in the COM_CONF path rather than the respective component model COM history paths. Resolves #2015 --- jobs/JGLOBAL_FORECAST | 2 +- scripts/exgdas_enkf_fcst.sh | 2 +- ush/forecast_postdet.sh | 9 ++++++--- ush/forecast_predet.sh | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/jobs/JGLOBAL_FORECAST b/jobs/JGLOBAL_FORECAST index e42c81eaa4..b2825af54f 100755 --- a/jobs/JGLOBAL_FORECAST +++ b/jobs/JGLOBAL_FORECAST @@ -46,7 +46,7 @@ declare -rx gcyc="${GDATE:8:2}" # Construct COM variables from templates (see config.com) YMD=${PDY} HH=${cyc} generate_com -rx COM_ATMOS_RESTART COM_ATMOS_INPUT COM_ATMOS_ANALYSIS \ - COM_ATMOS_HISTORY COM_ATMOS_MASTER COM_TOP + COM_ATMOS_HISTORY COM_ATMOS_MASTER COM_TOP COM_CONF RUN=${rCDUMP} YMD="${gPDY}" HH="${gcyc}" generate_com -rx \ COM_ATMOS_RESTART_PREV:COM_ATMOS_RESTART_TMPL diff --git a/scripts/exgdas_enkf_fcst.sh b/scripts/exgdas_enkf_fcst.sh index 7eb2a3a711..fd6136ddd2 100755 --- a/scripts/exgdas_enkf_fcst.sh +++ b/scripts/exgdas_enkf_fcst.sh @@ -131,7 +131,7 @@ for imem in $(seq "${ENSBEG}" "${ENSEND}"); do # Construct COM variables from templates (see config.com) # Can't make these read-only because we are looping over members MEMDIR="${memchar}" YMD=${PDY} HH=${cyc} generate_com -x COM_ATMOS_RESTART COM_ATMOS_INPUT COM_ATMOS_ANALYSIS \ - COM_ATMOS_HISTORY COM_ATMOS_MASTER + COM_ATMOS_HISTORY COM_ATMOS_MASTER COM_CONF MEMDIR="${memchar}" YMD="${gPDY}" HH="${gcyc}" generate_com -x COM_ATMOS_RESTART_PREV:COM_ATMOS_RESTART_TMPL diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index bafa61dd0e..ac59fcacac 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -514,7 +514,10 @@ FV3_out() { done else # No need to copy FV3 restart files when RUN=gfs or gefs - ${NCP} "${DATA}/input.nml" "${COM_ATMOS_HISTORY}/input.nml" + ${NCP} "${DATA}/input.nml" "${COM_CONF}/ufs.input.nml" + ${NCP} "${DATA}/model_configure" "${COM_CONF}/ufs.model_configure" + ${NCP} "${DATA}/nems.configure" "${COM_CONF}/ufs.nems.configure" + ${NCP} "${DATA}/diag_table" "${COM_CONF}/ufs.diag_table" fi echo "SUB ${FUNCNAME[0]}: Output data for FV3 copied" } @@ -853,7 +856,7 @@ MOM6_out() { # Copy MOM_input from DATA to COM_OCEAN_INPUT after the forecast is run (and successfull) if [[ ! -d ${COM_OCEAN_INPUT} ]]; then mkdir -p "${COM_OCEAN_INPUT}"; fi - ${NCP} "${DATA}/INPUT/MOM_input" "${COM_OCEAN_INPUT}/" + ${NCP} "${DATA}/INPUT/MOM_input" "${COM_CONF}/ufs.MOM_input" # TODO: mediator should have its own CMEPS_out() function # Copy mediator restarts from DATA to COM @@ -991,7 +994,7 @@ CICE_out() { # Copy ice_in namelist from DATA to COMOUTice after the forecast is run (and successfull) if [[ ! -d "${COM_ICE_INPUT}" ]]; then mkdir -p "${COM_ICE_INPUT}"; fi - ${NCP} "${DATA}/ice_in" "${COM_ICE_INPUT}/ice_in" + ${NCP} "${DATA}/ice_in" "${COM_CONF}/ufs.ice_in" } GOCART_rc() { diff --git a/ush/forecast_predet.sh b/ush/forecast_predet.sh index ce0b50f818..84d377019a 100755 --- a/ush/forecast_predet.sh +++ b/ush/forecast_predet.sh @@ -88,7 +88,7 @@ common_predet(){ tcyc=${scyc} fi - + mkdir -p "${COM_CONF}" cd "${DATA}" || ( echo "FATAL ERROR: Unable to 'cd ${DATA}', ABORT!"; exit 8 ) } From 0a0d6984e094d2a551d5d8331102142e7db13fc2 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Tue, 14 Nov 2023 14:08:26 -0500 Subject: [PATCH 2/9] Enable warm starting of the model for forecast-only mode (#2031) This PR: - adds an option to warm|cold start the ufs-weather-model when setting up an experiment for GFS/GEFS - adds the capability to stage FV3 restarts when the atmosphere is warm started from FV3 restarts. This would be used in the GEFS free-forecast for part of the reforecast capability. - If a coupled model is warm started for the atmosphere, also check if mediator restarts are present. If so, stage mediator restarts to allow restarting the coupled model. Fixes #2016 --- ci/cases/pr/C48_S2SA_gefs.yaml | 2 +- parm/config/gefs/config.base.emc.dyn | 7 +- scripts/exglobal_stage_ic.sh | 102 +++++++++++++++++++-------- workflow/setup_expt.py | 3 +- 4 files changed, 82 insertions(+), 32 deletions(-) diff --git a/ci/cases/pr/C48_S2SA_gefs.yaml b/ci/cases/pr/C48_S2SA_gefs.yaml index 927a979b13..2abbf0043e 100644 --- a/ci/cases/pr/C48_S2SA_gefs.yaml +++ b/ci/cases/pr/C48_S2SA_gefs.yaml @@ -9,9 +9,9 @@ arguments: resens: 48 nens: 2 gfs_cyc: 1 + start: cold comrot: {{ 'RUNTESTS' | getenv }}/COMROT expdir: {{ 'RUNTESTS' | getenv }}/EXPDIR - icsdir: {{ 'ICSDIR_ROOT' | getenv }}/C48C48mx500 idate: 2021032312 edate: 2021032312 yaml: {{ HOMEgfs }}/ci/platforms/gefs_ci_defaults.yaml diff --git a/parm/config/gefs/config.base.emc.dyn b/parm/config/gefs/config.base.emc.dyn index b62c921ed0..04fc396e5a 100644 --- a/parm/config/gefs/config.base.emc.dyn +++ b/parm/config/gefs/config.base.emc.dyn @@ -282,11 +282,16 @@ export NMEM_ENS=@NMEM_ENS@ export ENSMEM="000" export MEMDIR="mem${ENSMEM}" +export DOIAU="NO" # While we are not doing IAU, we may want to warm start w/ IAU in the future # Check if cycle is cold starting if [[ "${EXP_WARM_START}" = ".false." ]]; then - export IAU_FHROT=0 + export IAU_FHROT=0 else + if [[ "${DOIAU}" = "YES" ]]; then export IAU_FHROT=3 + else + export IAU_FHROT=0 + fi fi # turned on nsst in anal and/or fcst steps, and turn off rtgsst diff --git a/scripts/exglobal_stage_ic.sh b/scripts/exglobal_stage_ic.sh index 53042c7e45..6276255167 100755 --- a/scripts/exglobal_stage_ic.sh +++ b/scripts/exglobal_stage_ic.sh @@ -9,9 +9,9 @@ gPDY="${GDATE:0:8}" gcyc="${GDATE:8:2}" MEMDIR_ARRAY=() -if [[ "${RUN}" == "gefs" ]]; then +if [[ "${RUN:-}" = "gefs" ]]; then # Populate the member_dirs array based on the value of NMEM_ENS - for ((ii = 0; ii <= "${NMEM_ENS}"; ii++)); do + for ((ii = 0; ii <= "${NMEM_ENS:-0}"; ii++)); do MEMDIR_ARRAY+=("mem$(printf "%03d" "${ii}")") done else @@ -27,35 +27,58 @@ error_message() { ############################################################### for MEMDIR in "${MEMDIR_ARRAY[@]}"; do - # Stage the FV3 initial conditions to ROTDIR (cold start) - YMD=${PDY} HH=${cyc} generate_com COM_ATMOS_INPUT - [[ ! -d "${COM_ATMOS_INPUT}" ]] && mkdir -p "${COM_ATMOS_INPUT}" - src="${BASE_CPLIC}/${CPL_ATMIC}/${PDY}${cyc}/${MEMDIR}/atmos/gfs_ctrl.nc" - tgt="${COM_ATMOS_INPUT}/gfs_ctrl.nc" - ${NCP} "${src}" "${tgt}" - rc=$? - ((rc != 0)) && error_message "${src}" "${tgt}" "${rc}" - err=$((err + rc)) - for ftype in gfs_data sfc_data; do - for ((tt = 1; tt <= 6; tt++)); do - src="${BASE_CPLIC}/${CPL_ATMIC}/${PDY}${cyc}/${MEMDIR}/atmos/${ftype}.tile${tt}.nc" - tgt="${COM_ATMOS_INPUT}/${ftype}.tile${tt}.nc" - ${NCP} "${src}" "${tgt}" - rc=$? - tgt="${COM_ATMOS_INPUT}/${ftype}.tile${tt}.nc" + + # Stage atmosphere initial conditions to ROTDIR + if [[ ${EXP_WARM_START:-".false."} = ".true." ]]; then + # Stage the FV3 restarts to ROTDIR (warm start) + RUN=${rCDUMP} YMD=${gPDY} HH=${gcyc} generate_com COM_ATMOS_RESTART_PREV:COM_ATMOS_RESTART_TMPL + [[ ! -d "${COM_ATMOS_RESTART_PREV}" ]] && mkdir -p "${COM_ATMOS_RESTART_PREV}" + for ftype in coupler.res fv_core.res.nc; do + src="${BASE_CPLIC}/${CPL_ATMIC:-}/${PDY}${cyc}/${MEMDIR}/atmos/${PDY}.${cyc}0000.${ftype}" + tgt="${COM_ATMOS_RESTART_PREV}/${PDY}.${cyc}0000.${ftype}" ${NCP} "${src}" "${tgt}" rc=$? ((rc != 0)) && error_message "${src}" "${tgt}" "${rc}" err=$((err + rc)) done - done + for ftype in ca_data fv_core.res fv_srf_wnd.res fv_tracer.res phy_data sfc_data; do + for ((tt = 1; tt <= 6; tt++)); do + src="${BASE_CPLIC}/${CPL_ATMIC:-}/${PDY}${cyc}/${MEMDIR}/atmos/${PDY}.${cyc}0000.${ftype}.tile${tt}.nc" + tgt="${COM_ATMOS_RESTART_PREV}/${PDY}.${cyc}0000.${ftype}.tile${tt}.nc" + ${NCP} "${src}" "${tgt}" + rc=$? + ((rc != 0)) && error_message "${src}" "${tgt}" "${rc}" + err=$((err + rc)) + done + done + else + # Stage the FV3 cold-start initial conditions to ROTDIR + YMD=${PDY} HH=${cyc} generate_com COM_ATMOS_INPUT + [[ ! -d "${COM_ATMOS_INPUT}" ]] && mkdir -p "${COM_ATMOS_INPUT}" + src="${BASE_CPLIC}/${CPL_ATMIC:-}/${PDY}${cyc}/${MEMDIR}/atmos/gfs_ctrl.nc" + tgt="${COM_ATMOS_INPUT}/gfs_ctrl.nc" + ${NCP} "${src}" "${tgt}" + rc=$? + ((rc != 0)) && error_message "${src}" "${tgt}" "${rc}" + err=$((err + rc)) + for ftype in gfs_data sfc_data; do + for ((tt = 1; tt <= 6; tt++)); do + src="${BASE_CPLIC}/${CPL_ATMIC:-}/${PDY}${cyc}/${MEMDIR}/atmos/${ftype}.tile${tt}.nc" + tgt="${COM_ATMOS_INPUT}/${ftype}.tile${tt}.nc" + ${NCP} "${src}" "${tgt}" + rc=$? + ((rc != 0)) && error_message "${src}" "${tgt}" "${rc}" + err=$((err + rc)) + done + done + fi # Stage ocean initial conditions to ROTDIR (warm start) if [[ "${DO_OCN:-}" = "YES" ]]; then - RUN=${rCDUMP} YMD=${gPDY} HH=${gcyc} generate_com COM_OCEAN_RESTART - [[ ! -d "${COM_OCEAN_RESTART}" ]] && mkdir -p "${COM_OCEAN_RESTART}" - src="${BASE_CPLIC}/${CPL_OCNIC}/${PDY}${cyc}/${MEMDIR}/ocean/${PDY}.${cyc}0000.MOM.res.nc" - tgt="${COM_OCEAN_RESTART}/${PDY}.${cyc}0000.MOM.res.nc" + RUN=${rCDUMP} YMD=${gPDY} HH=${gcyc} generate_com COM_OCEAN_RESTART_PREV:COM_OCEAN_RESTART_TMPL + [[ ! -d "${COM_OCEAN_RESTART_PREV}" ]] && mkdir -p "${COM_OCEAN_RESTART_PREV}" + src="${BASE_CPLIC}/${CPL_OCNIC:-}/${PDY}${cyc}/${MEMDIR}/ocean/${PDY}.${cyc}0000.MOM.res.nc" + tgt="${COM_OCEAN_RESTART_PREV}/${PDY}.${cyc}0000.MOM.res.nc" ${NCP} "${src}" "${tgt}" rc=$? ((rc != 0)) && error_message "${src}" "${tgt}" "${rc}" @@ -66,7 +89,7 @@ for MEMDIR in "${MEMDIR_ARRAY[@]}"; do ;; "025" ) for nn in $(seq 1 3); do - src="${BASE_CPLIC}/${CPL_OCNIC}/${PDY}${cyc}/${MEMDIR}/ocean/${PDY}.${cyc}0000.MOM.res_${nn}.nc" + src="${BASE_CPLIC}/${CPL_OCNIC:-}/${PDY}${cyc}/${MEMDIR}/ocean/${PDY}.${cyc}0000.MOM.res_${nn}.nc" tgt="${COM_OCEAN_RESTART}/${PDY}.${cyc}0000.MOM.res_${nn}.nc" ${NCP} "${src}" "${tgt}" rc=$? @@ -80,13 +103,33 @@ for MEMDIR in "${MEMDIR_ARRAY[@]}"; do err=$((err + rc)) ;; esac + + # TODO: Do mediator restarts exists in a ATMW configuration? + # TODO: No mediator is presumably involved in an ATMA configuration + if [[ ${EXP_WARM_START:-".false."} = ".true." ]]; then + # Stage the mediator restarts to ROTDIR (warm start/restart the coupled model) + RUN=${rCDUMP} YMD=${gPDY} HH=${gcyc} generate_com COM_MED_RESTART_PREV:COM_MED_RESTART_TMPL + [[ ! -d "${COM_MED_RESTART_PREV}" ]] && mkdir -p "${COM_MED_RESTART_PREV}" + src="${BASE_CPLIC}/${CPL_MEDIC:-}/${PDY}${cyc}/${MEMDIR}/med/${PDY}.${cyc}0000.ufs.cpld.cpl.r.nc" + tgt="${COM_MED_RESTART_PREV}/${PDY}.${cyc}0000.ufs.cpld.cpl.r.nc" + if [[ -f "${src}" ]]; then + ${NCP} "${src}" "${tgt}" + rc=$? + ((rc != 0)) && error_message "${src}" "${tgt}" "${rc}" + err=$((err + rc)) + else + echo "WARNING: No mediator restarts available with warm_start=${EXP_WARM_START}" + fi + fi + fi + # Stage ice initial conditions to ROTDIR (warm start) if [[ "${DO_ICE:-}" = "YES" ]]; then - RUN=${rCDUMP} YMD=${gPDY} HH=${gcyc} generate_com COM_ICE_RESTART - [[ ! -d "${COM_ICE_RESTART}" ]] && mkdir -p "${COM_ICE_RESTART}" - src="${BASE_CPLIC}/${CPL_ICEIC}/${PDY}${cyc}/${MEMDIR}/ice/${PDY}.${cyc}0000.cice_model.res.nc" - tgt="${COM_ICE_RESTART}/${PDY}.${cyc}0000.cice_model.res.nc" + RUN=${rCDUMP} YMD=${gPDY} HH=${gcyc} generate_com COM_ICE_RESTART_PREV:COM_ICE_RESTART_TMPL + [[ ! -d "${COM_ICE_RESTART_PREV}" ]] && mkdir -p "${COM_ICE_RESTART_PREV}" + src="${BASE_CPLIC}/${CPL_ICEIC:-}/${PDY}${cyc}/${MEMDIR}/ice/${PDY}.${cyc}0000.cice_model.res.nc" + tgt="${COM_ICE_RESTART_PREV}/${PDY}.${cyc}0000.cice_model.res.nc" ${NCP} "${src}" "${tgt}" rc=$? ((rc != 0)) && error_message "${src}" "${tgt}" "${rc}" @@ -98,7 +141,7 @@ for MEMDIR in "${MEMDIR_ARRAY[@]}"; do YMD=${PDY} HH=${cyc} generate_com COM_WAVE_RESTART [[ ! -d "${COM_WAVE_RESTART}" ]] && mkdir -p "${COM_WAVE_RESTART}" for grdID in ${waveGRD}; do # TODO: check if this is a bash array; if so adjust - src="${BASE_CPLIC}/${CPL_WAVIC}/${PDY}${cyc}/${MEMDIR}/wave/${PDY}.${cyc}0000.restart.${grdID}" + src="${BASE_CPLIC}/${CPL_WAVIC:-}/${PDY}${cyc}/${MEMDIR}/wave/${PDY}.${cyc}0000.restart.${grdID}" tgt="${COM_WAVE_RESTART}/${PDY}.${cyc}0000.restart.${grdID}" ${NCP} "${src}" "${tgt}" rc=$? @@ -108,6 +151,7 @@ for MEMDIR in "${MEMDIR_ARRAY[@]}"; do fi done # for MEMDIR in "${MEMDIR_ARRAY[@]}"; do + ############################################################### # Check for errors and exit if any of the above failed if [[ "${err}" -ne 0 ]]; then diff --git a/workflow/setup_expt.py b/workflow/setup_expt.py index a808cafd91..b1fa439052 100755 --- a/workflow/setup_expt.py +++ b/workflow/setup_expt.py @@ -432,7 +432,8 @@ def _gfs_or_gefs_forecast_args(parser): return parser def _gefs_args(parser): - parser.add_argument('--start', help=SUPPRESS, type=str, required=False, default='cold') + parser.add_argument('--start', help='restart mode: warm or cold', type=str, + choices=['warm', 'cold'], required=False, default='cold') parser.add_argument('--configdir', help=SUPPRESS, type=str, required=False, default=os.path.join(_top, 'parm/config/gefs')) parser.add_argument('--yaml', help='Defaults to substitute from', type=str, required=False, From 42d7f2f0c48fab898b764e09cfbbd7a9fabbae08 Mon Sep 17 00:00:00 2001 From: Kate Friedman Date: Tue, 14 Nov 2023 17:54:29 -0500 Subject: [PATCH 3/9] Separate tracker and genesis jobs from vrfy job (#2058) This PR creates new individual jobs for the tracker and genesis jobs that are being pulled out of the `vrfy` job (issue #235). The `tracker` and `genesis` jobs will be on by default while the `genesis_fsu` job will be off by default. This mimics the current settings in the `vrfy` job. No enhancements or upgrades are made to the jobs themselves in this PR, only to separate them from the `vrfy` job. However, one change compared to how they currently run in the `vrfy` job is to no longer run the `tracker` in the gdas suite. This mimics how the `ens_tracker` package is run in operations (gfs only). Changes in this PR: 1. Create rocoto job scripts for tracker/genesis jobs. 2. Create configs for tracker/genesis jobs, as well as `config.tropcy` for shared settings. 3. Add tracker/genesis jobs to `config.resources`; use resources from the ecf scripts for `ens_tracker` jobs in operations 4. Add tracker/genesis jobs to rocoto setup for both cycled and forecast-only modes. 5. Update arguments for `jjob_header.sh` script in tracker/genesis JJOB scripts to use specific job names and configs instead of vrfy. 6. Rename `tracker_ver` to `ens_tracker_ver` in version files to mimic variable within tracker package. 7. Rename and move tracker/genesis switches to `config.base`. 8. Remove tracker/genesis jobs from `vrfy` job (`jobs/rocoto/vrfy` and `config.vrfy`). 9. Reduce vrfy job resources to accommodate tasks having been removed. Refs #235 Resolves #1988 Resolves #2048 --- jobs/JGFS_ATMOS_CYCLONE_GENESIS | 2 +- jobs/JGFS_ATMOS_CYCLONE_TRACKER | 2 +- jobs/JGFS_ATMOS_FSU_GENESIS | 2 +- jobs/rocoto/genesis.sh | 20 ++++++++ jobs/rocoto/genesis_fsu.sh | 20 ++++++++ jobs/rocoto/tracker.sh | 20 ++++++++ jobs/rocoto/vrfy.sh | 28 ------------ parm/config/gfs/config.base.emc.dyn | 3 ++ parm/config/gfs/config.genesis | 12 +++++ parm/config/gfs/config.genesis_fsu | 12 +++++ parm/config/gfs/config.resources | 35 +++++++++++--- parm/config/gfs/config.tracker | 12 +++++ parm/config/gfs/config.tropcy | 15 ++++++ parm/config/gfs/config.vrfy | 37 --------------- versions/run.hera.ver | 2 +- versions/run.jet.ver | 2 +- versions/run.orion.ver | 2 +- versions/run.s4.ver | 2 +- versions/run.wcoss2.ver | 2 +- workflow/applications/applications.py | 3 ++ workflow/applications/gfs_cycled.py | 18 ++++++++ workflow/applications/gfs_forecast_only.py | 18 ++++++++ workflow/rocoto/gfs_tasks.py | 53 ++++++++++++++++++++-- workflow/rocoto/tasks.py | 1 + 24 files changed, 239 insertions(+), 84 deletions(-) create mode 100755 jobs/rocoto/genesis.sh create mode 100755 jobs/rocoto/genesis_fsu.sh create mode 100755 jobs/rocoto/tracker.sh create mode 100644 parm/config/gfs/config.genesis create mode 100644 parm/config/gfs/config.genesis_fsu create mode 100644 parm/config/gfs/config.tracker create mode 100644 parm/config/gfs/config.tropcy diff --git a/jobs/JGFS_ATMOS_CYCLONE_GENESIS b/jobs/JGFS_ATMOS_CYCLONE_GENESIS index d2d147125c..5ac97e079c 100755 --- a/jobs/JGFS_ATMOS_CYCLONE_GENESIS +++ b/jobs/JGFS_ATMOS_CYCLONE_GENESIS @@ -1,7 +1,7 @@ #! /usr/bin/env bash source "${HOMEgfs}/ush/preamble.sh" -source "${HOMEgfs}/ush/jjob_header.sh" -e "vrfy" -c "base vrfy" +source "${HOMEgfs}/ush/jjob_header.sh" -e "genesis" -c "base genesis" ############################################## diff --git a/jobs/JGFS_ATMOS_CYCLONE_TRACKER b/jobs/JGFS_ATMOS_CYCLONE_TRACKER index 09ec630009..a91d8e3c5b 100755 --- a/jobs/JGFS_ATMOS_CYCLONE_TRACKER +++ b/jobs/JGFS_ATMOS_CYCLONE_TRACKER @@ -1,7 +1,7 @@ #! /usr/bin/env bash source "${HOMEgfs}/ush/preamble.sh" -source "${HOMEgfs}/ush/jjob_header.sh" -e "vrfy" -c "base vrfy" +source "${HOMEgfs}/ush/jjob_header.sh" -e "tracker" -c "base tracker" export COMPONENT="atmos" diff --git a/jobs/JGFS_ATMOS_FSU_GENESIS b/jobs/JGFS_ATMOS_FSU_GENESIS index c31037aa08..cc730e21bb 100755 --- a/jobs/JGFS_ATMOS_FSU_GENESIS +++ b/jobs/JGFS_ATMOS_FSU_GENESIS @@ -1,7 +1,7 @@ #! /usr/bin/env bash source "${HOMEgfs}/ush/preamble.sh" -source "${HOMEgfs}/ush/jjob_header.sh" -e "vrfy" -c "base vrfy" +source "${HOMEgfs}/ush/jjob_header.sh" -e "genesis_fsu" -c "base genesis_fsu" export COMPONENT="atmos" diff --git a/jobs/rocoto/genesis.sh b/jobs/rocoto/genesis.sh new file mode 100755 index 0000000000..009a7006ef --- /dev/null +++ b/jobs/rocoto/genesis.sh @@ -0,0 +1,20 @@ +#! /usr/bin/env bash + +source "${HOMEgfs}/ush/preamble.sh" + +############################################################### +# Source FV3GFS workflow modules +source "${HOMEgfs}/ush/load_fv3gfs_modules.sh" +status=$? +(( status != 0 )) && exit "${status}" + +export job="genesis" +export jobid="${job}.$$" + +############################################################### +# Execute the JJOB + +"${HOMEgfs}/jobs/JGFS_ATMOS_CYCLONE_GENESIS" +status=$? + +exit "${status}" diff --git a/jobs/rocoto/genesis_fsu.sh b/jobs/rocoto/genesis_fsu.sh new file mode 100755 index 0000000000..05c0ff8827 --- /dev/null +++ b/jobs/rocoto/genesis_fsu.sh @@ -0,0 +1,20 @@ +#! /usr/bin/env bash + +source "${HOMEgfs}/ush/preamble.sh" + +############################################################### +# Source FV3GFS workflow modules +source "${HOMEgfs}/ush/load_fv3gfs_modules.sh" +status=$? +(( status != 0 )) && exit "${status}" + +export job="genesis_fsu" +export jobid="${job}.$$" + +############################################################### +# Execute the JJOB + +"${HOMEgfs}/jobs/JGFS_ATMOS_FSU_GENESIS" +status=$? + +exit "${status}" diff --git a/jobs/rocoto/tracker.sh b/jobs/rocoto/tracker.sh new file mode 100755 index 0000000000..3e2efd644e --- /dev/null +++ b/jobs/rocoto/tracker.sh @@ -0,0 +1,20 @@ +#! /usr/bin/env bash + +source "${HOMEgfs}/ush/preamble.sh" + +############################################################### +# Source FV3GFS workflow modules +source "${HOMEgfs}/ush/load_fv3gfs_modules.sh" +status=$? +(( status != 0 )) && exit "${status}" + +export job="tracker" +export jobid="${job}.$$" + +############################################################### +# Execute the JJOB + +"${HOMEgfs}/jobs/JGFS_ATMOS_CYCLONE_TRACKER" +status=$? + +exit "${status}" diff --git a/jobs/rocoto/vrfy.sh b/jobs/rocoto/vrfy.sh index 67ac43e137..1c0cf61d3b 100755 --- a/jobs/rocoto/vrfy.sh +++ b/jobs/rocoto/vrfy.sh @@ -52,34 +52,6 @@ if [[ "${RUNMOS}" == "YES" && "${CDUMP}" == "gfs" ]]; then fi -################################################################################ -echo -echo "=============== START TO RUN CYCLONE TRACK VERIFICATION ===============" -if [[ ${VRFYTRAK} = "YES" ]]; then - - COMINsyn=${COMINsyn:-$(compath.py "${envir}/com/gfs/${gfs_ver}")/syndat} - export COMINsyn - - ${TRACKERSH} -fi - - -################################################################################ -echo -echo "=============== START TO RUN CYCLONE GENESIS VERIFICATION ===============" -if [[ ${VRFYGENESIS} = "YES" && "${CDUMP}" = "gfs" ]]; then - ${GENESISSH} -fi - - -################################################################################ -echo -echo "=============== START TO RUN CYCLONE GENESIS VERIFICATION (FSU) ===============" -if [[ ${VRFYFSU} = "YES" && "${CDUMP}" = "gfs" ]]; then - ${GENESISFSU} -fi - - ############################################################### # Force Exit out cleanly cd "${DATAROOT}" diff --git a/parm/config/gfs/config.base.emc.dyn b/parm/config/gfs/config.base.emc.dyn index 9892665ef2..179f37388f 100644 --- a/parm/config/gfs/config.base.emc.dyn +++ b/parm/config/gfs/config.base.emc.dyn @@ -57,6 +57,9 @@ export DO_BUFRSND="NO" # BUFR sounding products export DO_GEMPAK="NO" # GEMPAK products export DO_AWIPS="NO" # AWIPS products export DO_VRFY="YES" # VRFY step +export DO_TRACKER="YES" # Hurricane track verification +export DO_GENESIS="YES" # Cyclone genesis verification +export DO_GENESIS_FSU="NO" # Cyclone genesis verification (FSU) export DO_VERFOZN="YES" # Ozone data assimilation monitoring export DO_VERFRAD="YES" # Radiance data assimilation monitoring export DO_VMINMON="YES" # GSI minimization monitoring diff --git a/parm/config/gfs/config.genesis b/parm/config/gfs/config.genesis new file mode 100644 index 0000000000..62a1bf88c0 --- /dev/null +++ b/parm/config/gfs/config.genesis @@ -0,0 +1,12 @@ +#! /usr/bin/env bash + +########## config.genesis ########## +echo "BEGIN: config.genesis" + +# Get task specific resources +. "${EXPDIR}/config.resources" genesis + +# Get tropcy settings +. "${EXPDIR}/config.tropcy" + +echo "END: config.genesis" diff --git a/parm/config/gfs/config.genesis_fsu b/parm/config/gfs/config.genesis_fsu new file mode 100644 index 0000000000..13948592c4 --- /dev/null +++ b/parm/config/gfs/config.genesis_fsu @@ -0,0 +1,12 @@ +#! /usr/bin/env bash + +########## config.genesis_fsu ########## +echo "BEGIN: config.genesis_fsu" + +# Get task specific resources +. "${EXPDIR}/config.resources" genesis_fsu + +# Get tropcy settings +. "${EXPDIR}/config.tropcy" + +echo "END: config.genesis_fsu" diff --git a/parm/config/gfs/config.resources b/parm/config/gfs/config.resources index 1f89994b69..1139fdc9a7 100644 --- a/parm/config/gfs/config.resources +++ b/parm/config/gfs/config.resources @@ -15,6 +15,7 @@ if [[ $# -ne 1 ]]; then echo "landanl" echo "aeroanlinit aeroanlrun aeroanlfinal" echo "anal sfcanl analcalc analdiag fcst post echgres" + echo "tracker genesis genesis_fsu" echo "verfozn verfrad vminmon vrfy fit2obs metp arch cleanup" echo "eobs ediag eomg eupd ecen esfc efcs epos earc" echo "init_chem mom6ic ocnpost" @@ -749,19 +750,39 @@ elif [[ ${step} = "vminmon" ]]; then export npe_node_vminmon_gfs=1 export memory_vminmon="1G" +elif [[ ${step} = "tracker" ]]; then + + export wtime_tracker="00:10:00" + export npe_tracker=1 + export nth_tracker=1 + export npe_node_tracker=1 + export memory_tracker="4G" + +elif [[ ${step} = "genesis" ]]; then + + export wtime_genesis="00:25:00" + export npe_genesis=1 + export nth_genesis=1 + export npe_node_genesis=1 + export memory_genesis="4G" + +elif [[ ${step} = "genesis_fsu" ]]; then + + export wtime_genesis_fsu="00:10:00" + export npe_genesis_fsu=1 + export nth_genesis_fsu=1 + export npe_node_genesis_fsu=1 + export memory_genesis_fsu="4G" + elif [[ ${step} = "vrfy" ]]; then - export wtime_vrfy="03:00:00" - export wtime_vrfy_gfs="06:00:00" - export npe_vrfy=3 + export wtime_vrfy="00:10:00" + export wtime_vrfy_gfs="00:10:00" + export npe_vrfy=1 export nth_vrfy=1 export npe_node_vrfy=1 export npe_vrfy_gfs=1 export npe_node_vrfy_gfs=1 - if [[ ${machine} == "HERA" ]]; then - export memory_vrfy="16384M" - fi - export is_exclusive=True elif [[ "${step}" = "fit2obs" ]]; then diff --git a/parm/config/gfs/config.tracker b/parm/config/gfs/config.tracker new file mode 100644 index 0000000000..71fcf9196d --- /dev/null +++ b/parm/config/gfs/config.tracker @@ -0,0 +1,12 @@ +#! /usr/bin/env bash + +########## config.tracker ########## +echo "BEGIN: config.tracker" + +# Get task specific resources +. "${EXPDIR}/config.resources" tracker + +# Get tropcy settings +. "${EXPDIR}/config.tropcy" + +echo "END: config.tracker" diff --git a/parm/config/gfs/config.tropcy b/parm/config/gfs/config.tropcy new file mode 100644 index 0000000000..718abe3be5 --- /dev/null +++ b/parm/config/gfs/config.tropcy @@ -0,0 +1,15 @@ +#! /usr/bin/env bash + +########## config.tropcy ########## +echo "BEGIN: config.tropcy" + +# Tracker/genesis package location +export HOMEens_tracker=${BASE_GIT}/TC_tracker/${ens_tracker_ver} + +export SENDCOM="YES" # Needed by tracker scripts still + +export FHOUT_CYCLONE=6 +FHMAX_CYCLONE=$(( FHMAX_GFS<240 ? FHMAX_GFS : 240 )) +export FHMAX_CYCLONE + +echo "END: config.tropcy" diff --git a/parm/config/gfs/config.vrfy b/parm/config/gfs/config.vrfy index 8b8c393ee1..945d0ecfba 100644 --- a/parm/config/gfs/config.vrfy +++ b/parm/config/gfs/config.vrfy @@ -10,45 +10,8 @@ echo "BEGIN: config.vrfy" export CDFNL="gdas" # Scores verification against GDAS/GFS analysis export MKPGB4PRCP="YES" # Make 0.25-deg pgb files in ARCDIR for precip verification -export VRFYTRAK="YES" # Hurricane track verification -export VRFYGENESIS="YES" # Cyclone genesis verification -export VRFYFSU="NO" # Cyclone genesis verification (FSU) export RUNMOS="NO" # whether to run entire MOS package -#------------------------------------------------- -# Cyclone genesis and cyclone track verification -#------------------------------------------------- - -export SENDCOM="YES" # Needed by tracker/genesis scripts still - -export HOMEens_tracker=$BASE_GIT/TC_tracker/${tracker_ver} - -if [[ "${VRFYTRAK}" = "YES" ]]; then - - export TRACKERSH="${HOMEgfs}/jobs/JGFS_ATMOS_CYCLONE_TRACKER" - COMINsyn=${COMINsyn:-$(compath.py "${envir}"/com/gfs/"${gfs_ver}")/syndat} - export COMINsyn - if [[ "${RUN}" = "gdas" ]]; then - export FHOUT_CYCLONE=3 - export FHMAX_CYCLONE=${FHMAX} - else - export FHOUT_CYCLONE=6 - FHMAX_CYCLONE=$(( FHMAX_GFS<240 ? FHMAX_GFS : 240 )) - export FHMAX_CYCLONE - fi -fi - - -if [[ "${VRFYGENESIS}" == "YES" && "${RUN}" == "gfs" ]]; then - - export GENESISSH="${HOMEgfs}/jobs/JGFS_ATMOS_CYCLONE_GENESIS" -fi - -if [[ "${VRFYFSU}" == "YES" && "${RUN}" == "gfs" ]]; then - - export GENESISFSU="${HOMEgfs}/jobs/JGFS_ATMOS_FSU_GENESIS" -fi - if [[ "${RUNMOS}" == "YES" && "${RUN}" == "gfs" ]]; then if [[ "${machine}" = "HERA" ]] ; then diff --git a/versions/run.hera.ver b/versions/run.hera.ver index 471e019dcd..2c5ff92e3a 100644 --- a/versions/run.hera.ver +++ b/versions/run.hera.ver @@ -24,5 +24,5 @@ export wgrib2_ver=2.0.8 export obsproc_run_ver=1.1.2 export prepobs_run_ver=1.0.1 -export tracker_ver=feature-GFSv17_com_reorg +export ens_tracker_ver=feature-GFSv17_com_reorg export fit2obs_ver=1.0.0 diff --git a/versions/run.jet.ver b/versions/run.jet.ver index 3cab138a1a..c016e7352b 100644 --- a/versions/run.jet.ver +++ b/versions/run.jet.ver @@ -26,5 +26,5 @@ export anaconda_ver=5.3.1 export obsproc_run_ver=1.1.2 export prepobs_run_ver=1.0.1 -export tracker_ver=feature-GFSv17_com_reorg +export ens_tracker_ver=feature-GFSv17_com_reorg export fit2obs_ver=1.0.0 diff --git a/versions/run.orion.ver b/versions/run.orion.ver index 80a05580cf..1b1400384e 100644 --- a/versions/run.orion.ver +++ b/versions/run.orion.ver @@ -23,5 +23,5 @@ export wgrib2_ver=2.0.8 export obsproc_run_ver=1.1.2 export prepobs_run_ver=1.0.1 -export tracker_ver=feature-GFSv17_com_reorg +export ens_tracker_ver=feature-GFSv17_com_reorg export fit2obs_ver=1.0.0 diff --git a/versions/run.s4.ver b/versions/run.s4.ver index 966c86fe01..25d4ed6bea 100644 --- a/versions/run.s4.ver +++ b/versions/run.s4.ver @@ -23,5 +23,5 @@ export wgrib2_ver=2.0.8 export obsproc_run_ver=1.1.2 export prepobs_run_ver=1.0.1 -export tracker_ver=feature-GFSv17_com_reorg +export ens_tracker_ver=feature-GFSv17_com_reorg export fit2obs_ver=1.0.0 diff --git a/versions/run.wcoss2.ver b/versions/run.wcoss2.ver index 13e64a22df..959d0c5f0a 100644 --- a/versions/run.wcoss2.ver +++ b/versions/run.wcoss2.ver @@ -45,5 +45,5 @@ export wgrib2_ver=2.0.8 export obsproc_run_ver=1.1.2 export prepobs_run_ver=1.0.1 -export tracker_ver=feature-GFSv17_com_reorg +export ens_tracker_ver=feature-GFSv17_com_reorg export fit2obs_ver=1.0.0 diff --git a/workflow/applications/applications.py b/workflow/applications/applications.py index 138a5ef43f..bc64bda4a5 100644 --- a/workflow/applications/applications.py +++ b/workflow/applications/applications.py @@ -58,6 +58,9 @@ def __init__(self, conf: Configuration) -> None: self.do_verfozn = _base.get('DO_VERFOZN', True) self.do_verfrad = _base.get('DO_VERFRAD', True) self.do_vminmon = _base.get('DO_VMINMON', True) + self.do_tracker = _base.get('DO_TRACKER', True) + self.do_genesis = _base.get('DO_GENESIS', True) + self.do_genesis_fsu = _base.get('DO_GENESIS_FSU', False) self.do_metp = _base.get('DO_METP', False) self.do_hpssarch = _base.get('HPSSARCH', False) diff --git a/workflow/applications/gfs_cycled.py b/workflow/applications/gfs_cycled.py index 3b8472d3c8..632f058c98 100644 --- a/workflow/applications/gfs_cycled.py +++ b/workflow/applications/gfs_cycled.py @@ -68,6 +68,15 @@ def _get_app_configs(self): if self.do_vminmon: configs += ['vminmon'] + if self.do_tracker: + configs += ['tracker'] + + if self.do_genesis: + configs += ['genesis'] + + if self.do_genesis_fsu: + configs += ['genesis_fsu'] + if self.do_metp: configs += ['metp'] @@ -195,6 +204,15 @@ def get_task_names(self): if self.do_vminmon: gfs_tasks += ['vminmon'] + if self.do_tracker: + gfs_tasks += ['tracker'] + + if self.do_genesis: + gfs_tasks += ['genesis'] + + if self.do_genesis_fsu: + gfs_tasks += ['genesis_fsu'] + if self.do_metp: gfs_tasks += ['metp'] diff --git a/workflow/applications/gfs_forecast_only.py b/workflow/applications/gfs_forecast_only.py index 73e17ee7aa..a130baf6e9 100644 --- a/workflow/applications/gfs_forecast_only.py +++ b/workflow/applications/gfs_forecast_only.py @@ -26,6 +26,15 @@ def _get_app_configs(self): if self.do_ocean or self.do_ice: configs += ['ocnpost'] + if self.do_atm and self.do_tracker: + configs += ['tracker'] + + if self.do_atm and self.do_genesis: + configs += ['genesis'] + + if self.do_atm and self.do_genesis_fsu: + configs += ['genesis_fsu'] + if self.do_atm and self.do_metp: configs += ['metp'] @@ -85,6 +94,15 @@ def get_task_names(self): if self.do_atm: tasks += ['vrfy'] + if self.do_atm and self.do_tracker: + tasks += ['tracker'] + + if self.do_atm and self.do_genesis: + tasks += ['genesis'] + + if self.do_atm and self.do_genesis_fsu: + tasks += ['genesis_fsu'] + if self.do_atm and self.do_metp: tasks += ['metp'] diff --git a/workflow/rocoto/gfs_tasks.py b/workflow/rocoto/gfs_tasks.py index 24d31521c2..f09c10880d 100644 --- a/workflow/rocoto/gfs_tasks.py +++ b/workflow/rocoto/gfs_tasks.py @@ -902,6 +902,39 @@ def vminmon(self): return task + def tracker(self): + deps = [] + dep_dict = {'type': 'metatask', 'name': f'{self.cdump}post'} + deps.append(rocoto.add_dependency(dep_dict)) + dependencies = rocoto.create_dependency(dep=deps) + + resources = self.get_resource('tracker') + task = create_wf_task('tracker', resources, cdump=self.cdump, envar=self.envars, dependency=dependencies) + + return task + + def genesis(self): + deps = [] + dep_dict = {'type': 'metatask', 'name': f'{self.cdump}post'} + deps.append(rocoto.add_dependency(dep_dict)) + dependencies = rocoto.create_dependency(dep=deps) + + resources = self.get_resource('genesis') + task = create_wf_task('genesis', resources, cdump=self.cdump, envar=self.envars, dependency=dependencies) + + return task + + def genesis_fsu(self): + deps = [] + dep_dict = {'type': 'metatask', 'name': f'{self.cdump}post'} + deps.append(rocoto.add_dependency(dep_dict)) + dependencies = rocoto.create_dependency(dep=deps) + + resources = self.get_resource('genesis_fsu') + task = create_wf_task('genesis_fsu', resources, cdump=self.cdump, envar=self.envars, dependency=dependencies) + + return task + def vrfy(self): deps = [] dep_dict = {'type': 'metatask', 'name': f'{self.cdump}post'} @@ -956,11 +989,15 @@ def arch(self): dependencies = [] if self.app_config.mode in ['cycled']: if self.cdump in ['gfs']: + dep_dict = {'type': 'task', 'name': f'{self.cdump}postanl'} + deps.append(rocoto.add_dependency(dep_dict)) if self.app_config.do_vminmon: dep_dict = {'type': 'task', 'name': f'{self.cdump}vminmon'} deps.append(rocoto.add_dependency(dep_dict)) elif self.cdump in ['gdas']: # Block for handling half cycle dependencies deps2 = [] + dep_dict = {'type': 'task', 'name': f'{self.cdump}postanl'} + deps2.append(rocoto.add_dependency(dep_dict)) if self.app_config.do_fit2obs: dep_dict = {'type': 'task', 'name': f'{self.cdump}fit2obs'} deps2.append(rocoto.add_dependency(dep_dict)) @@ -977,9 +1014,21 @@ def arch(self): dep_dict = {'type': 'cycleexist', 'condition': 'not', 'offset': '-06:00:00'} dependencies.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='or', dep=dependencies) + if self.cdump in ['gfs'] and self.app_config.do_tracker: + dep_dict = {'type': 'task', 'name': f'{self.cdump}tracker'} + deps.append(rocoto.add_dependency(dep_dict)) + if self.cdump in ['gfs'] and self.app_config.do_genesis: + dep_dict = {'type': 'task', 'name': f'{self.cdump}genesis'} + deps.append(rocoto.add_dependency(dep_dict)) + if self.cdump in ['gfs'] and self.app_config.do_genesis_fsu: + dep_dict = {'type': 'task', 'name': f'{self.cdump}genesis_fsu'} + deps.append(rocoto.add_dependency(dep_dict)) if self.app_config.do_vrfy: dep_dict = {'type': 'task', 'name': f'{self.cdump}vrfy'} deps.append(rocoto.add_dependency(dep_dict)) + # Post job dependencies + dep_dict = {'type': 'metatask', 'name': f'{self.cdump}post'} + deps.append(rocoto.add_dependency(dep_dict)) if self.app_config.do_wave: dep_dict = {'type': 'task', 'name': f'{self.cdump}wavepostsbs'} deps.append(rocoto.add_dependency(dep_dict)) @@ -992,10 +1041,6 @@ def arch(self): if self.app_config.mode in ['forecast-only']: # TODO: fix ocnpost to run in cycled mode dep_dict = {'type': 'metatask', 'name': f'{self.cdump}ocnpost'} deps.append(rocoto.add_dependency(dep_dict)) - # If all verification and ocean/wave coupling is off, add the gdas/gfs post metatask as a dependency - if len(deps) == 0: - dep_dict = {'type': 'metatask', 'name': f'{self.cdump}post'} - deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps + dependencies) diff --git a/workflow/rocoto/tasks.py b/workflow/rocoto/tasks.py index b1dd1b0d92..67a0a9884a 100644 --- a/workflow/rocoto/tasks.py +++ b/workflow/rocoto/tasks.py @@ -21,6 +21,7 @@ class Tasks: 'preplandobs', 'landanl', 'fcst', 'post', 'ocnpost', 'verfozn', 'verfrad', 'vminmon', 'vrfy', 'metp', + 'tracker', 'genesis', 'genesis_fsu', 'postsnd', 'awips', 'gempak', 'waveawipsbulls', 'waveawipsgridded', 'wavegempak', 'waveinit', 'wavepostbndpnt', 'wavepostbndpntbll', 'wavepostpnt', 'wavepostsbs', 'waveprep'] From 4e3d82ba3a1fa7cdd4443bcd4cf83b2f8835137c Mon Sep 17 00:00:00 2001 From: Kate Friedman Date: Wed, 15 Nov 2023 13:39:14 -0500 Subject: [PATCH 4/9] Resolve ENKF archive script bugs (#2065) Fix two bugs in the exgdas_enkf_earc.sh script: 1) Replace ARCH_LIST with DATA to match changes done in PR #2000 and update path to generated archive list files. 2) Add status check and exit after script attempts to make tarball on HPSS. Refs #2064 --- scripts/exgdas_enkf_earc.sh | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/scripts/exgdas_enkf_earc.sh b/scripts/exgdas_enkf_earc.sh index f172a4ef41..199b5609a2 100755 --- a/scripts/exgdas_enkf_earc.sh +++ b/scripts/exgdas_enkf_earc.sh @@ -8,8 +8,6 @@ source "${HOMEgfs}/ush/preamble.sh" export n=$((10#${ENSGRP})) export CDUMP_ENKF="${EUPD_CYC:-"gdas"}" -export ARCH_LIST="${COM_TOP}/earc${ENSGRP}" - # ICS are restarts and always lag INC by $assim_freq hours. EARCINC_CYC=${ARCH_CYC} EARCICS_CYC=$((ARCH_CYC-assim_freq)) @@ -17,10 +15,6 @@ if [ "${EARCICS_CYC}" -lt 0 ]; then EARCICS_CYC=$((EARCICS_CYC+24)) fi -[[ -d ${ARCH_LIST} ]] && rm -rf "${ARCH_LIST}" -mkdir -p "${ARCH_LIST}" -cd "${ARCH_LIST}" || exit 2 - "${HOMEgfs}/ush/hpssarch_gen.sh" "${RUN}" status=$? if [ "${status}" -ne 0 ]; then @@ -66,7 +60,7 @@ if (( 10#${ENSGRP} > 0 )) && [[ ${HPSSARCH} = "YES" || ${LOCALARCH} = "YES" ]]; if [ "${PDY}${cyc}" -gt "${SDATE}" ]; then # Don't run for first half cycle - ${TARCMD} -P -cvf "${ATARDIR}/${PDY}${cyc}/${RUN}_grp${ENSGRP}.tar" $(cat "${ARCH_LIST}/${RUN}_grp${n}.txt") + ${TARCMD} -P -cvf "${ATARDIR}/${PDY}${cyc}/${RUN}_grp${ENSGRP}.tar" $(cat "${DATA}/${RUN}_grp${n}.txt") status=$? if [ "${status}" -ne 0 ] && [ "${PDY}${cyc}" -ge "${firstday}" ]; then echo "FATAL ERROR: ${TARCMD} ${PDY}${cyc} ${RUN}_grp${ENSGRP}.tar failed" @@ -74,7 +68,7 @@ if (( 10#${ENSGRP} > 0 )) && [[ ${HPSSARCH} = "YES" || ${LOCALARCH} = "YES" ]]; fi if [ "${SAVEWARMICA}" = "YES" ] && [ "${cyc}" -eq "${EARCINC_CYC}" ]; then - ${TARCMD} -P -cvf "${ATARDIR}/${PDY}${cyc}/${RUN}_restarta_grp${ENSGRP}.tar" $(cat "${ARCH_LIST}/${RUN}_restarta_grp${n}.txt") + ${TARCMD} -P -cvf "${ATARDIR}/${PDY}${cyc}/${RUN}_restarta_grp${ENSGRP}.tar" $(cat "${DATA}/${RUN}_restarta_grp${n}.txt") status=$? if [ "${status}" -ne 0 ]; then echo "FATAL ERROR: ${TARCMD} ${PDY}${cyc} ${RUN}_restarta_grp${ENSGRP}.tar failed" @@ -83,7 +77,7 @@ if (( 10#${ENSGRP} > 0 )) && [[ ${HPSSARCH} = "YES" || ${LOCALARCH} = "YES" ]]; fi if [ "${SAVEWARMICB}" = "YES" ] && [ "${cyc}" -eq "${EARCICS_CYC}" ]; then - ${TARCMD} -P -cvf "${ATARDIR}/${PDY}${cyc}/${RUN}_restartb_grp${ENSGRP}.tar" $(cat "${ARCH_LIST}/${RUN}_restartb_grp${n}.txt") + ${TARCMD} -P -cvf "${ATARDIR}/${PDY}${cyc}/${RUN}_restartb_grp${ENSGRP}.tar" $(cat "${DATA}/${RUN}_restartb_grp${n}.txt") status=$? if [ "${status}" -ne 0 ]; then echo "FATAL ERROR: ${TARCMD} ${PDY}${cyc} ${RUN}_restartb_grp${ENSGRP}.tar failed" @@ -122,12 +116,16 @@ if [ "${ENSGRP}" -eq 0 ]; then break fi fi - done < "${ARCH_LIST}/${RUN}.txt" + done < "${DATA}/${RUN}.txt" # Create the tarball tar_fl=${ATARDIR}/${PDY}${cyc}/${RUN}.tar - ${TARCMD} -P -cvf "${tar_fl}" $(cat "${ARCH_LIST}/${RUN}.txt") + ${TARCMD} -P -cvf "${tar_fl}" $(cat "${DATA}/${RUN}.txt") status=$? + if [[ "${status}" -ne 0 ]]; then + echo "FATAL ERROR: Tarring of ${tar_fl} failed" + exit "${status}" + fi # If rstprod was found, change the group of the tarball if [[ "${has_rstprod}" == "YES" ]]; then From 85f1f5131ffd70061231304ea477bde0559eb67b Mon Sep 17 00:00:00 2001 From: Guoqing Ge Date: Wed, 15 Nov 2023 11:47:21 -0700 Subject: [PATCH 5/9] Use assim_freq to configure "offset" in dependencies (#2039) Use the assim_freq from config.base to configure "offset" in dependencies instead of hard-coding them. Resolves #2038 --- workflow/applications/applications.py | 9 +-- workflow/applications/gfs_cycled.py | 74 ++++++++++++------------ workflow/rocoto/gefs_xml.py | 14 +++-- workflow/rocoto/gfs_cycled_xml.py | 24 +++++--- workflow/rocoto/gfs_forecast_only_xml.py | 10 ++-- workflow/rocoto/gfs_tasks.py | 27 ++++----- workflow/rocoto/tasks.py | 3 +- 7 files changed, 87 insertions(+), 74 deletions(-) diff --git a/workflow/applications/applications.py b/workflow/applications/applications.py index bc64bda4a5..e517783291 100644 --- a/workflow/applications/applications.py +++ b/workflow/applications/applications.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 from typing import Dict, List, Any +from datetime import timedelta from hosts import Host -from wxflow import Configuration +from wxflow import Configuration, to_timedelta from abc import ABC, ABCMeta, abstractmethod __all__ = ['AppConfig'] @@ -170,14 +171,14 @@ def get_task_names(self) -> Dict[str, List[str]]: pass @staticmethod - def get_gfs_interval(gfs_cyc: int) -> str: + def get_gfs_interval(gfs_cyc: int) -> timedelta: """ return interval in hours based on gfs_cyc """ - gfs_internal_map = {'0': None, '1': '24:00:00', '2': '12:00:00', '4': '06:00:00'} + gfs_internal_map = {'1': '24H', '2': '12H', '4': '6H'} try: - return gfs_internal_map[str(gfs_cyc)] + return to_timedelta(gfs_internal_map[str(gfs_cyc)]) except KeyError: raise KeyError(f'Invalid gfs_cyc = {gfs_cyc}') diff --git a/workflow/applications/gfs_cycled.py b/workflow/applications/gfs_cycled.py index 632f058c98..3dc199c5ec 100644 --- a/workflow/applications/gfs_cycled.py +++ b/workflow/applications/gfs_cycled.py @@ -1,6 +1,6 @@ from typing import Dict, Any from applications.applications import AppConfig -from wxflow import Configuration +from wxflow import Configuration, to_timedelta from datetime import timedelta @@ -265,47 +265,45 @@ def get_gfs_cyc_dates(base: Dict[str, Any]) -> Dict[str, Any]: base_out = base.copy() - gfs_cyc = base['gfs_cyc'] sdate = base['SDATE'] edate = base['EDATE'] - base_out['INTERVAL'] = '06:00:00' # Cycled interval is 6 hours - - interval_gfs = AppConfig.get_gfs_interval(gfs_cyc) + base_out['INTERVAL'] = to_timedelta(f"{base['assim_freq']}H") # Set GFS cycling dates - hrinc = 0 - hrdet = 0 - if gfs_cyc == 0: - return base_out - elif gfs_cyc == 1: - hrinc = 24 - sdate.hour - hrdet = edate.hour - elif gfs_cyc == 2: - if sdate.hour in [0, 12]: - hrinc = 12 - elif sdate.hour in [6, 18]: + gfs_cyc = base['gfs_cyc'] + if gfs_cyc != 0: + interval_gfs = AppConfig.get_gfs_interval(gfs_cyc) + hrinc = 0 + hrdet = 0 + if gfs_cyc == 1: + hrinc = 24 - sdate.hour + hrdet = edate.hour + elif gfs_cyc == 2: + if sdate.hour in [0, 12]: + hrinc = 12 + elif sdate.hour in [6, 18]: + hrinc = 6 + if edate.hour in [6, 18]: + hrdet = 6 + elif gfs_cyc == 4: hrinc = 6 - if edate.hour in [6, 18]: - hrdet = 6 - elif gfs_cyc == 4: - hrinc = 6 - sdate_gfs = sdate + timedelta(hours=hrinc) - edate_gfs = edate - timedelta(hours=hrdet) - if sdate_gfs > edate: - print('W A R N I N G!') - print('Starting date for GFS cycles is after Ending date of experiment') - print(f'SDATE = {sdate.strftime("%Y%m%d%H")}, EDATE = {edate.strftime("%Y%m%d%H")}') - print(f'SDATE_GFS = {sdate_gfs.strftime("%Y%m%d%H")}, EDATE_GFS = {edate_gfs.strftime("%Y%m%d%H")}') - gfs_cyc = 0 - - base_out['gfs_cyc'] = gfs_cyc - base_out['SDATE_GFS'] = sdate_gfs - base_out['EDATE_GFS'] = edate_gfs - base_out['INTERVAL_GFS'] = interval_gfs - - fhmax_gfs = {} - for hh in ['00', '06', '12', '18']: - fhmax_gfs[hh] = base.get(f'FHMAX_GFS_{hh}', base.get('FHMAX_GFS_00', 120)) - base_out['FHMAX_GFS'] = fhmax_gfs + sdate_gfs = sdate + timedelta(hours=hrinc) + edate_gfs = edate - timedelta(hours=hrdet) + if sdate_gfs > edate: + print('W A R N I N G!') + print('Starting date for GFS cycles is after Ending date of experiment') + print(f'SDATE = {sdate.strftime("%Y%m%d%H")}, EDATE = {edate.strftime("%Y%m%d%H")}') + print(f'SDATE_GFS = {sdate_gfs.strftime("%Y%m%d%H")}, EDATE_GFS = {edate_gfs.strftime("%Y%m%d%H")}') + gfs_cyc = 0 + + base_out['gfs_cyc'] = gfs_cyc + base_out['SDATE_GFS'] = sdate_gfs + base_out['EDATE_GFS'] = edate_gfs + base_out['INTERVAL_GFS'] = interval_gfs + + fhmax_gfs = {} + for hh in ['00', '06', '12', '18']: + fhmax_gfs[hh] = base.get(f'FHMAX_GFS_{hh}', base.get('FHMAX_GFS_00', 120)) + base_out['FHMAX_GFS'] = fhmax_gfs return base_out diff --git a/workflow/rocoto/gefs_xml.py b/workflow/rocoto/gefs_xml.py index 7e8df32991..b25a73fa6c 100644 --- a/workflow/rocoto/gefs_xml.py +++ b/workflow/rocoto/gefs_xml.py @@ -2,7 +2,7 @@ from rocoto.workflow_xml import RocotoXML from applications.applications import AppConfig -from wxflow import to_timedelta +from wxflow import to_timedelta, timedelta_to_HMS from typing import Dict @@ -16,13 +16,17 @@ def __init__(self, app_config: AppConfig, rocoto_config: Dict) -> None: def get_cycledefs(self): sdate = self._base['SDATE'] edate = self._base['EDATE'] - interval = self._base.get('INTERVAL_GFS', '24:00:00') + interval = self._base.get('INTERVAL_GFS', to_timedelta('24H')) + sdate_str = sdate.strftime("%Y%m%d%H%M") + edate_str = edate.strftime("%Y%m%d%H%M") + interval_str = timedelta_to_HMS(interval) strings = [] - strings.append(f'\t{sdate.strftime("%Y%m%d%H%M")} {edate.strftime("%Y%m%d%H%M")} {interval}') + strings.append(f'\t{sdate_str} {edate_str} {interval_str}') - sdate = sdate + to_timedelta(interval) + sdate = sdate + interval if sdate <= edate: - strings.append(f'\t{sdate.strftime("%Y%m%d%H%M")} {edate.strftime("%Y%m%d%H%M")} {interval}') + sdate_str = sdate.strftime("%Y%m%d%H%M") + strings.append(f'\t{sdate_str} {edate_str} {interval_str}') strings.append('') strings.append('') diff --git a/workflow/rocoto/gfs_cycled_xml.py b/workflow/rocoto/gfs_cycled_xml.py index d817b3ac03..afd663c337 100644 --- a/workflow/rocoto/gfs_cycled_xml.py +++ b/workflow/rocoto/gfs_cycled_xml.py @@ -2,7 +2,7 @@ from rocoto.workflow_xml import RocotoXML from applications.applications import AppConfig -from wxflow import to_timedelta +from wxflow import to_timedelta, timedelta_to_HMS from typing import Dict @@ -14,21 +14,29 @@ def __init__(self, app_config: AppConfig, rocoto_config: Dict) -> None: def get_cycledefs(self): sdate = self._base['SDATE'] edate = self._base['EDATE'] - interval = self._base.get('INTERVAL', '06:00:00') + interval = to_timedelta(f"{self._base['assim_freq']}H") + sdate_str = sdate.strftime("%Y%m%d%H%M") + edate_str = edate.strftime("%Y%m%d%H%M") + interval_str = timedelta_to_HMS(interval) strings = [] - strings.append(f'\t{sdate.strftime("%Y%m%d%H%M")} {sdate.strftime("%Y%m%d%H%M")} {interval}') - sdate = sdate + to_timedelta(interval) - strings.append(f'\t{sdate.strftime("%Y%m%d%H%M")} {edate.strftime("%Y%m%d%H%M")} {interval}') + strings.append(f'\t{sdate_str} {sdate_str} {interval_str}') + sdate = sdate + interval + sdate_str = sdate.strftime("%Y%m%d%H%M") + strings.append(f'\t{sdate_str} {edate_str} {interval_str}') if self._app_config.gfs_cyc != 0: sdate_gfs = self._base['SDATE_GFS'] edate_gfs = self._base['EDATE_GFS'] interval_gfs = self._base['INTERVAL_GFS'] - strings.append(f'\t{sdate_gfs.strftime("%Y%m%d%H%M")} {edate_gfs.strftime("%Y%m%d%H%M")} {interval_gfs}') + sdate_gfs_str = sdate_gfs.strftime("%Y%m%d%H%M") + edate_gfs_str = edate_gfs.strftime("%Y%m%d%H%M") + interval_gfs_str = timedelta_to_HMS(interval_gfs) + strings.append(f'\t{sdate_gfs_str} {edate_gfs_str} {interval_gfs_str}') - sdate_gfs = sdate_gfs + to_timedelta(interval_gfs) + sdate_gfs = sdate_gfs + interval_gfs + sdate_gfs_str = sdate_gfs.strftime("%Y%m%d%H%M") if sdate_gfs <= edate_gfs: - strings.append(f'\t{sdate_gfs.strftime("%Y%m%d%H%M")} {edate_gfs.strftime("%Y%m%d%H%M")} {interval_gfs}') + strings.append(f'\t{sdate_gfs_str} {edate_gfs_str} {interval_gfs_str}') strings.append('') strings.append('') diff --git a/workflow/rocoto/gfs_forecast_only_xml.py b/workflow/rocoto/gfs_forecast_only_xml.py index 7ae4eb34c5..cf53e685e9 100644 --- a/workflow/rocoto/gfs_forecast_only_xml.py +++ b/workflow/rocoto/gfs_forecast_only_xml.py @@ -2,7 +2,7 @@ from rocoto.workflow_xml import RocotoXML from applications.applications import AppConfig -from wxflow import to_timedelta +from wxflow import to_timedelta, timedelta_to_HMS from typing import Dict @@ -14,13 +14,13 @@ def __init__(self, app_config: AppConfig, rocoto_config: Dict) -> None: def get_cycledefs(self): sdate = self._base['SDATE'] edate = self._base['EDATE'] - interval = self._base.get('INTERVAL_GFS', '24:00:00') + interval = self._base.get('INTERVAL_GFS', to_timedelta('24H')) strings = [] - strings.append(f'\t{sdate.strftime("%Y%m%d%H%M")} {edate.strftime("%Y%m%d%H%M")} {interval}') + strings.append(f'\t{sdate.strftime("%Y%m%d%H%M")} {edate.strftime("%Y%m%d%H%M")} {timedelta_to_HMS(interval)}') - sdate = sdate + to_timedelta(interval) + sdate = sdate + interval if sdate <= edate: - strings.append(f'\t{sdate.strftime("%Y%m%d%H%M")} {edate.strftime("%Y%m%d%H%M")} {interval}') + strings.append(f'\t{sdate.strftime("%Y%m%d%H%M")} {edate.strftime("%Y%m%d%H%M")} {timedelta_to_HMS(interval)}') strings.append('') strings.append('') diff --git a/workflow/rocoto/gfs_tasks.py b/workflow/rocoto/gfs_tasks.py index f09c10880d..1da0f72694 100644 --- a/workflow/rocoto/gfs_tasks.py +++ b/workflow/rocoto/gfs_tasks.py @@ -1,5 +1,6 @@ from applications.applications import AppConfig from rocoto.tasks import Tasks, create_wf_task +from wxflow import timedelta_to_HMS import rocoto.rocoto as rocoto import numpy as np @@ -86,10 +87,10 @@ def prep(self): gfs_enkf = True if self.app_config.do_hybvar and 'gfs' in self.app_config.eupd_cdumps else False deps = [] - dep_dict = {'type': 'metatask', 'name': 'gdaspost', 'offset': '-06:00:00'} + dep_dict = {'type': 'metatask', 'name': 'gdaspost', 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} deps.append(rocoto.add_dependency(dep_dict)) data = f'{atm_hist_path}/gdas.t@Hz.atmf009.nc' - dep_dict = {'type': 'data', 'data': data, 'offset': '-06:00:00'} + dep_dict = {'type': 'data', 'data': data, 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} deps.append(rocoto.add_dependency(dep_dict)) data = f'{dump_path}/{self.cdump}.t@Hz.updated.status.tm00.bufr_d' dep_dict = {'type': 'data', 'data': data} @@ -116,7 +117,7 @@ def waveinit(self): dep_dict = {'type': 'task', 'name': f'{self.cdump}prep'} deps.append(rocoto.add_dependency(dep_dict)) if self.cdump in ['gdas']: - dep_dict = {'type': 'cycleexist', 'condition': 'not', 'offset': '-06:00:00'} + dep_dict = {'type': 'cycleexist', 'condition': 'not', 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='or', dep=deps) cycledef = 'gdas_half,gdas' if self.cdump in ['gdas'] else self.cdump @@ -155,7 +156,7 @@ def aerosol_init(self): interval = self._base['INTERVAL_GFS'] elif self.cdump in ['gdas']: interval = self._base['INTERVAL'] - offset = f'-{interval}' + offset = f'-{timedelta_to_HMS(interval)}' # Files from previous cycle files = [f'@Y@m@d.@H0000.fv_core.res.nc'] + \ @@ -181,7 +182,7 @@ def anal(self): dep_dict = {'type': 'task', 'name': f'{self.cdump}prep'} deps.append(rocoto.add_dependency(dep_dict)) if self.app_config.do_hybvar: - dep_dict = {'type': 'metatask', 'name': 'enkfgdasepmn', 'offset': '-06:00:00'} + dep_dict = {'type': 'metatask', 'name': 'enkfgdasepmn', 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) else: @@ -223,7 +224,7 @@ def analcalc(self): dep_dict = {'type': 'task', 'name': f'{self.cdump}sfcanl'} deps.append(rocoto.add_dependency(dep_dict)) if self.app_config.do_hybvar and self.cdump in ['gdas']: - dep_dict = {'type': 'task', 'name': 'enkfgdasechgres', 'offset': '-06:00:00'} + dep_dict = {'type': 'task', 'name': 'enkfgdasechgres', 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) @@ -262,7 +263,7 @@ def atmanlinit(self): dep_dict = {'type': 'task', 'name': f'{self.cdump}prepatmiodaobs'} deps.append(rocoto.add_dependency(dep_dict)) if self.app_config.do_hybvar: - dep_dict = {'type': 'metatask', 'name': 'enkfgdasepmn', 'offset': '-06:00:00'} + dep_dict = {'type': 'metatask', 'name': 'enkfgdasepmn', 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) else: @@ -369,7 +370,7 @@ def ocnanalprep(self): deps = [] data = f'{ocean_hist_path}/gdas.t@Hz.ocnf009.nc' - dep_dict = {'type': 'data', 'data': data, 'offset': '-06:00:00'} + dep_dict = {'type': 'data', 'data': data, 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep=deps) @@ -536,7 +537,7 @@ def _fcst_cycled(self): dependencies = rocoto.create_dependency(dep_condition='and', dep=dependencies) if self.cdump in ['gdas']: - dep_dict = {'type': 'cycleexist', 'condition': 'not', 'offset': '-06:00:00'} + dep_dict = {'type': 'cycleexist', 'condition': 'not', 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} dependencies.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='or', dep=dependencies) @@ -1074,7 +1075,7 @@ def eobs(self): deps = [] dep_dict = {'type': 'task', 'name': f'{self.cdump.replace("enkf","")}prep'} deps.append(rocoto.add_dependency(dep_dict)) - dep_dict = {'type': 'metatask', 'name': 'enkfgdasepmn', 'offset': '-06:00:00'} + dep_dict = {'type': 'metatask', 'name': 'enkfgdasepmn', 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) @@ -1129,7 +1130,7 @@ def atmensanlinit(self): deps = [] dep_dict = {'type': 'task', 'name': f'{self.cdump.replace("enkf","")}prepatmiodaobs'} deps.append(rocoto.add_dependency(dep_dict)) - dep_dict = {'type': 'metatask', 'name': 'enkfgdasepmn', 'offset': '-06:00:00'} + dep_dict = {'type': 'metatask', 'name': 'enkfgdasepmn', 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) @@ -1145,7 +1146,7 @@ def atmensanlrun(self): deps = [] dep_dict = {'type': 'task', 'name': f'{self.cdump}atmensanlinit'} deps.append(rocoto.add_dependency(dep_dict)) - dep_dict = {'type': 'metatask', 'name': 'enkfgdasepmn', 'offset': '-06:00:00'} + dep_dict = {'type': 'metatask', 'name': 'enkfgdasepmn', 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) @@ -1243,7 +1244,7 @@ def efcs(self): dep_dict = {'type': 'task', 'name': f'{self.cdump}esfc'} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) - dep_dict = {'type': 'cycleexist', 'condition': 'not', 'offset': '-06:00:00'} + dep_dict = {'type': 'cycleexist', 'condition': 'not', 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} dependencies.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='or', dep=dependencies) diff --git a/workflow/rocoto/tasks.py b/workflow/rocoto/tasks.py index 67a0a9884a..fd66ee2031 100644 --- a/workflow/rocoto/tasks.py +++ b/workflow/rocoto/tasks.py @@ -3,7 +3,7 @@ import numpy as np from applications.applications import AppConfig import rocoto.rocoto as rocoto -from wxflow import Template, TemplateConstants +from wxflow import Template, TemplateConstants, to_timedelta __all__ = ['Tasks', 'create_wf_task'] @@ -34,6 +34,7 @@ def __init__(self, app_config: AppConfig, cdump: str) -> None: # Save dict_configs and base in the internal state (never know where it may be needed) self._configs = self.app_config.configs self._base = self._configs['base'] + self._base['cycle_interval'] = to_timedelta(f'{self._base["assim_freq"]}H') self.n_tiles = 6 # TODO - this needs to be elsewhere From be9085e62aae147e3c74602e2f82a99b374fc783 Mon Sep 17 00:00:00 2001 From: Guillaume Vernieres Date: Wed, 15 Nov 2023 13:48:58 -0500 Subject: [PATCH 6/9] Save the required CICE history for the sea-ice DA (#2062) The hist_avg setting of CICE was changed to be an array. --- ush/forecast_postdet.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index ac59fcacac..6bfb932659 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -886,9 +886,9 @@ CICE_postdet() { dumpfreq=${dumpfreq:-"y"} # "h","d","m" or "y" for restarts at intervals of "hours", "days", "months" or "years" if [[ "${RUN}" =~ "gdas" ]]; then - cice_hist_avg=".false." # DA needs instantaneous + cice_hist_avg=".false., .false., .false., .false., .false." # DA needs instantaneous else - cice_hist_avg=".true." # P8 wants averaged over histfreq_n + cice_hist_avg=".true., .true., .true., .true., .true." # P8 wants averaged over histfreq_n fi FRAZIL_FWSALT=${FRAZIL_FWSALT:-".true."} From 255616d37505c785bdddd5d3e39e8399110b626e Mon Sep 17 00:00:00 2001 From: mdtoyNOAA <73618848+mdtoyNOAA@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:02:09 -0700 Subject: [PATCH 7/9] Update functionality for Prototype HR3 UGWP (#1987) This PR adds/modifies namelist options and activates new 'ccpp' suite definition files for the updated Unified Gravity Wave Physics (UGWP) in the ufs-weather- model recently updated for HR3. The changes to UGWP are the use of the GSL drag suite for orographic gravity wave drag (GWD) and blocking, as well as the new UGWP Version 1 non-stationary GWD. See ufs-community/ufs-weather-model#1923 for details. Resolves #1986 --- parm/config/gefs/config.base.emc.dyn | 4 ++-- parm/config/gefs/config.fcst | 17 ++++++++++------- parm/config/gefs/config.ufs | 14 ++++++++++++++ parm/config/gfs/config.base.emc.dyn | 4 ++-- parm/config/gfs/config.fcst | 17 ++++++++++------- parm/config/gfs/config.ufs | 14 ++++++++++++++ sorc/build_ufs.sh | 2 +- sorc/checkout.sh | 2 +- ush/forecast_postdet.sh | 2 +- ush/parsing_namelists_FV3.sh | 14 ++++++++++---- 10 files changed, 65 insertions(+), 25 deletions(-) diff --git a/parm/config/gefs/config.base.emc.dyn b/parm/config/gefs/config.base.emc.dyn index 04fc396e5a..12a8422ea2 100644 --- a/parm/config/gefs/config.base.emc.dyn +++ b/parm/config/gefs/config.base.emc.dyn @@ -138,7 +138,7 @@ export DO_WAVE="NO" export DO_OCN="NO" export DO_ICE="NO" export DO_AERO="NO" -export CCPP_SUITE="FV3_GFS_v17_p8" +export CCPP_SUITE="FV3_GFS_v17_p8_ugwpv1" export WAVE_CDUMP="" # When to include wave suite: gdas, gfs, or both export DOBNDPNT_WAVE="NO" export cplwav2atm=".false." @@ -204,7 +204,7 @@ case "${APP}" in export DO_COUPLED="YES" export DO_OCN="YES" export DO_ICE="YES" - export CCPP_SUITE="FV3_GFS_v17_coupled_p8" # TODO: Does this include FV3_GFS_v17_p8? Can this be used instead of FV3_GFS_v17_p8 on L141 + export CCPP_SUITE="FV3_GFS_v17_coupled_p8_ugwpv1" # TODO: Does this include FV3_GFS_v17_p8? Can this be used instead of FV3_GFS_v17_p8 on L141 export confignamevarfornems="cpld" if [[ "${APP}" =~ A$ ]]; then diff --git a/parm/config/gefs/config.fcst b/parm/config/gefs/config.fcst index a125c96331..4d43c38b82 100644 --- a/parm/config/gefs/config.fcst +++ b/parm/config/gefs/config.fcst @@ -119,24 +119,27 @@ if (( gwd_opt == 2 )); then #export do_ugwp_v1_orog_only=".false." #--used for UFS p8 - export knob_ugwp_version=0 + export knob_ugwp_version=1 export do_ugwp=".false." export do_tofd=".false." - export do_ugwp_v0=".true." - export do_ugwp_v1=".false." + export do_ugwp_v0=".false." + export do_ugwp_v1=".true." export do_ugwp_v0_orog_only=".false." export do_ugwp_v0_nst_only=".false." - export do_gsl_drag_ls_bl=".false." + export do_gsl_drag_ls_bl=".true." export do_gsl_drag_ss=".true." - export do_gsl_drag_tofd=".false." + export do_gsl_drag_tofd=".true." export do_ugwp_v1_orog_only=".false." launch_level=$(echo "${LEVS}/2.35" |bc) export launch_level + if [[ ${do_gsl_drag_ls_bl} == ".true." ]]; then + export cdmbgwd=${cdmbgwd_gsl} + fi fi # Sponge layer settings -export tau=10.0 -export rf_cutoff=7.5e2 +export tau=0. +export rf_cutoff=10. export d2_bg_k1=0.20 export d2_bg_k2=0.04 export dz_min=6 diff --git a/parm/config/gefs/config.ufs b/parm/config/gefs/config.ufs index 563ee8f021..8418459cc3 100644 --- a/parm/config/gefs/config.ufs +++ b/parm/config/gefs/config.ufs @@ -112,6 +112,8 @@ case "${fv3_res}" in export nthreads_fv3=1 export nthreads_fv3_gfs=1 export cdmbgwd="0.071,2.1,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="40.0,1.77,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=6.0e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=1 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=1 export WRITE_GROUP_GFS=1 @@ -126,6 +128,8 @@ case "${fv3_res}" in export nthreads_fv3=1 export nthreads_fv3_gfs=1 export cdmbgwd="0.14,1.8,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="20.0,2.5,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=3.0e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=1 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=1 export WRITE_GROUP_GFS=1 @@ -140,6 +144,8 @@ case "${fv3_res}" in export nthreads_fv3=1 export nthreads_fv3_gfs=2 export cdmbgwd="0.23,1.5,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="10.0,3.5,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=1.5e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=1 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=10 export WRITE_GROUP_GFS=2 @@ -154,6 +160,8 @@ case "${fv3_res}" in export nthreads_fv3=1 export nthreads_fv3_gfs=2 export cdmbgwd="1.1,0.72,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="5.0,5.0,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=0.8e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=2 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=8 export WRITE_GROUP_GFS=2 @@ -168,6 +176,8 @@ case "${fv3_res}" in export nthreads_fv3=4 export nthreads_fv3_gfs=4 export cdmbgwd="4.0,0.15,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="2.5,7.5,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=0.5e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=2 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=10 export WRITE_GROUP_GFS=4 @@ -182,6 +192,8 @@ case "${fv3_res}" in export nthreads_fv3=4 export nthreads_fv3_gfs=4 export cdmbgwd="4.0,0.10,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="1.67,8.8,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=0.35e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=4 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=10 # TODO: refine these numbers when a case is available export WRITE_GROUP_GFS=4 @@ -196,6 +208,8 @@ case "${fv3_res}" in export nthreads_fv3=4 export nthreads_fv3_gfs=4 export cdmbgwd="4.0,0.05,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="0.625,14.1,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=0.13e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=4 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=10 # TODO: refine these numbers when a case is available export WRITE_GROUP_GFS=4 diff --git a/parm/config/gfs/config.base.emc.dyn b/parm/config/gfs/config.base.emc.dyn index 179f37388f..fdf5bc25c1 100644 --- a/parm/config/gfs/config.base.emc.dyn +++ b/parm/config/gfs/config.base.emc.dyn @@ -151,7 +151,7 @@ export DO_WAVE="NO" export DO_OCN="NO" export DO_ICE="NO" export DO_AERO="NO" -export CCPP_SUITE="FV3_GFS_v17_p8" +export CCPP_SUITE="FV3_GFS_v17_p8_ugwpv1" export WAVE_CDUMP="" # When to include wave suite: gdas, gfs, or both export DOBNDPNT_WAVE="NO" export cplwav2atm=".false." @@ -217,7 +217,7 @@ case "${APP}" in export DO_COUPLED="YES" export DO_OCN="YES" export DO_ICE="YES" - export CCPP_SUITE="FV3_GFS_v17_coupled_p8" # TODO: Does this include FV3_GFS_v17_p8? Can this be used instead of FV3_GFS_v17_p8 on L149 + export CCPP_SUITE="FV3_GFS_v17_coupled_p8_ugwpv1" # TODO: Does this include FV3_GFS_v17_p8? Can this be used instead of FV3_GFS_v17_p8 on L149 export confignamevarfornems="cpld" if [[ "${APP}" =~ A$ ]]; then diff --git a/parm/config/gfs/config.fcst b/parm/config/gfs/config.fcst index 5202a90731..7a3c1b3b30 100644 --- a/parm/config/gfs/config.fcst +++ b/parm/config/gfs/config.fcst @@ -119,24 +119,27 @@ if (( gwd_opt == 2 )); then #export do_ugwp_v1_orog_only=".false." #--used for UFS p8 - export knob_ugwp_version=0 + export knob_ugwp_version=1 export do_ugwp=".false." export do_tofd=".false." - export do_ugwp_v0=".true." - export do_ugwp_v1=".false." + export do_ugwp_v0=".false." + export do_ugwp_v1=".true." export do_ugwp_v0_orog_only=".false." export do_ugwp_v0_nst_only=".false." - export do_gsl_drag_ls_bl=".false." + export do_gsl_drag_ls_bl=".true." export do_gsl_drag_ss=".true." - export do_gsl_drag_tofd=".false." + export do_gsl_drag_tofd=".true." export do_ugwp_v1_orog_only=".false." launch_level=$(echo "${LEVS}/2.35" |bc) export launch_level + if [[ ${do_gsl_drag_ls_bl} == ".true." ]]; then + export cdmbgwd=${cdmbgwd_gsl} + fi fi # Sponge layer settings -export tau=10.0 -export rf_cutoff=7.5e2 +export tau=0. +export rf_cutoff=10. export d2_bg_k1=0.20 export d2_bg_k2=0.04 export dz_min=6 diff --git a/parm/config/gfs/config.ufs b/parm/config/gfs/config.ufs index 2441716a05..e499d90fdd 100644 --- a/parm/config/gfs/config.ufs +++ b/parm/config/gfs/config.ufs @@ -112,6 +112,8 @@ case "${fv3_res}" in export nthreads_fv3=1 export nthreads_fv3_gfs=1 export cdmbgwd="0.071,2.1,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="40.0,1.77,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=6.0e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=1 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=1 export WRITE_GROUP_GFS=1 @@ -126,6 +128,8 @@ case "${fv3_res}" in export nthreads_fv3=1 export nthreads_fv3_gfs=1 export cdmbgwd="0.14,1.8,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="20.0,2.5,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=3.0e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=1 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=1 export WRITE_GROUP_GFS=1 @@ -140,6 +144,8 @@ case "${fv3_res}" in export nthreads_fv3=1 export nthreads_fv3_gfs=2 export cdmbgwd="0.23,1.5,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="10.0,3.5,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=1.5e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=1 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=10 export WRITE_GROUP_GFS=2 @@ -154,6 +160,8 @@ case "${fv3_res}" in export nthreads_fv3=2 export nthreads_fv3_gfs=2 export cdmbgwd="1.1,0.72,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="5.0,5.0,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=0.8e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=4 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=10 export WRITE_GROUP_GFS=4 @@ -168,6 +176,8 @@ case "${fv3_res}" in export nthreads_fv3=4 export nthreads_fv3_gfs=4 export cdmbgwd="4.0,0.15,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="2.5,7.5,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=0.5e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=2 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=10 export WRITE_GROUP_GFS=4 @@ -182,6 +192,8 @@ case "${fv3_res}" in export nthreads_fv3=4 export nthreads_fv3_gfs=4 export cdmbgwd="4.0,0.10,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="1.67,8.8,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=0.35e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=4 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=10 # TODO: refine these numbers when a case is available export WRITE_GROUP_GFS=4 @@ -196,6 +208,8 @@ case "${fv3_res}" in export nthreads_fv3=4 export nthreads_fv3_gfs=4 export cdmbgwd="4.0,0.05,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling + export cdmbgwd_gsl="0.625,14.1,1.0,1.0" # settings for GSL drag suite + export knob_ugwp_tauamp=0.13e-3 # setting for UGWPv1 non-stationary GWD export WRITE_GROUP=4 export WRTTASK_PER_GROUP_PER_THREAD_PER_TILE=10 # TODO: refine these numbers when a case is available export WRITE_GROUP_GFS=4 diff --git a/sorc/build_ufs.sh b/sorc/build_ufs.sh index aaeeefea23..3e3f879f1a 100755 --- a/sorc/build_ufs.sh +++ b/sorc/build_ufs.sh @@ -5,7 +5,7 @@ cwd=$(pwd) # Default settings APP="S2SWA" -CCPP_SUITES="FV3_GFS_v17_p8,FV3_GFS_v17_coupled_p8" # TODO: does the g-w need to build with all these CCPP_SUITES? +CCPP_SUITES="FV3_GFS_v17_p8_ugwpv1,FV3_GFS_v17_coupled_p8_ugwpv1" # TODO: does the g-w need to build with all these CCPP_SUITES? while getopts ":da:j:v" option; do case "${option}" in diff --git a/sorc/checkout.sh b/sorc/checkout.sh index 3a3f96e327..a80ee90d55 100755 --- a/sorc/checkout.sh +++ b/sorc/checkout.sh @@ -151,7 +151,7 @@ source "${topdir}/../workflow/gw_setup.sh" # The checkout version should always be a speciifc commit (hash or tag), not a branch errs=0 # Checkout UFS submodules in parallel -checkout "ufs_model.fd" "https://github.com/ufs-community/ufs-weather-model" "${ufs_model_hash:-63a43d9}" "8" ; errs=$((errs + $?)) +checkout "ufs_model.fd" "https://github.com/ufs-community/ufs-weather-model" "${ufs_model_hash:-63a43d9}" "8" & # Run all other checkouts simultaneously with just 1 core each to handle submodules. checkout "wxflow" "https://github.com/NOAA-EMC/wxflow" "528f5ab" & diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 6bfb932659..9d93f52840 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -381,7 +381,7 @@ EOF # time step parameters in FV3 k_split=${k_split:-2} - n_split=${n_split:-6} + n_split=${n_split:-5} if [[ "${MONO:0:4}" = "mono" ]]; then # monotonic options d_con=${d_con_mono:-"0."} diff --git a/ush/parsing_namelists_FV3.sh b/ush/parsing_namelists_FV3.sh index ec3af83415..da51966645 100755 --- a/ush/parsing_namelists_FV3.sh +++ b/ush/parsing_namelists_FV3.sh @@ -81,6 +81,10 @@ cat > input.nml < input.nml <> input.nml < Date: Wed, 15 Nov 2023 16:44:03 -0500 Subject: [PATCH 8/9] Fix missing _PREV in ocean restart file location (#2070) --- scripts/exglobal_stage_ic.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/exglobal_stage_ic.sh b/scripts/exglobal_stage_ic.sh index 6276255167..58b37f3114 100755 --- a/scripts/exglobal_stage_ic.sh +++ b/scripts/exglobal_stage_ic.sh @@ -90,7 +90,7 @@ for MEMDIR in "${MEMDIR_ARRAY[@]}"; do "025" ) for nn in $(seq 1 3); do src="${BASE_CPLIC}/${CPL_OCNIC:-}/${PDY}${cyc}/${MEMDIR}/ocean/${PDY}.${cyc}0000.MOM.res_${nn}.nc" - tgt="${COM_OCEAN_RESTART}/${PDY}.${cyc}0000.MOM.res_${nn}.nc" + tgt="${COM_OCEAN_RESTART_PREV}/${PDY}.${cyc}0000.MOM.res_${nn}.nc" ${NCP} "${src}" "${tgt}" rc=$? ((rc != 0)) && error_message "${src}" "${tgt}" "${rc}" From 635c4719e603538ce7cccf9ea6b31f3f84f20849 Mon Sep 17 00:00:00 2001 From: Walter Kolczynski - NOAA Date: Thu, 16 Nov 2023 20:35:30 +0000 Subject: [PATCH 9/9] Fix some rocoto dependencies (#2074) A few small errors/cleanup in the dependencies, mostly in fcst: A few small errors/cleanup have crept into the dependencies with recent changes, mostly in fcst: - Fixed the offset, as it would yield a string rocoto doesn't recognize when the interval was 24+ hrs - Removed the duplicate wave dependency. When `waveprep` is included, it depends on `waveinit` so there is no need to add a `waveinit` dependency. - Converted an interval in the archive job that was missed in #2039 Resolves #2075 --- workflow/rocoto/gfs_tasks.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/workflow/rocoto/gfs_tasks.py b/workflow/rocoto/gfs_tasks.py index 1da0f72694..cde0c96771 100644 --- a/workflow/rocoto/gfs_tasks.py +++ b/workflow/rocoto/gfs_tasks.py @@ -156,7 +156,7 @@ def aerosol_init(self): interval = self._base['INTERVAL_GFS'] elif self.cdump in ['gdas']: interval = self._base['INTERVAL'] - offset = f'-{timedelta_to_HMS(interval)}' + offset = timedelta_to_HMS(-interval) # Files from previous cycle files = [f'@Y@m@d.@H0000.fv_core.res.nc'] + \ @@ -491,8 +491,6 @@ def _fcst_forecast_only(self): wave_job = 'waveprep' if self.app_config.model_app in ['ATMW'] else 'waveinit' dep_dict = {'type': 'task', 'name': f'{self.cdump}{wave_job}'} dependencies.append(rocoto.add_dependency(dep_dict)) - dep_dict = {'type': 'task', 'name': f'{self.cdump}waveinit'} - dependencies.append(rocoto.add_dependency(dep_dict)) if self.app_config.do_aero: # Calculate offset based on CDUMP = gfs | gdas @@ -501,7 +499,7 @@ def _fcst_forecast_only(self): interval = self._base['INTERVAL_GFS'] elif self.cdump in ['gdas']: interval = self._base['INTERVAL'] - offset = f'-{interval}' + offset = timedelta_to_HMS(-interval) deps = [] dep_dict = {'type': 'task', 'name': f'{self.cdump}aerosol_init'} deps.append(rocoto.add_dependency(dep_dict)) @@ -1012,7 +1010,7 @@ def arch(self): dep_dict = {'type': 'task', 'name': f'{self.cdump}vminmon'} deps2.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps2) - dep_dict = {'type': 'cycleexist', 'condition': 'not', 'offset': '-06:00:00'} + dep_dict = {'type': 'cycleexist', 'condition': 'not', 'offset': f"-{timedelta_to_HMS(self._base['cycle_interval'])}"} dependencies.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='or', dep=dependencies) if self.cdump in ['gfs'] and self.app_config.do_tracker: