From 9a7abd7a4a1e8d9c39efd8f0177fe850ff6b38c9 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Thu, 19 Jan 2023 14:33:05 -0500 Subject: [PATCH 01/27] update setup_expt.py for cycling w/ coupled model --- workflow/setup_expt.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/workflow/setup_expt.py b/workflow/setup_expt.py index df2f47703e..7c3af2e406 100755 --- a/workflow/setup_expt.py +++ b/workflow/setup_expt.py @@ -185,16 +185,11 @@ def edit_baseconfig(host, inputs): } tmpl_dict = dict(tmpl_dict, **extend_dict) - if inputs.mode in ['cycled']: - extend_dict = { - "@CCPP_SUITE@": 'FV3_GFS_v16', - "@IMP_PHYSICS@": 11 - } - elif inputs.mode in ['forecast-only']: - extend_dict = { - "@CCPP_SUITE@": 'FV3_GFS_v17_p8', - "@IMP_PHYSICS@": 8 - } + # cycled and forecast-only use the same CCPP_SUITE and MP + extend_dict = { + "@CCPP_SUITE@": 'FV3_GFS_v17_p8', + "@IMP_PHYSICS@": 8 + } tmpl_dict = dict(tmpl_dict, **extend_dict) base_input = f'{inputs.configdir}/config.base.emc.dyn' @@ -283,22 +278,24 @@ def input_args(): subp.add_argument('--yaml', help='Defaults to substitute from', type=str, required=False, default=os.path.join(_top, 'parm/config/yaml/defaults.yaml')) + ufs_apps = ['ATM', 'ATMA', 'ATMW', 'S2S', 'S2SW'] + # cycled mode additional arguments cycled.add_argument('--resens', help='resolution of the ensemble model forecast', type=int, required=False, default=192) cycled.add_argument('--nens', help='number of ensemble members', type=int, required=False, default=20) cycled.add_argument('--app', help='UFS application', type=str, - choices=['ATM', 'ATMW', 'ATMA'], required=False, default='ATM') + choices=ufs_apps, required=False, default='ATM') # forecast only mode additional arguments - forecasts.add_argument('--app', help='UFS application', type=str, choices=[ - 'ATM', 'ATMA', 'ATMW', 'S2S', 'S2SW', 'S2SWA', 'NG-GODAS'], required=False, default='ATM') + forecasts.add_argument('--app', help='UFS application', type=str, + choices=ufs_apps + ['S2SWA'], required=False, default='ATM') args = parser.parse_args() - if args.app in ['S2S', 'S2SW'] and args.icsdir is None: - raise SyntaxError("An IC directory must be specified with --icsdir when running the S2S or S2SW app") + if args.mode in ['forecast-only'] and args.app in ['S2S', 'S2SW'] and args.icsdir is None: + raise SyntaxError("An IC directory must be specified with --icsdir when running the S2S or S2SW app in forecast-only mode") # Add an entry for warm_start = .true. or .false. if args.start == "warm": From 87752bc3498a28e0e1e4651392c9251e492f9097 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Thu, 19 Jan 2023 16:03:31 -0500 Subject: [PATCH 02/27] add ocnpost to cycled applications when using coupled model --- workflow/applications.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/workflow/applications.py b/workflow/applications.py index 73c139adb1..1a33daa0aa 100644 --- a/workflow/applications.py +++ b/workflow/applications.py @@ -181,6 +181,9 @@ def _cycled_configs(self): else: configs += ['anal', 'analdiag'] + if self.do_ocean: + configs += ['ocnpost'] + configs += ['sfcanl', 'analcalc', 'fcst', 'post', 'vrfy', 'arch'] if self.do_gldas: @@ -341,7 +344,11 @@ def _get_cycled_task_names(self): """ gdas_gfs_common_tasks_before_fcst = ['prep'] - gdas_gfs_common_tasks_after_fcst = ['post', 'vrfy'] + gdas_gfs_common_tasks_after_fcst = ['post'] + if self.do_ocean: + gdas_gfs_common_tasks_after_fcst += ['ocnpost'] + gdas_gfs_common_tasks_after_fcst += ['vrfy'] + gdas_gfs_common_cleanup_tasks = ['arch'] if self.do_jedivar: From 7fa1c144336e5045a9036170abcb83127cb539ff Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Fri, 20 Jan 2023 14:07:46 -0500 Subject: [PATCH 03/27] fill COMROT for coupled and warm start --- .gitignore | 1 + workflow/setup_expt.py | 127 ++++++++++++++++++++++++++++------------- 2 files changed, 87 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index fb8273d8a4..4f2d103a02 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ __pycache__ *.sw[a-p] ._* .DS_Store +nohup.out .idea/ .vscode/ diff --git a/workflow/setup_expt.py b/workflow/setup_expt.py index 7c3af2e406..35e7a9bb21 100755 --- a/workflow/setup_expt.py +++ b/workflow/setup_expt.py @@ -7,12 +7,12 @@ import os import glob import shutil -from datetime import datetime from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter from hosts import Host from pygw.yaml_file import YAMLFile +from pygw.timetools import to_datetime, to_timedelta, datetime_to_YMDH _here = os.path.dirname(__file__) @@ -55,46 +55,89 @@ def fill_COMROT_cycled(host, inputs): Implementation of 'fill_COMROT' for cycled mode """ - idatestr = inputs.idate.strftime('%Y%m%d%H') comrot = os.path.join(inputs.comrot, inputs.pslot) - if inputs.icsdir is not None: - # Link ensemble member initial conditions - if inputs.nens > 0: - enkfdir = f'enkf{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' - makedirs_if_missing(os.path.join(comrot, enkfdir)) - - # Link atmospheric files (ocean, ice, coming TBD ...) - for ii in range(1, inputs.nens + 1): - memdir = f'mem{ii:03d}/atmos' - dst_dir = os.path.join(comrot, enkfdir, memdir, 'INPUT') - src_dir = os.path.join(inputs.icsdir, enkfdir, memdir, 'INPUT') - makedirs_if_missing(dst_dir) - files = os.listdir(src_dir) - for fname in files: - os.symlink(os.path.join(src_dir, fname), - os.path.join(dst_dir, fname)) - - # Link deterministic initial conditions - detdir = f'{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' - makedirs_if_missing(os.path.join(comrot, detdir)) - - # Link atmospheric files (ocean, ice, TBD ...) - dst_dir = os.path.join(comrot, detdir, 'atmos/INPUT') - src_dir = os.path.join(inputs.icsdir, detdir, 'atmos/INPUT') - makedirs_if_missing(dst_dir) + do_ocean = do_ice = do_med = False + if inputs.app in ['S2S', 'S2SW']: + do_ocean = do_ice = do_med = True + + if inputs.icsdir is None: + print("User did not provide path to stage initial conditions in COMROT") + return + + if inputs.start in ['warm']: # This is warm start experiment + idatestr = datetime_to_YMDH(inputs.idate - to_timedelta('T06H')) + atmos_dir = ocean_dir = ice_dir = 'RESTART' + med_dir = '' + elif inputs.start in ['cold']: # This is a cold start experiment + idatestr = datetime_to_YMDH(inputs.idate) + atmos_dir = 'INPUT' + # ocean_dir, ice_dir TBD for cold start cases + + def link_files_from_src_to_dst(src_dir, dst_dir): files = os.listdir(src_dir) for fname in files: os.symlink(os.path.join(src_dir, fname), - os.path.join(dst_dir, fname)) + os.path.join(dst_dir, fname)) + return + + + # Link ensemble member initial conditions + if inputs.nens > 0: + enkfdir = f'enkf{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' + makedirs_if_missing(os.path.join(comrot, enkfdir)) + + for ii in range(1, inputs.nens + 1): + memdir = f'mem{ii:03d}' + # Link atmospheric files + dst_dir = os.path.join(comrot, enkfdir, memdir, 'atmos', atmos_dir) + src_dir = os.path.join(inputs.icsdir, enkfdir, memdir, 'atmos', atmos_dir) + makedirs_if_missing(dst_dir) + link_files_from_src_to_dst(src_dir, dst_dir) + # ocean, ice, etc. TBD ... + + # Link deterministic initial conditions + detdir = f'{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' + makedirs_if_missing(os.path.join(comrot, detdir)) + + # Link atmospheric files + dst_dir = os.path.join(comrot, detdir, 'atmos', atmos_dir) + src_dir = os.path.join(inputs.icsdir, detdir, 'atmos', atmos_dir) + makedirs_if_missing(dst_dir) + link_files_from_src_to_dst(src_dir, dst_dir) + + # Link ocean files + if do_ocean: + dst_dir = os.path.join(comrot, detdir, 'ocean', ocean_dir) + src_dir = os.path.join(inputs.icsdir, detdir, 'ocean', ocean_dir) + makedirs_if_missing(dst_dir) + link_files_from_src_to_dst(src_dir, dst_dir) - # Link bias correction and radiance diagnostics files - src_dir = os.path.join(inputs.icsdir, detdir, 'atmos') - dst_dir = os.path.join(comrot, detdir, 'atmos') - for ftype in ['abias', 'abias_pc', 'abias_air', 'radstat']: - fname = f'{inputs.cdump}.t{idatestr[8:]}z.{ftype}' - os.symlink(os.path.join(src_dir, f'{fname}'), - os.path.join(dst_dir, f'{fname}')) + # Link ice files + if do_ice: + dst_dir = os.path.join(comrot, detdir, 'ice', ice_dir) + src_dir = os.path.join(inputs.icsdir, detdir, 'ice', ice_dir) + makedirs_if_missing(dst_dir) + link_files_from_src_to_dst(src_dir, dst_dir) + + # Link mediator files + if do_med: + dst_dir = os.path.join(comrot, detdir, 'med', med_dir) + src_dir = os.path.join(inputs.icsdir, detdir, 'med', med_dir) + makedirs_if_missing(dst_dir) + link_files_from_src_to_dst(src_dir, dst_dir) + + # Link bias correction and radiance diagnostics files + idatestr = datetime_to_YMDH(inputs.idate) + detdir = f'{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' + src_dir = os.path.join(inputs.icsdir, detdir, 'atmos') + dst_dir = os.path.join(comrot, detdir, 'atmos') + makedirs_if_missing(dst_dir) + for ftype in ['abias', 'abias_pc', 'abias_air', 'radstat']: + fname = f'{inputs.cdump}.t{idatestr[8:]}z.{ftype}' + src_file = os.path.join(src_dir, fname) + if os.path.exists(src_file): + os.symlink(src_file, os.path.join(dst_dir, fname)) return @@ -164,8 +207,8 @@ def edit_baseconfig(host, inputs): extend_dict = dict() extend_dict = { "@PSLOT@": inputs.pslot, - "@SDATE@": inputs.idate.strftime('%Y%m%d%H'), - "@EDATE@": inputs.edate.strftime('%Y%m%d%H'), + "@SDATE@": datetime_to_YMDH(inputs.idate), + "@EDATE@": datetime_to_YMDH(inputs.edate), "@CASECTL@": f'C{inputs.resdet}', "@EXPDIR@": inputs.expdir, "@ROTDIR@": inputs.comrot, @@ -263,8 +306,8 @@ def input_args(): subp.add_argument('--expdir', help='full path to EXPDIR', type=str, required=False, default=os.getenv('HOME')) subp.add_argument('--idate', help='starting date of experiment, initial conditions must exist!', - required=True, type=lambda dd: datetime.strptime(dd, '%Y%m%d%H')) - subp.add_argument('--edate', help='end date experiment', required=True, type=lambda dd: datetime.strptime(dd, '%Y%m%d%H')) + required=True, type=lambda dd: to_datetime(dd)) + subp.add_argument('--edate', help='end date experiment', required=True, type=lambda dd: to_datetime(dd)) subp.add_argument('--icsdir', help='full path to initial condition directory', type=str, required=False, default=None) subp.add_argument('--configdir', help='full path to directory containing the config files', type=str, required=False, default=os.path.join(_top, 'parm/config')) @@ -298,10 +341,12 @@ def input_args(): raise SyntaxError("An IC directory must be specified with --icsdir when running the S2S or S2SW app in forecast-only mode") # Add an entry for warm_start = .true. or .false. - if args.start == "warm": + if args.start in ['warm']: args.warm_start = ".true." - else: + elif args.start in ['cold']: args.warm_start = ".false." + print(args.warm_start) + return args From 48b0ab012806ec6f94a026d05e2bac4753bce55b Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Sun, 22 Jan 2023 12:00:26 -0500 Subject: [PATCH 04/27] add capability to copy restarts back to com --- ush/forecast_postdet.sh | 157 +++++++++++++++++++++++++++++++--------- ush/forecast_predet.sh | 10 +++ 2 files changed, 131 insertions(+), 36 deletions(-) diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index e74fcac105..f1336cc0e5 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -265,7 +265,7 @@ EOF if [ $imp_physics -eq 8 ]; then $NLN $FIX_AM/CCN_ACTIVATE.BIN $DATA/CCN_ACTIVATE.BIN $NLN $FIX_AM/freezeH2O.dat $DATA/freezeH2O.dat - $NLN $FIX_AM/qr_acr_qg.dat $DATA/qr_acr_qg.dat + $NLN $FIX_AM/qr_acr_qg.dat $DATA/qr_acr_qg.dat $NLN $FIX_AM/qr_acr_qs.dat $DATA/qr_acr_qs.dat fi @@ -620,19 +620,19 @@ WW3_postdet() { for wavGRD in ${grdALL}; do $NCP $ROTDIR/${CDUMP}.${PDY}/${cyc}/wave/rundata/${COMPONENTwave}.mod_def.$wavGRD $DATA/mod_def.$wavGRD done - else - #if shel, only 1 waveGRD which is linked to mod_def.ww3 + else + #if shel, only 1 waveGRD which is linked to mod_def.ww3 $NCP $ROTDIR/${CDUMP}.${PDY}/${cyc}/wave/rundata/${COMPONENTwave}.mod_def.$waveGRD $DATA/mod_def.ww3 fi #if wave mesh is not the same as the ocn/ice mesh, linkk it in the file comparemesh=${MESH_OCN_ICE:-"mesh.mx${ICERES}.nc"} - if [ "$MESH_WAV" = "$comparemesh" ]; then + if [ "$MESH_WAV" = "$comparemesh" ]; then echo "Wave is on same mesh as ocean/ice" - else + else $NLN -sf $FIXwave/$MESH_WAV $DATA/ - fi + fi export WAVHCYC=${WAVHCYC:-6} export WRDATE=$($NDATE -${WAVHCYC} $CDATE) @@ -648,35 +648,35 @@ WW3_postdet() { if [ $warm_start = ".true." -o $RERUN = "YES" ]; then if [ $RERUN = "NO" ]; then waverstfile=${WRDIR}/${sPDY}.${scyc}0000.restart.${wavGRD} - else + else waverstfile=${RSTDIR_WAVE}/${PDYT}.${cyct}0000.restart.${wavGRD} fi - else + else waverstfile=${RSTDIR_WAVE}/${sPDY}.${scyc}0000.restart.${wavGRD} fi if [ ! -f ${waverstfile} ]; then if [ $RERUN = "NO" ]; then echo "WARNING: NON-FATAL ERROR wave IC is missing, will start from rest" - else - echo "ERROR: Wave IC is missing in RERUN, exiting." - exit 1 - fi + else + echo "ERROR: Wave IC is missing in RERUN, exiting." + exit 1 + fi else if [ $waveMULTIGRID = ".true." ]; then $NLN ${waverstfile} $DATA/restart.${wavGRD} - else + else $NLN ${waverstfile} $DATA/restart.ww3 fi fi - done + done if [ $waveMULTIGRID = ".true." ]; then for wavGRD in $waveGRD ; do $NLN $datwave/${wavprfx}.log.${wavGRD}.${PDY}${cyc} log.${wavGRD} done - else - $NLN $datwave/${wavprfx}.log.${waveGRD}.${PDY}${cyc} log.ww3 - fi + else + $NLN $datwave/${wavprfx}.log.${waveGRD}.${PDY}${cyc} log.ww3 + fi if [ "$WW3ICEINP" = "YES" ]; then wavicefile=$COMINwave/rundata/${CDUMPwave}.${WAVEICE_FID}.${cycle}.ice @@ -702,7 +702,7 @@ WW3_postdet() { cd $DATA if [ $waveMULTIGRID = ".true." ]; then $NLN $datwave/${wavprfx}.log.mww3.${PDY}${cyc} log.mww3 - fi + fi # Loop for gridded output (uses FHINC) fhr=$FHMIN_WAV @@ -714,9 +714,9 @@ WW3_postdet() { for wavGRD in ${waveGRD} ; do $NLN $datwave/${wavprfx}.out_grd.${wavGRD}.${YMD}.${HMS} $DATA/${YMD}.${HMS}.out_grd.${wavGRD} done - else + else $NLN $datwave/${wavprfx}.out_grd.${waveGRD}.${YMD}.${HMS} $DATA/${YMD}.${HMS}.out_grd.ww3 - fi + fi FHINC=$FHOUT_WAV if [ $FHMAX_HF_WAV -gt 0 -a $FHOUT_HF_WAV -gt 0 -a $fhr -lt $FHMAX_HF_WAV ]; then FHINC=$FHOUT_HF_WAV @@ -732,9 +732,9 @@ WW3_postdet() { HMS="$(echo $YMDH | cut -c9-10)0000" if [ $waveMULTIGRID = ".true." ]; then $NLN $datwave/${wavprfx}.out_pnt.${waveuoutpGRD}.${YMD}.${HMS} $DATA/${YMD}.${HMS}.out_pnt.${waveuoutpGRD} - else + else $NLN $datwave/${wavprfx}.out_pnt.${waveuoutpGRD}.${YMD}.${HMS} $DATA/${YMD}.${HMS}.out_pnt.ww3 - fi + fi FHINC=$FHINCP_WAV fhr=$((fhr+FHINC)) @@ -747,11 +747,11 @@ WW3_nml() { if [ "${USE_WAV_RMP:-YES}" = "YES" ]; then if (( $( ls -1 $FIXwave/rmp_src_to_dst_conserv_* > /dev/null | wc -l) > 0 )); then for file in $(ls $FIXwave/rmp_src_to_dst_conserv_*) ; do - $NLN $file $DATA/ + $NLN $file $DATA/ done else - echo 'FATAL ERROR : No rmp precomputed nc files found for wave model' - exit 4 + echo 'FATAL ERROR : No rmp precomputed nc files found for wave model' + exit 4 fi fi source $SCRIPTDIR/parsing_namelists_WW3.sh @@ -773,10 +773,23 @@ CPL_out() { MOM6_postdet() { echo "SUB ${FUNCNAME[0]}: MOM6 after run type determination" - OCNRES=${OCNRES:-"025"} + OCNRES=${OCNRES:-"025"} # TODO: remove from here and lift higher # Copy MOM6 ICs - $NCP -pf $ICSDIR/$CDATE/ocn/MOM*nc $DATA/INPUT/ + if [[ "${MODE}" == 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res.nc" "${DATA}/INPUT/MOM.res.nc" + case $OCNRES in + "025") + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_1.nc" "${DATA}/INPUT/MOM.res_1.nc" + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_2.nc" "${DATA}/INPUT/MOM.res_2.nc" + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_3.nc" "${DATA}/INPUT/MOM.res_3.nc" + ;; + *) + ;; + esac + else + $NCP -pf "${ICSDIR}/${CDATE}/ocn/MOM*nc" "${DATA}/INPUT/" # TODO: Update files in ICSDIR to reflect COM structure naming convention + fi # Copy MOM6 fixed files $NCP -pf $FIXmom/$OCNRES/* $DATA/INPUT/ @@ -790,10 +803,16 @@ MOM6_postdet() { exit 3 fi - # Copy mediator restart files to RUNDIR - if [ $warm_start = ".true." -o $RERUN = "YES" ]; then - $NCP $ROTDIR/$CDUMP.$PDY/$cyc/med/ufs.cpld*.nc $DATA/ - $NCP $ROTDIR/$CDUMP.$PDY/$cyc/med/rpointer.cpl $DATA/ + # Copy mediator restart file to RUNDIR # TODO: mediator should have its own CMEPS_postdet() function + local mediator_file="${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/med/${PDY}.${cyc}0000.ufs.cpld.cpl.r.nc" + if [[ -f "${mediator_file}" ]]; then + $NCP "${mediator_file}" "${DATA}/ufs.cpld.cpl.r.nc" + rm -f "${DATA}/rpointer.cpl" + touch "${DATA}/rpointer.cpl" + echo "ufs.cpld.cpl.r.nc" >> "${DATA}/rpointer.cpl" + else + echo "FATAL ERROR: ${mediator_file} does not exist, ABORT!" + exit 4 fi if [ $DO_OCN_SPPT = "YES" -o $DO_OCN_PERT_EPBL = "YES" ]; then @@ -864,6 +883,51 @@ MOM6_nml() { MOM6_out() { echo "SUB ${FUNCNAME[0]}: Copying output data for MOM6" + + # Link ocean restarts from DATA to COM + local ocean_com_dir="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ocean" + mkdir -p "${ocean_com_dir}/RESTART" + # end point restart does not have a timestamp, calculate + local rdate=$($NDATE $FHMAX $CDATE) + $NLN "${DATA}/MOM6_RESTART/MOM.res.nc" "${ocean_com_dir}/RESTART/${rdate:0:8}.${rdate:8:2}0000.res.nc" + # Greater than 1/2 degree have a single MOM restart + # Less than 1/2 degree have 3 additional restarts + case ${OCNRES} in + "025") + $NLN "${DATA}/MOM6_RESTART/MOM.res_1.nc" "${ocean_com_dir}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_1.nc" + $NLN "${DATA}/MOM6_RESTART/MOM.res_2.nc" "${ocean_com_dir}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_2.nc" + $NLN "${DATA}/MOM6_RESTART/MOM.res_3.nc" "${ocean_com_dir}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_3.nc" + ;; + *) + ;; + esac + # Loop over restart_interval_nems and link restarts from DATA to COM + local idate=$($NDATE $restart_interval_nems $CDATE) + while [[ $idate -lt $rdate ]]; do + local idatestr=$(date +%Y-%m-%d-%H -d "${idate:0:8} ${idate:8:2}") + $NLN "${DATA}/MOM6_RESTART/MOM.res.${idatestr}-00-00.nc" "${ocean_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000.res.nc" + case ${OCNRES} in + "025") + $NLN "${DATA}/MOM6_RESTART/MOM.res_1.${idatestr}-00-00.nc" "${ocean_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_1.nc" + $NLN "${DATA}/MOM6_RESTART/MOM.res_2.${idatestr}-00-00.nc" "${ocean_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_2.nc" + $NLN "${DATA}/MOM6_RESTART/MOM.res_3.${idatestr}-00-00.nc" "${ocean_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_3.nc" + ;; + *) + ;; + esac + local idate=$($NDATE $restart_interval_nems $idate) + done + + # TODO: mediator should have its own CMEPS_out() function + # Link mediator restarts from DATA to COM + local med_com_dir="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/med" + mkdir -p "${med_com_dir}/RESTART" + local idate=$($NDATE $restart_interval_nems $CDATE) + while [[ $idate -le $rdate ]]; do + local seconds=$(to_seconds ${idatestr:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds + local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" + $NLN "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}" "${med_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000."ufs.cpld.cpl.r.nc + done } CICE_postdet() { @@ -872,7 +936,7 @@ CICE_postdet() { year=$(echo $CDATE|cut -c 1-4) month=$(echo $CDATE|cut -c 5-6) day=$(echo $CDATE|cut -c 7-8) - sec=$(echo $CDATE|cut -c 9-10) + sec=$(echo $CDATE|cut -c 9-10) stepsperhr=$((3600/$ICETIM)) nhours=$($NHOUR $CDATE ${year}010100) steps=$((nhours*stepsperhr)) @@ -918,16 +982,23 @@ CICE_postdet() { ice_kmt_file=${ice_kmt_file:-"kmtu_cice_NEMS_mx${ICERES}.nc"} export MESH_OCN_ICE=${MESH_OCN_ICE:-"mesh.mx${ICERES}.nc"} - iceic="cice_model.res_$CDATE.nc" - - # Copy CICE IC - $NCP -p $ICSDIR/$CDATE/ice/cice_model_${ICERESdec}.res_$CDATE.nc $DATA/$iceic + # Copy/link CICE IC to DATA + if [[ "${MODE}" == 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${cyc}/ice/RESTART/${PDY}.${cyc}0000.cice_model.res.nc" "${DATA}/cice_model.res.nc" + else + $NCP -p $ICSDIR/$CDATE/ice/cice_model_${ICERESdec}.res_$CDATE.nc $DATA/cice_model.res.nc + fi + # TODO: add a check for the restarts to exist, if not, exit eloquently + rm -f "${DATA}/ice.restart_file" + touch "${DATA}/ice.restart_file" + echo "${DATA}/cice_model.res.nc" >> "${DATA}/ice.restart_file" echo "Link CICE fixed files" $NLN -sf $FIXcice/$ICERES/${ice_grid_file} $DATA/ $NLN -sf $FIXcice/$ICERES/${ice_kmt_file} $DATA/ $NLN -sf $FIXcice/$ICERES/$MESH_OCN_ICE $DATA/ + # TODO: shouldn't this be in CICE_out()? # Link output files export ENSMEM=${ENSMEM:-01} export IDATE=$CDATE @@ -964,6 +1035,20 @@ CICE_nml() { CICE_out() { echo "SUB ${FUNCNAME[0]}: Copying output data for CICE" + # TODO: Why is this empty? Is there no cice output being copied back to COM? There is output linked to COMOUTice in CICE_postdet() + # And people as why this needs refactoring. + + local ice_com_dir="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ice" + mkdir -p "${ice_com_dir}/RESTART" + + # Link ice restarts to COMOUTice + # Loop over restart_interval_nems and link restarts from DATA to COM + local idate=$($NDATE $restart_interval_nems $CDATE) + while [[ $idate -le $rdate ]]; do + local seconds=$(to_seconds ${idatestr:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds + local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" + $NLN "${DATA}/RESTART/iced.${idatestr}" "${ice_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000.cice_model.res.nc" + done } GOCART_rc() { diff --git a/ush/forecast_predet.sh b/ush/forecast_predet.sh index f3ed57292e..b2c6304581 100755 --- a/ush/forecast_predet.sh +++ b/ush/forecast_predet.sh @@ -10,6 +10,16 @@ # For all non-evironment variables # Cycling and forecast hour specific parameters + +to_seconds() { +# Function to convert HHMMSS to seconds since 00Z + local hhmmss=${1} + local hh=${hhmmss:0:2} + local mm=${hhmmss:2:2} + local ss=${hhmmss:4:2} + echo $(((hh*3600+mm*60+ss))) +} + common_predet(){ echo "SUB ${FUNCNAME[0]}: Defining variables for shared through models" pwd=$(pwd) From c463640e494535f3fdda54485bd775eece0e5bae Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Sun, 22 Jan 2023 15:46:09 -0500 Subject: [PATCH 05/27] make room for C48O5deg. configuration --- parm/config/config.base.emc.dyn | 53 +++++++++++++++++--------------- parm/config/config.defaults.s2sw | 35 ++++++++++++--------- parm/config/config.fv3 | 14 ++++----- parm/config/config.resources | 4 ++- ush/forecast_postdet.sh | 22 ++++++------- workflow/applications.py | 7 ++++- workflow/setup_expt.py | 1 + 7 files changed, 77 insertions(+), 59 deletions(-) diff --git a/parm/config/config.base.emc.dyn b/parm/config/config.base.emc.dyn index 5519b6a3bb..33a74fee66 100755 --- a/parm/config/config.base.emc.dyn +++ b/parm/config/config.base.emc.dyn @@ -165,6 +165,26 @@ export DOBNDPNT_WAVE="NO" export cplwav2atm=".false." export FRAC_GRID=".true." +# Set operational resolution +export OPS_RES="C768" # Do not change + +# Resolution specific parameters +export LEVS=128 +export CASE="@CASECTL@" +export CASE_ENKF="@CASEENS@" +case "$CASE" in + "C48") + export OCNRES=500 + export OCNTIM=3600 # TODO: add OCNTIM for other resolutions? + ;; + "C96") export OCNRES=100;; + "C192") export OCNRES=050;; + "C384") export OCNRES=025;; + "C768") export OCNRES=025;; + *) export OCNRES=025;; +esac +export ICERES=$OCNRES + case "${APP}" in ATM) export confignamevarfornems="atm" @@ -212,23 +232,6 @@ case "${APP}" in ;; esac -# Set operational resolution -export OPS_RES="C768" # Do not change - -# Resolution specific parameters -export LEVS=128 -export CASE="@CASECTL@" -export CASE_ENKF="@CASEENS@" -case "$CASE" in - "C48") export OCNRES=500;; - "C96") export OCNRES=100;; - "C192") export OCNRES=050;; - "C384") export OCNRES=025;; - "C768") export OCNRES=025;; - *) export OCNRES=025;; -esac -export ICERES=$OCNRES - # Surface cycle update frequency if [[ "$CDUMP" == "gdas" ]] ; then export FHCYC=1 @@ -305,7 +308,7 @@ export IAU_DELTHRS_ENKF=6 export lobsdiag_forenkf=".true." # run GLDAS to spin up land ICs -export DO_GLDAS="YES" +export DO_GLDAS="NO" export gldas_cyc=00 # Exception handling that when DO_GLDAS is set, the FHOUT must be 1 @@ -328,12 +331,14 @@ export DO_JEDIENS="NO" export DO_JEDIOCNVAR="NO" # Hybrid related -export DOHYBVAR="YES" -export NMEM_ENKF=@NMEM_ENKF@ -export NMEM_EFCS=30 -export SMOOTH_ENKF="NO" -export l4densvar=".true." -export lwrite4danl=".true." +export DOHYBVAR="@DOHYBVAR@" +if [ $DOHYBVAR = "YES" ]; then # Only relevant, if doing hybrid + export NMEM_ENKF=@NMEM_ENKF@ + export NMEM_EFCS=30 + export SMOOTH_ENKF="NO" + export l4densvar=".true." + export lwrite4danl=".true." +fi # EnKF output frequency if [ $DOHYBVAR = "YES" ]; then diff --git a/parm/config/config.defaults.s2sw b/parm/config/config.defaults.s2sw index 5032a998ad..a5f992e858 100644 --- a/parm/config/config.defaults.s2sw +++ b/parm/config/config.defaults.s2sw @@ -3,7 +3,6 @@ # Empty variables must include a space otherwise they will be overwritten # config.base -# CASE=C384 FHMAX_GFS_00=48 FHMAX_GFS_06=48 FHMAX_GFS_12=48 @@ -15,21 +14,27 @@ FHOUT_HF_GFS=-1 min_seaice="1.0e-6" use_cice_alb=".true." -# config.fv3 -DELTIM=300 -layout_x_gfs=8 -layout_y_gfs=8 -WRITE_GROUP_GFS=1 -WRTTASK_PER_GROUP_GFS=24 -#The settings below will result in S2SWA running 35 days under 8 hours wallclock on hera -#layout_x_gfs=24 -#layout_y_gfs=16 -#WRTTASK_PER_GROUP_GFS=86 -WRTIOBUF="32M" -MEDPETS=300 - +# config.fv3 # TODO: This is hard-wired for P8 and needs to be refactored. For now, use case C384 +case "${CASE}" in + "C384") + DELTIM=300 + layout_x_gfs=8 + layout_y_gfs=8 + WRITE_GROUP_GFS=1 + WRTTASK_PER_GROUP_GFS=24 + #The settings below will result in S2SWA running 35 days under 8 hours wallclock on hera + #layout_x_gfs=24 + #layout_y_gfs=16 + #WRTTASK_PER_GROUP_GFS=86 + WRTIOBUF="32M" # TODO: This value is for P8 w/ C384. Why not update/set this as default in config.fv3 C384? + MEDPETS=300 # TODO: P8 wants to use 300 instead of ATMPETS = layout_x * layout_y * 6 + ;; +esac + +# config.ice + +# TODO: These also are likely P8 hard-wired configurations. Perhaps this file should be config.P8.defaults # config.wave - waveGRD='gwes_30m' waveinterpGRD=' ' waveuoutpGRD='gwes_30m' diff --git a/parm/config/config.fv3 b/parm/config/config.fv3 index ce39807d11..1f6fea460d 100755 --- a/parm/config/config.fv3 +++ b/parm/config/config.fv3 @@ -45,18 +45,18 @@ fi # (Standard) Model resolution dependent variables case ${case_in} in "C48") - export DELTIM=450 - export layout_x=3 - export layout_y=2 - export layout_x_gfs=3 - export layout_y_gfs=2 + export DELTIM=1200 + export layout_x=1 + export layout_y=1 + export layout_x_gfs=1 + export layout_y_gfs=1 export nth_fv3=1 export nth_fv3_gfs=1 export cdmbgwd="0.071,2.1,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling export WRITE_GROUP=1 - export WRTTASK_PER_GROUP=64 + export WRTTASK_PER_GROUP=6 export WRITE_GROUP_GFS=1 - export WRTTASK_PER_GROUP_GFS=64 + export WRTTASK_PER_GROUP_GFS=6 export WRTIOBUF="1M" ;; "C96") diff --git a/parm/config/config.resources b/parm/config/config.resources index 6e5c956db8..b71d1c9b0b 100755 --- a/parm/config/config.resources +++ b/parm/config/config.resources @@ -370,7 +370,7 @@ elif [ ${step} = "gldas" ]; then elif [ ${step} = "fcst" ]; then - export wtime_fcst="00:40:00" + export wtime_fcst="00:30:00" if [ ${CASE} = "C768" ]; then export wtime_fcst_gfs="06:00:00" elif [ ${CASE} = "C384" ]; then @@ -437,6 +437,7 @@ elif [ ${step} = "fcst" ]; then if [[ ${DO_OCN} == "YES" ]]; then case ${OCNRES} in # Except for 025, these are guesses for now + 500) export OCNPETS=8 ;; 100) export OCNPETS=20 ;; 050) export OCNPETS=60 ;; 025) export OCNPETS=220 ;; @@ -451,6 +452,7 @@ elif [ ${step} = "fcst" ]; then if [[ ${DO_ICE} == "YES" ]]; then case ${ICERES} in # Except for 025, these are guesses for now + 500) export ICEPETS=4 ;; 100) export ICEPETS=10 ;; 050) export ICEPETS=30 ;; 025) export ICEPETS=120 ;; diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index f1336cc0e5..a31fac1ff2 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -943,7 +943,15 @@ CICE_postdet() { npt=$((FHMAX*$stepsperhr)) # Need this in order for dump_last to work histfreq_n=${histfreq_n:-6} - dumpfreq_n=${dumpfreq_n:-840} # restart write interval in seconds, default 35 days + if [[ "${MODE}" == "cycled" ]]; then # TODO: this needs to be improved to include CDUMP = GDAS | GFS + if [[ "${CDUMP}"= "gdas" ]]; then # TODO: improve and remove this default of dumping hourly restarts for cycled system + dumpfreq_n=1 + elif [[ "${CDUMP}" = "gfs" ]]; then + dumpfreq_n=${dumpfreq_n:-24} + fi + else + dumpfreq_n=${dumpfreq_n:-840} # default 35 days (840 hours) for forecast-only + fi dumpfreq=${dumpfreq:-"h"} # "h","d","m" or "y" for restarts at intervals of "hours", "days", "months" or "years" cice_hist_avg=${cice_hist_avg:-".true."} @@ -967,16 +975,8 @@ CICE_postdet() { USE_RESTART_TIME='.false.' restart_pond_lvl=${restart_pond_lvl:-".false."} - ICERES=${ICERES:-"025"} - if [ $ICERES = '025' ]; then - ICERESdec="0.25" - fi - if [ $ICERES = '050' ]; then - ICERESdec="0.50" - fi - if [ $ICERES = '100' ]; then - ICERESdec="1.00" - fi + ICERES=${ICERES:-"025"} # TODO: similar to MOM_out, lift this higher + ICERESdec=echo "$ICERES" | awk '{printf "%0.2f", $1/100}' ice_grid_file=${ice_grid_file:-"grid_cice_NEMS_mx${ICERES}.nc"} ice_kmt_file=${ice_kmt_file:-"kmtu_cice_NEMS_mx${ICERES}.nc"} diff --git a/workflow/applications.py b/workflow/applications.py index 1a33daa0aa..e29f55bcea 100644 --- a/workflow/applications.py +++ b/workflow/applications.py @@ -443,7 +443,12 @@ def _get_cycled_task_names(self): gfs_tasks += gdas_gfs_common_cleanup_tasks - tasks = {'gdas': gdas_tasks, 'gfs': gfs_tasks} + tasks = dict() + tasks['gdas'] = gdas_tasks + + # Add CDUMP=gfs tasks if running early cycle + if self.gfs_cyc > 0: + tasks['gfs'] = gfs_tasks return tasks diff --git a/workflow/setup_expt.py b/workflow/setup_expt.py index 35e7a9bb21..486fc6f7f3 100755 --- a/workflow/setup_expt.py +++ b/workflow/setup_expt.py @@ -225,6 +225,7 @@ def edit_baseconfig(host, inputs): extend_dict = { "@CASEENS@": f'C{inputs.resens}', "@NMEM_ENKF@": inputs.nens, + "@DOHYBVAR@": "YES" if inputs.nens > 0 else "NO", } tmpl_dict = dict(tmpl_dict, **extend_dict) From 07206c3b09922ba96d9e8feac9bfc8cba28fed27 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Sun, 22 Jan 2023 15:51:42 -0500 Subject: [PATCH 06/27] pynorm check --- workflow/setup_expt.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/workflow/setup_expt.py b/workflow/setup_expt.py index 486fc6f7f3..e23be16fb9 100755 --- a/workflow/setup_expt.py +++ b/workflow/setup_expt.py @@ -78,10 +78,9 @@ def link_files_from_src_to_dst(src_dir, dst_dir): files = os.listdir(src_dir) for fname in files: os.symlink(os.path.join(src_dir, fname), - os.path.join(dst_dir, fname)) + os.path.join(dst_dir, fname)) return - # Link ensemble member initial conditions if inputs.nens > 0: enkfdir = f'enkf{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' @@ -334,7 +333,7 @@ def input_args(): # forecast only mode additional arguments forecasts.add_argument('--app', help='UFS application', type=str, - choices=ufs_apps + ['S2SWA'], required=False, default='ATM') + choices=ufs_apps + ['S2SWA'], required=False, default='ATM') args = parser.parse_args() From 897e454b28f8a7f10b6fa3d112510980735f7648 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Sun, 22 Jan 2023 23:05:05 -0500 Subject: [PATCH 07/27] add 5deg MOM6_input template and update config.ice for 5deg --- parm/config/config.base.emc.dyn | 12 +- parm/config/config.ice | 16 +- parm/mom6/MOM_input_template_500 | 537 +++++++++++++++++++++++++++++++ ush/forecast_postdet.sh | 14 +- ush/parsing_namelists_CICE.sh | 2 +- ush/parsing_namelists_MOM6.sh | 90 +++--- 6 files changed, 613 insertions(+), 58 deletions(-) create mode 100644 parm/mom6/MOM_input_template_500 diff --git a/parm/config/config.base.emc.dyn b/parm/config/config.base.emc.dyn index 33a74fee66..62cdf1d2af 100755 --- a/parm/config/config.base.emc.dyn +++ b/parm/config/config.base.emc.dyn @@ -332,13 +332,11 @@ export DO_JEDIOCNVAR="NO" # Hybrid related export DOHYBVAR="@DOHYBVAR@" -if [ $DOHYBVAR = "YES" ]; then # Only relevant, if doing hybrid - export NMEM_ENKF=@NMEM_ENKF@ - export NMEM_EFCS=30 - export SMOOTH_ENKF="NO" - export l4densvar=".true." - export lwrite4danl=".true." -fi +export NMEM_ENKF=@NMEM_ENKF@ +export NMEM_EFCS=30 +export SMOOTH_ENKF="NO" +export l4densvar=".true." +export lwrite4danl=".true." # EnKF output frequency if [ $DOHYBVAR = "YES" ]; then diff --git a/parm/config/config.ice b/parm/config/config.ice index 3a6916600f..19f493fda2 100644 --- a/parm/config/config.ice +++ b/parm/config/config.ice @@ -1,4 +1,16 @@ #! /usr/bin/env bash -export NX_GLB="1440" -export NY_GLB="1080" +case "${ICERES}" in + "025") + export NX_GLB="1440" + export NY_GLB="1080" + ;; + "500") # TODO: From GV, check w/ DW + export NX_GLB="36" + export NY_GLB="70" + ;; + *) + echo "FATAL ERROR: Unsupported ICERES = ${ICERES}, ABORT!" + exit 1 + ;; +esac diff --git a/parm/mom6/MOM_input_template_500 b/parm/mom6/MOM_input_template_500 new file mode 100644 index 0000000000..2cae7e88a9 --- /dev/null +++ b/parm/mom6/MOM_input_template_500 @@ -0,0 +1,537 @@ +! This file was written by the model and records the non-default parameters used at run-time. + +! === module MOM === + +! === module MOM_unit_scaling === +! Parameters for doing unit scaling of variables. +USE_REGRIDDING = True ! [Boolean] default = False + ! If True, use the ALE algorithm (regridding/remapping). If False, use the + ! layered isopycnal algorithm. +THICKNESSDIFFUSE = True ! [Boolean] default = False + ! If true, interface heights are diffused with a coefficient of KHTH. +THICKNESSDIFFUSE_FIRST = True ! [Boolean] default = False + ! If true, do thickness diffusion before dynamics. This is only used if + ! THICKNESSDIFFUSE is true. +DT = @[DT_DYNAM_MOM6] ! [s] + ! The (baroclinic) dynamics time step. The time-step that is actually used will + ! be an integer fraction of the forcing time-step (DT_FORCING in ocean-only mode + ! or the coupling timestep in coupled mode.) +DT_THERM = @[DT_THERM_MOM6] ! [s] default = 1800.0 + ! The thermodynamic and tracer advection time step. Ideally DT_THERM should be + ! an integer multiple of DT and less than the forcing or coupling time-step, + ! unless THERMO_SPANS_COUPLING is true, in which case DT_THERM can be an integer + ! multiple of the coupling timestep. By default DT_THERM is set to DT. +THERMO_SPANS_COUPLING = False ! [Boolean] default = False + ! If true, the MOM will take thermodynamic and tracer timesteps that can be + ! longer than the coupling timestep. The actual thermodynamic timestep that is + ! used in this case is the largest integer multiple of the coupling timestep + ! that is less than or equal to DT_THERM. +HFREEZE = 20.0 ! [m] default = -1.0 + ! If HFREEZE > 0, melt potential will be computed. The actual depth + ! over which melt potential is computed will be min(HFREEZE, OBLD) + ! where OBLD is the boundary layer depth. If HFREEZE <= 0 (default) + ! melt potential will not be computed. +FRAZIL = True ! [Boolean] default = False + ! If true, water freezes if it gets too cold, and the accumulated heat deficit + ! is returned in the surface state. FRAZIL is only used if + ! ENABLE_THERMODYNAMICS is true. +BOUND_SALINITY = True ! [Boolean] default = False + ! If true, limit salinity to being positive. (The sea-ice model may ask for more + ! salt than is available and drive the salinity negative otherwise.) + +! === module MOM_domains === +TRIPOLAR_N = True ! [Boolean] default = False + ! Use tripolar connectivity at the northern edge of the domain. With + ! TRIPOLAR_N, NIGLOBAL must be even. +NIGLOBAL = @[NX_GLB] ! + ! The total number of thickness grid points in the x-direction in the physical + ! domain. With STATIC_MEMORY_ this is set in MOM_memory.h at compile time. +NJGLOBAL = @[NY_GLB] ! + ! The total number of thickness grid points in the y-direction in the physical + ! domain. With STATIC_MEMORY_ this is set in MOM_memory.h at compile time. + +! === module MOM_hor_index === +! Sets the horizontal array index types. + +! === module MOM_fixed_initialization === +INPUTDIR = "INPUT" ! default = "." + ! The directory in which input files are found. + +! === module MOM_grid_init === +GRID_CONFIG = "mosaic" ! + ! A character string that determines the method for defining the horizontal + ! grid. Current options are: + ! mosaic - read the grid from a mosaic (supergrid) + ! file set by GRID_FILE. + ! cartesian - use a (flat) Cartesian grid. + ! spherical - use a simple spherical grid. + ! mercator - use a Mercator spherical grid. +GRID_FILE = "ocean_hgrid.nc" ! + ! Name of the file from which to read horizontal grid data. +GRID_ROTATION_ANGLE_BUGS = False ! [Boolean] default = True + ! If true, use an older algorithm to calculate the sine and + ! cosines needed rotate between grid-oriented directions and + ! true north and east. Differences arise at the tripolar fold +USE_TRIPOLAR_GEOLONB_BUG = False ! [Boolean] default = True + ! If true, use older code that incorrectly sets the longitude in some points + ! along the tripolar fold to be off by 360 degrees. +TOPO_CONFIG = "file" ! + ! This specifies how bathymetry is specified: + ! file - read bathymetric information from the file + ! specified by (TOPO_FILE). + ! flat - flat bottom set to MAXIMUM_DEPTH. + ! bowl - an analytically specified bowl-shaped basin + ! ranging between MAXIMUM_DEPTH and MINIMUM_DEPTH. + ! spoon - a similar shape to 'bowl', but with an vertical + ! wall at the southern face. + ! halfpipe - a zonally uniform channel with a half-sine + ! profile in the meridional direction. + ! bbuilder - build topography from list of functions. + ! benchmark - use the benchmark test case topography. + ! Neverworld - use the Neverworld test case topography. + ! DOME - use a slope and channel configuration for the + ! DOME sill-overflow test case. + ! ISOMIP - use a slope and channel configuration for the + ! ISOMIP test case. + ! DOME2D - use a shelf and slope configuration for the + ! DOME2D gravity current/overflow test case. + ! Kelvin - flat but with rotated land mask. + ! seamount - Gaussian bump for spontaneous motion test case. + ! dumbbell - Sloshing channel with reservoirs on both ends. + ! shelfwave - exponential slope for shelfwave test case. + ! Phillips - ACC-like idealized topography used in the Phillips config. + ! dense - Denmark Strait-like dense water formation and overflow. + ! USER - call a user modified routine. +TOPO_FILE = "ocean_topog.nc" ! default = "topog.nc" + ! The file from which the bathymetry is read. +!MAXIMUM_DEPTH = 5801.341919389728 ! [m] + ! The (diagnosed) maximum depth of the ocean. +MINIMUM_DEPTH = 10.0 ! [m] default = 0.0 + ! If MASKING_DEPTH is unspecified, then anything shallower than MINIMUM_DEPTH is + ! assumed to be land and all fluxes are masked out. If MASKING_DEPTH is + ! specified, then all depths shallower than MINIMUM_DEPTH but deeper than + ! MASKING_DEPTH are rounded to MINIMUM_DEPTH. + +! === module MOM_open_boundary === +! Controls where open boundaries are located, what kind of boundary condition to impose, and what data to apply, +! if any. +MASKING_DEPTH = 0.0 ! [m] default = -9999.0 + ! The depth below which to mask points as land points, for which all fluxes are + ! zeroed out. MASKING_DEPTH is ignored if negative. + +! === module MOM_verticalGrid === +! Parameters providing information about the vertical grid. +NK = 25 ! [nondim] + ! The number of model layers. + +! === module MOM_tracer_registry === + +! === module MOM_EOS === +TFREEZE_FORM = "MILLERO_78" ! default = "LINEAR" + ! TFREEZE_FORM determines which expression should be used for the freezing + ! point. Currently, the valid choices are "LINEAR", "MILLERO_78", "TEOS10" + +! === module MOM_restart === +RESTART_CHECKSUMS_REQUIRED = False +! === module MOM_tracer_flow_control === + +! === module MOM_coord_initialization === +COORD_CONFIG = "file" ! default = "none" + ! This specifies how layers are to be defined: + ! ALE or none - used to avoid defining layers in ALE mode + ! file - read coordinate information from the file + ! specified by (COORD_FILE). + ! BFB - Custom coords for buoyancy-forced basin case + ! based on SST_S, T_BOT and DRHO_DT. + ! linear - linear based on interfaces not layers + ! layer_ref - linear based on layer densities + ! ts_ref - use reference temperature and salinity + ! ts_range - use range of temperature and salinity + ! (T_REF and S_REF) to determine surface density + ! and GINT calculate internal densities. + ! gprime - use reference density (RHO_0) for surface + ! density and GINT calculate internal densities. + ! ts_profile - use temperature and salinity profiles + ! (read from COORD_FILE) to set layer densities. + ! USER - call a user modified routine. +COORD_FILE = "layer_coord25.nc" ! + ! The file from which the coordinate densities are read. +REGRIDDING_COORDINATE_MODE = "HYCOM1" ! default = "LAYER" + ! Coordinate mode for vertical regridding. Choose among the following + ! possibilities: LAYER - Isopycnal or stacked shallow water layers + ! ZSTAR, Z* - stretched geopotential z* + ! SIGMA_SHELF_ZSTAR - stretched geopotential z* ignoring shelf + ! SIGMA - terrain following coordinates + ! RHO - continuous isopycnal + ! HYCOM1 - HyCOM-like hybrid coordinate + ! SLIGHT - stretched coordinates above continuous isopycnal + ! ADAPTIVE - optimize for smooth neutral density surfaces +BOUNDARY_EXTRAPOLATION = True ! [Boolean] default = False + ! When defined, a proper high-order reconstruction scheme is used within + ! boundary cells rather than PCM. E.g., if PPM is used for remapping, a PPM + ! reconstruction will also be used within boundary cells. +ALE_COORDINATE_CONFIG = "HYBRID:hycom1_25.nc,sigma2,FNC1:5,4000,4.5,.01" ! default = "UNIFORM" + ! Determines how to specify the coordinate + ! resolution. Valid options are: + ! PARAM - use the vector-parameter ALE_RESOLUTION + ! UNIFORM[:N] - uniformly distributed + ! FILE:string - read from a file. The string specifies + ! the filename and variable name, separated + ! by a comma or space, e.g. FILE:lev.nc,dz + ! or FILE:lev.nc,interfaces=zw + ! WOA09[:N] - the WOA09 vertical grid (approximately) + ! FNC1:string - FNC1:dz_min,H_total,power,precision + ! HYBRID:string - read from a file. The string specifies + ! the filename and two variable names, separated + ! by a comma or space, for sigma-2 and dz. e.g. + ! HYBRID:vgrid.nc,sigma2,dz +!ALE_RESOLUTION = 2*5.0, 5.01, 5.07, 5.25, 5.68, 6.55, 8.1, 10.66, 14.620000000000001, 20.450000000000003, 28.73, 40.1, 55.32, 75.23, 100.8, 133.09, 173.26, 222.62, 282.56, 354.62, 440.47, 541.87, 660.76, 799.1800000000001 ! [m] + ! The distribution of vertical resolution for the target + ! grid used for Eulerian-like coordinates. For example, + ! in z-coordinate mode, the parameter is a list of level + ! thicknesses (in m). In sigma-coordinate mode, the list + ! is of non-dimensional fractions of the water column. +!TARGET_DENSITIES = 1010.0, 1020.843017578125, 1027.0274658203125, 1029.279541015625, 1030.862548828125, 1032.1572265625, 1033.27978515625, 1034.251953125, 1034.850830078125, 1035.28857421875, 1035.651123046875, 1035.967529296875, 1036.2410888671875, 1036.473876953125, 1036.6800537109375, 1036.8525390625, 1036.9417724609375, 1037.0052490234375, 1037.057373046875, 1037.1065673828125, 1037.15576171875, 1037.2060546875, 1037.26416015625, 1037.3388671875, 1037.4749755859375, 1038.0 ! [m] + ! HYBRID target densities for itnerfaces +REGRID_COMPRESSIBILITY_FRACTION = 0.01 ! [not defined] default = 0.0 + ! When interpolating potential density profiles we can add + ! some artificial compressibility solely to make homogenous + ! regions appear stratified. +MAXIMUM_INT_DEPTH_CONFIG = "FNC1:5,8000.0,1.0,.125" ! default = "NONE" + ! Determines how to specify the maximum interface depths. + ! Valid options are: + ! NONE - there are no maximum interface depths + ! PARAM - use the vector-parameter MAXIMUM_INTERFACE_DEPTHS + ! FILE:string - read from a file. The string specifies + ! the filename and variable name, separated + ! by a comma or space, e.g. FILE:lev.nc,Z + ! FNC1:string - FNC1:dz_min,H_total,power,precision +!MAXIMUM_INT_DEPTHS = 0.0, 5.0, 36.25, 93.75, 177.5, 287.5, 423.75, 586.25, 775.0, 990.0, 1231.25, 1498.75, 1792.5, 2112.5, 2458.75, 2831.25, 3230.0, 3655.0, 4106.25, 4583.75, 5087.5, 5617.5, 6173.75, 6756.25, 7365.0, 8000.0 ! [m] + ! The list of maximum depths for each interface. +MAX_LAYER_THICKNESS_CONFIG = "FNC1:400,31000.0,0.1,.01" ! default = "NONE" + ! Determines how to specify the maximum layer thicknesses. + ! Valid options are: + ! NONE - there are no maximum layer thicknesses + ! PARAM - use the vector-parameter MAX_LAYER_THICKNESS + ! FILE:string - read from a file. The string specifies + ! the filename and variable name, separated + ! by a comma or space, e.g. FILE:lev.nc,Z + ! FNC1:string - FNC1:dz_min,H_total,power,precision +!MAX_LAYER_THICKNESS = 400.0, 1094.2, 1144.02, 1174.81, 1197.42, 1215.4099999999999, 1230.42, 1243.3200000000002, 1254.65, 1264.78, 1273.94, 1282.31, 1290.02, 1297.17, 1303.85, 1310.1, 1316.0, 1321.5700000000002, 1326.85, 1331.87, 1336.67, 1341.25, 1345.6399999999999, 1349.85, 1353.88 ! [m] + ! The list of maximum thickness for each layer. +REMAPPING_SCHEME = "PPM_H4" ! default = "PLM" + ! This sets the reconstruction scheme used for vertical remapping for all + ! variables. It can be one of the following schemes: PCM (1st-order + ! accurate) + ! PLM (2nd-order accurate) + ! PPM_H4 (3rd-order accurate) + ! PPM_IH4 (3rd-order accurate) + ! PQM_IH4IH3 (4th-order accurate) + ! PQM_IH6IH5 (5th-order accurate) + +! === module MOM_grid === +! Parameters providing information about the lateral grid. + +! === module MOM_state_initialization === +INIT_LAYERS_FROM_Z_FILE = True ! [Boolean] default = False + ! If true, initialize the layer thicknesses, temperatures, and salinities from a + ! Z-space file on a latitude-longitude grid. + +! === module MOM_initialize_layers_from_Z === +TEMP_SALT_Z_INIT_FILE = "" ! default = "temp_salt_z.nc" + ! The name of the z-space input file used to initialize + ! temperatures (T) and salinities (S). If T and S are not + ! in the same file, TEMP_Z_INIT_FILE and SALT_Z_INIT_FILE + ! must be set. +TEMP_Z_INIT_FILE = "woa18_decav_t00_01.nc" ! default = "" + ! The name of the z-space input file used to initialize + ! temperatures, only. +SALT_Z_INIT_FILE = "woa18_decav_s00_01.nc" ! default = "" + ! The name of the z-space input file used to initialize + ! temperatures, only. +Z_INIT_FILE_PTEMP_VAR = "t_an" ! default = "ptemp" + ! The name of the potential temperature variable in + ! TEMP_Z_INIT_FILE. +Z_INIT_FILE_SALT_VAR = "s_an" ! default = "salt" + ! The name of the salinity variable in + ! SALT_Z_INIT_FILE. +Z_INIT_ALE_REMAPPING = True ! [Boolean] default = False + ! If True, then remap straight to model coordinate from file. + +! === module MOM_diag_mediator === + +! === module MOM_MEKE === +USE_MEKE = True ! [Boolean] default = False + ! If true, turns on the MEKE scheme which calculates a sub-grid mesoscale eddy + ! kinetic energy budget. + +! === module MOM_lateral_mixing_coeffs === +USE_VARIABLE_MIXING = True ! [Boolean] default = False + ! If true, the variable mixing code will be called. This allows diagnostics to + ! be created even if the scheme is not used. If KHTR_SLOPE_CFF>0 or + ! KhTh_Slope_Cff>0, this is set to true regardless of what is in the parameter + ! file. +! === module MOM_set_visc === +CHANNEL_DRAG = True ! [Boolean] default = False + ! If true, the bottom drag is exerted directly on each layer proportional to the + ! fraction of the bottom it overlies. +HBBL = 10.0 ! [m] + ! The thickness of a bottom boundary layer with a viscosity of KVBBL if + ! BOTTOMDRAGLAW is not defined, or the thickness over which near-bottom + ! velocities are averaged for the drag law if BOTTOMDRAGLAW is defined but + ! LINEAR_DRAG is not. +KV = 1.0E-04 ! [m2 s-1] + ! The background kinematic viscosity in the interior. The molecular value, ~1e-6 + ! m2 s-1, may be used. + +! === module MOM_continuity === + +! === module MOM_continuity_PPM === + +! === module MOM_CoriolisAdv === +CORIOLIS_SCHEME = "SADOURNY75_ENSTRO" ! default = "SADOURNY75_ENERGY" + ! CORIOLIS_SCHEME selects the discretization for the Coriolis terms. Valid + ! values are: + ! SADOURNY75_ENERGY - Sadourny, 1975; energy cons. + ! ARAKAWA_HSU90 - Arakawa & Hsu, 1990 + ! SADOURNY75_ENSTRO - Sadourny, 1975; enstrophy cons. + ! ARAKAWA_LAMB81 - Arakawa & Lamb, 1981; En. + Enst. + ! ARAKAWA_LAMB_BLEND - A blend of Arakawa & Lamb with + ! Arakawa & Hsu and Sadourny energy +BOUND_CORIOLIS = True ! [Boolean] default = False + ! If true, the Coriolis terms at u-points are bounded by the four estimates of + ! (f+rv)v from the four neighboring v-points, and similarly at v-points. This + ! option would have no effect on the SADOURNY Coriolis scheme if it were + ! possible to use centered difference thickness fluxes. + +! === module MOM_PressureForce === + +! === module MOM_PressureForce_AFV === +MASS_WEIGHT_IN_PRESSURE_GRADIENT = True ! [Boolean] default = False + ! If true, use mass weighting when interpolating T/S for integrals near the + ! bathymetry in AFV pressure gradient calculations. + +! === module MOM_hor_visc === +LAPLACIAN = True ! [Boolean] default = False + ! If true, use a Laplacian horizontal viscosity. +KH_VEL_SCALE = 0.01 ! [m s-1] default = 0.0 + ! The velocity scale which is multiplied by the grid spacing to calculate the + ! Laplacian viscosity. The final viscosity is the largest of this scaled + ! viscosity, the Smagorinsky and Leith viscosities, and KH. +KH_SIN_LAT = 2000.0 ! [m2 s-1] default = 0.0 + ! The amplitude of a latitudinally-dependent background viscosity of the form + ! KH_SIN_LAT*(SIN(LAT)**KH_PWR_OF_SINE). +SMAGORINSKY_KH = True ! [Boolean] default = False + ! If true, use a Smagorinsky nonlinear eddy viscosity. +SMAG_LAP_CONST = 0.15 ! [nondim] default = 0.0 + ! The nondimensional Laplacian Smagorinsky constant, often 0.15. +AH_VEL_SCALE = 0.01 ! [m s-1] default = 0.0 + ! The velocity scale which is multiplied by the cube of the grid spacing to + ! calculate the biharmonic viscosity. The final viscosity is the largest of this + ! scaled viscosity, the Smagorinsky and Leith viscosities, and AH. +SMAGORINSKY_AH = True ! [Boolean] default = False + ! If true, use a biharmonic Smagorinsky nonlinear eddy viscosity. +SMAG_BI_CONST = 0.06 ! [nondim] default = 0.0 + ! The nondimensional biharmonic Smagorinsky constant, typically 0.015 - 0.06. +USE_LAND_MASK_FOR_HVISC = True ! [Boolean] default = False + ! If true, use Use the land mask for the computation of thicknesses at velocity + ! locations. This eliminates the dependence on arbitrary values over land or + ! outside of the domain. + +! === module MOM_vert_friction === +HMIX_FIXED = 0.5 ! [m] + ! The prescribed depth over which the near-surface viscosity and diffusivity are + ! elevated when the bulk mixed layer is not used. +MAXVEL = 6.0 ! [m s-1] default = 3.0E+08 + ! The maximum velocity allowed before the velocity components are truncated. + +! === module MOM_barotropic === +BOUND_BT_CORRECTION = True ! [Boolean] default = False + ! If true, the corrective pseudo mass-fluxes into the barotropic solver are + ! limited to values that require less than maxCFL_BT_cont to be accommodated. +BT_PROJECT_VELOCITY = True ! [Boolean] default = False + ! If true, step the barotropic velocity first and project out the velocity + ! tendency by 1+BEBT when calculating the transport. The default (false) is to + ! use a predictor continuity step to find the pressure field, and then to do a + ! corrector continuity step using a weighted average of the old and new + ! velocities, with weights of (1-BEBT) and BEBT. +DYNAMIC_SURFACE_PRESSURE = False ! [Boolean] default = False + ! If true, add a dynamic pressure due to a viscous ice shelf, for instance. +BEBT = 0.2 ! [nondim] default = 0.1 + ! BEBT determines whether the barotropic time stepping uses the forward-backward + ! time-stepping scheme or a backward Euler scheme. BEBT is valid in the range + ! from 0 (for a forward-backward treatment of nonrotating gravity waves) to 1 + ! (for a backward Euler treatment). In practice, BEBT must be greater than about + ! 0.05. +DTBT = -0.9 ! [s or nondim] default = -0.98 + ! The barotropic time step, in s. DTBT is only used with the split explicit time + ! stepping. To set the time step automatically based the maximum stable value + ! use 0, or a negative value gives the fraction of the stable value. Setting + ! DTBT to 0 is the same as setting it to -0.98. The value of DTBT that will + ! actually be used is an integer fraction of DT, rounding down. + +! === module MOM_mixed_layer_restrat === +MIXEDLAYER_RESTRAT = False ! [Boolean] default = False + ! If true, a density-gradient dependent re-stratifying flow is imposed in the + ! mixed layer. Can be used in ALE mode without restriction but in layer mode can + ! only be used if BULKMIXEDLAYER is true. +FOX_KEMPER_ML_RESTRAT_COEF = 60.0 ! [nondim] default = 0.0 + ! A nondimensional coefficient that is proportional to the ratio of the + ! deformation radius to the dominant lengthscale of the submesoscale mixed layer + ! instabilities, times the minimum of the ratio of the mesoscale eddy kinetic + ! energy to the large-scale geostrophic kinetic energy or 1 plus the square of + ! the grid spacing over the deformation radius, as detailed by Fox-Kemper et al. + ! (2010) +MLE_FRONT_LENGTH = 200.0 ! [m] default = 0.0 + ! If non-zero, is the frontal-length scale used to calculate the upscaling of + ! buoyancy gradients that is otherwise represented by the parameter + ! FOX_KEMPER_ML_RESTRAT_COEF. If MLE_FRONT_LENGTH is non-zero, it is recommended + ! to set FOX_KEMPER_ML_RESTRAT_COEF=1.0. +MLE_USE_PBL_MLD = True ! [Boolean] default = False + ! If true, the MLE parameterization will use the mixed-layer depth provided by + ! the active PBL parameterization. If false, MLE will estimate a MLD based on a + ! density difference with the surface using the parameter MLE_DENSITY_DIFF. +MLE_MLD_DECAY_TIME = 2.592E+06 ! [s] default = 0.0 + ! The time-scale for a running-mean filter applied to the mixed-layer depth used + ! in the MLE restratification parameterization. When the MLD deepens below the + ! current running-mean the running-mean is instantaneously set to the current + ! MLD. + +! === module MOM_diabatic_driver === +! The following parameters are used for diabatic processes. +ENERGETICS_SFC_PBL = True ! [Boolean] default = False + ! If true, use an implied energetics planetary boundary layer scheme to + ! determine the diffusivity and viscosity in the surface boundary layer. +EPBL_IS_ADDITIVE = False ! [Boolean] default = True + ! If true, the diffusivity from ePBL is added to all other diffusivities. + ! Otherwise, the larger of kappa-shear and ePBL diffusivities are used. + +! === module MOM_CVMix_KPP === +! This is the MOM wrapper to CVMix:KPP +! See http://cvmix.github.io/ + +! === module MOM_tidal_mixing === +! Vertical Tidal Mixing Parameterization + +! === module MOM_CVMix_conv === +! Parameterization of enhanced mixing due to convection via CVMix + +! === module MOM_set_diffusivity === + +! === module MOM_bkgnd_mixing === +! Adding static vertical background mixing coefficients +KD = 1.5E-05 ! [m2 s-1] default = 0.0 + ! The background diapycnal diffusivity of density in the interior. Zero or the + ! molecular value, ~1e-7 m2 s-1, may be used. +KD_MIN = 2.0E-06 ! [m2 s-1] default = 2.0E-07 + ! The minimum diapycnal diffusivity. +HENYEY_IGW_BACKGROUND = True ! [Boolean] default = False + ! If true, use a latitude-dependent scaling for the near surface background + ! diffusivity, as described in Harrison & Hallberg, JPO 2008. + +! === module MOM_kappa_shear === +! Parameterization of shear-driven turbulence following Jackson, Hallberg and Legg, JPO 2008 +USE_JACKSON_PARAM = True ! [Boolean] default = False + ! If true, use the Jackson-Hallberg-Legg (JPO 2008) shear mixing + ! parameterization. +MAX_RINO_IT = 25 ! [nondim] default = 50 + ! The maximum number of iterations that may be used to estimate the Richardson + ! number driven mixing. + +! === module MOM_CVMix_shear === +! Parameterization of shear-driven turbulence via CVMix (various options) + +! === module MOM_CVMix_ddiff === +! Parameterization of mixing due to double diffusion processes via CVMix + +! === module MOM_diabatic_aux === +! The following parameters are used for auxiliary diabatic processes. + +! === module MOM_energetic_PBL === +EPBL_USTAR_MIN = 1.45842E-18 ! [m s-1] + ! The (tiny) minimum friction velocity used within the ePBL code, derived from + ! OMEGA and ANGSTROM.. +USE_LA_LI2016 = True ! [nondim] default = False + ! A logical to use the Li et al. 2016 (submitted) formula to determine the + ! Langmuir number. +USE_WAVES = False ! [Boolean] default = False + ! If true, enables surface wave modules. + +! === module MOM_regularize_layers === + +! === module MOM_opacity === + +! === module MOM_tracer_advect === +TRACER_ADVECTION_SCHEME = "PPM:H3" ! default = "PLM" + ! The horizontal transport scheme for tracers: + ! PLM - Piecewise Linear Method + ! PPM:H3 - Piecewise Parabolic Method (Huyhn 3rd order) + ! PPM - Piecewise Parabolic Method (Colella-Woodward) + +! === module MOM_tracer_hor_diff === +KHTR = 50.0 ! [m2 s-1] default = 0.0 + ! The background along-isopycnal tracer diffusivity. +CHECK_DIFFUSIVE_CFL = True ! [Boolean] default = False + ! If true, use enough iterations the diffusion to ensure that the diffusive + ! equivalent of the CFL limit is not violated. If false, always use the greater + ! of 1 or MAX_TR_DIFFUSION_CFL iteration. +MAX_TR_DIFFUSION_CFL = 2.0 ! [nondim] default = -1.0 + ! If positive, locally limit the along-isopycnal tracer diffusivity to keep the + ! diffusive CFL locally at or below this value. The number of diffusive + ! iterations is often this value or the next greater integer. + +! === module MOM_neutral_diffusion === +! This module implements neutral diffusion of tracers +USE_NEUTRAL_DIFFUSION = True ! [Boolean] default = False + ! If true, enables the neutral diffusion module. + +! === module MOM_sum_output === +MAXTRUNC = 1000 ! [truncations save_interval-1] default = 0 + ! The run will be stopped, and the day set to a very large value if the velocity + ! is truncated more than MAXTRUNC times between energy saves. Set MAXTRUNC to 0 + ! to stop if there is any truncation of velocities. + +! === module ocean_model_init === +ODA_INCUPD = @[MOM_IAU] ! [Boolean] default = False + ! If true, oda incremental updates will be applied + ! everywhere in the domain. +ODA_INCUPD_FILE = "inc.nc" ! The name of the file with the T,S,h increments. + +ODA_TEMPINC_VAR = "Temp" ! default = "ptemp_inc" + ! The name of the potential temperature inc. variable in + ! ODA_INCUPD_FILE. +ODA_SALTINC_VAR = "Salt" ! default = "sal_inc" + ! The name of the salinity inc. variable in + ! ODA_INCUPD_FILE. +ODA_THK_VAR = "h" ! default = "h" + ! The name of the int. depth inc. variable in + ! ODA_INCUPD_FILE. +ODA_INCUPD_UV = false ! +!ODA_UINC_VAR = "u" ! default = "u_inc" + ! The name of the zonal vel. inc. variable in + ! ODA_INCUPD_UV_FILE. +!ODA_VINC_VAR = "v" ! default = "v_inc" + ! The name of the meridional vel. inc. variable in + ! ODA_INCUPD_UV_FILE. +ODA_INCUPD_NHOURS = @[MOM_IAU_HRS] ! default=3.0 + +! === module MOM_surface_forcing === +OCEAN_SURFACE_STAGGER = "A" ! default = "C" + ! A case-insensitive character string to indicate the + ! staggering of the surface velocity field that is + ! returned to the coupler. Valid values include + ! 'A', 'B', or 'C'. + +MAX_P_SURF = 0.0 ! [Pa] default = -1.0 + ! The maximum surface pressure that can be exerted by the atmosphere and + ! floating sea-ice or ice shelves. This is needed because the FMS coupling + ! structure does not limit the water that can be frozen out of the ocean and the + ! ice-ocean heat fluxes are treated explicitly. No limit is applied if a + ! negative value is used. +WIND_STAGGER = "A" ! default = "C" + ! A case-insensitive character string to indicate the + ! staggering of the input wind stress field. Valid + ! values are 'A', 'B', or 'C'. +! === module MOM_restart === + +! === module MOM_file_parser === diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index a31fac1ff2..e07a04a179 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -776,7 +776,7 @@ MOM6_postdet() { OCNRES=${OCNRES:-"025"} # TODO: remove from here and lift higher # Copy MOM6 ICs - if [[ "${MODE}" == 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only + if [[ "${MODE}" = 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res.nc" "${DATA}/INPUT/MOM.res.nc" case $OCNRES in "025") @@ -806,7 +806,7 @@ MOM6_postdet() { # Copy mediator restart file to RUNDIR # TODO: mediator should have its own CMEPS_postdet() function local mediator_file="${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/med/${PDY}.${cyc}0000.ufs.cpld.cpl.r.nc" if [[ -f "${mediator_file}" ]]; then - $NCP "${mediator_file}" "${DATA}/ufs.cpld.cpl.r.nc" + $NLN "${mediator_file}" "${DATA}/ufs.cpld.cpl.r.nc" rm -f "${DATA}/rpointer.cpl" touch "${DATA}/rpointer.cpl" echo "ufs.cpld.cpl.r.nc" >> "${DATA}/rpointer.cpl" @@ -943,8 +943,8 @@ CICE_postdet() { npt=$((FHMAX*$stepsperhr)) # Need this in order for dump_last to work histfreq_n=${histfreq_n:-6} - if [[ "${MODE}" == "cycled" ]]; then # TODO: this needs to be improved to include CDUMP = GDAS | GFS - if [[ "${CDUMP}"= "gdas" ]]; then # TODO: improve and remove this default of dumping hourly restarts for cycled system + if [[ "${MODE}" = "cycled" ]]; then # TODO: this needs to be improved to include CDUMP = GDAS | GFS + if [[ "${CDUMP}" = "gdas" ]]; then # TODO: improve and remove this default of dumping hourly restarts for cycled system dumpfreq_n=1 elif [[ "${CDUMP}" = "gfs" ]]; then dumpfreq_n=${dumpfreq_n:-24} @@ -983,15 +983,15 @@ CICE_postdet() { export MESH_OCN_ICE=${MESH_OCN_ICE:-"mesh.mx${ICERES}.nc"} # Copy/link CICE IC to DATA - if [[ "${MODE}" == 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only - $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${cyc}/ice/RESTART/${PDY}.${cyc}0000.cice_model.res.nc" "${DATA}/cice_model.res.nc" + if [[ "${MODE}" = 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ice/RESTART/${PDY}.${cyc}0000.cice_model.res.nc" "${DATA}/cice_model.res.nc" else $NCP -p $ICSDIR/$CDATE/ice/cice_model_${ICERESdec}.res_$CDATE.nc $DATA/cice_model.res.nc fi # TODO: add a check for the restarts to exist, if not, exit eloquently rm -f "${DATA}/ice.restart_file" touch "${DATA}/ice.restart_file" - echo "${DATA}/cice_model.res.nc" >> "${DATA}/ice.restart_file" + echo "${DATA}/cice_model.res.nc" >> "${DATA}/ice.restart_file" echo "Link CICE fixed files" $NLN -sf $FIXcice/$ICERES/${ice_grid_file} $DATA/ diff --git a/ush/parsing_namelists_CICE.sh b/ush/parsing_namelists_CICE.sh index 64a711bffc..9584d2cdfa 100755 --- a/ush/parsing_namelists_CICE.sh +++ b/ush/parsing_namelists_CICE.sh @@ -24,7 +24,7 @@ cat > ice_in <> input.nml < $DATA/INPUT/MOM_input + -e "s/@\[MOM_IAU_HRS\]/$MOM_IAU_HRS/g" \ + -e "s/@\[MOM_IAU\]/$MOM_IAU/g" $DATA/INPUT/MOM_input_template_$OCNRES > $DATA/INPUT/MOM_input rm $DATA/INPUT/MOM_input_template_$OCNRES #data table for runoff: From e4475b307b0892ba3caa434811aec3a06b54a753 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Mon, 23 Jan 2023 22:09:06 -0500 Subject: [PATCH 08/27] First C48 5deg ocean run success. --- jobs/JGLOBAL_FORECAST | 1 + parm/config/config.ice | 2 + scripts/exglobal_forecast.sh | 54 +++++-------- ush/forecast_postdet.sh | 142 ++++++++++++++++------------------ ush/parsing_namelists_CICE.sh | 11 ++- 5 files changed, 101 insertions(+), 109 deletions(-) diff --git a/jobs/JGLOBAL_FORECAST b/jobs/JGLOBAL_FORECAST index 9027512761..dc9759040b 100755 --- a/jobs/JGLOBAL_FORECAST +++ b/jobs/JGLOBAL_FORECAST @@ -1,6 +1,7 @@ #! /usr/bin/env bash source "${HOMEgfs}/ush/preamble.sh" +export DATA=${DATAROOT}/debug_fcst # TODO: (RM) remove before PR source "${HOMEgfs}/ush/jjob_header.sh" -e "fcst" -c "base fcst" ############################################## diff --git a/parm/config/config.ice b/parm/config/config.ice index 19f493fda2..ff0bc7c18c 100644 --- a/parm/config/config.ice +++ b/parm/config/config.ice @@ -8,6 +8,8 @@ case "${ICERES}" in "500") # TODO: From GV, check w/ DW export NX_GLB="36" export NY_GLB="70" + export block_size_x="18" # TODO: These are calculated in parsing_namelists_CICE.sh, but the model does not like those values + export block_size_y="35" ;; *) echo "FATAL ERROR: Unsupported ICERES = ${ICERES}, ABORT!" diff --git a/scripts/exglobal_forecast.sh b/scripts/exglobal_forecast.sh index 3f2ad87caf..90e66ca4a3 100755 --- a/scripts/exglobal_forecast.sh +++ b/scripts/exglobal_forecast.sh @@ -123,8 +123,7 @@ common_predet echo $RUN case $RUN in 'data') DATM_predet;; - 'gfs') FV3_GFS_predet;; - 'gdas') FV3_GFS_predet;; + 'gfs' | 'gdas') FV3_GFS_predet;; 'gefs') FV3_GEFS_predet;; esac [[ $cplflx = .true. ]] && MOM6_predet @@ -132,8 +131,7 @@ esac [[ $cplice = .true. ]] && CICE_predet case $RUN in - 'gfs') FV3_GFS_det;; - 'gdas') FV3_GFS_det;; + 'gfs' | 'gdas') FV3_GFS_det;; 'gefs') FV3_GEFS_det;; esac #no run type determination for data atmosphere [[ $cplflx = .true. ]] && MOM6_det @@ -146,8 +144,7 @@ echo "MAIN: Post-determination set up of run type" echo $RUN case $RUN in 'data') DATM_postdet;; - 'gfs') FV3_GFS_postdet;; - 'gdas') FV3_GFS_postdet;; + 'gfs' | 'gdas') FV3_GFS_postdet;; 'gefs') FV3_GEFS_postdet;; esac #no post determination set up for data atmosphere [[ $cplflx = .true. ]] && MOM6_postdet @@ -159,10 +156,9 @@ echo "MAIN: Post-determination set up of run type finished" echo "MAIN: Writing name lists and model configuration" case $RUN in 'data') DATM_nml;; - 'gfs') FV3_GFS_nml;; - 'gdas') FV3_GFS_nml;; + 'gfs' | 'gdas') FV3_GFS_nml;; 'gefs') FV3_GEFS_nml;; -esac #no namelist for data atmosphere +esac [[ $cplflx = .true. ]] && MOM6_nml [[ $cplwav = .true. ]] && WW3_nml [[ $cplice = .true. ]] && CICE_nml @@ -188,31 +184,23 @@ if [ $esmf_profile ]; then export ESMF_RUNTIME_PROFILE_OUTPUT=SUMMARY fi -if [ $machine != 'sandbox' ]; then - $NCP $FCSTEXECDIR/$FCSTEXEC $DATA/. - export OMP_NUM_THREADS=$NTHREADS_FV3 - $APRUN_FV3 $DATA/$FCSTEXEC 1>&1 2>&2 - export ERR=$? - export err=$ERR - $ERRSCRIPT || exit $err -else - echo "MAIN: mpirun launch here" -fi +$NCP $FCSTEXECDIR/$FCSTEXEC $DATA/. +export OMP_NUM_THREADS=$NTHREADS_FV3 +$APRUN_FV3 $DATA/$FCSTEXEC 1>&1 2>&2 +export ERR=$? +export err=$ERR +$ERRSCRIPT || exit $err -if [ $machine != 'sandbox' ]; then - case $RUN in - 'data') data_out_Data_ATM;; - 'gfs') data_out_GFS;; - 'gdas') data_out_GFS;; - 'gefs') data_out_GEFS;; - esac - [[ $cplflx = .true. ]] && MOM6_out - [[ $cplwav = .true. ]] && WW3_out - [[ $cplice = .true. ]] && CICE_out - [[ $esmf_profile = .true. ]] && CPL_out -else - echo "MAIN: Running on sandbox mode, no output linking" -fi +case $RUN in + 'data') data_out_Data_ATM;; + 'gfs') data_out_GFS;; + 'gdas') data_out_GFS;; + 'gefs') data_out_GEFS;; +esac +[[ $cplflx = .true. ]] && MOM6_out +[[ $cplwav = .true. ]] && WW3_out +[[ $cplice = .true. ]] && CICE_out +[[ $esmf_profile = .true. ]] && CPL_out echo "MAIN: Output copied to COMROT" #------------------------------------------------------------------ diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index e07a04a179..2300907b10 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -45,23 +45,22 @@ FV3_GFS_postdet(){ if [ $RERUN = "NO" ]; then #............................. - # Link all (except sfc_data) restart files from $gmemdir + # Link all restart files from $gmemdir for file in $(ls $gmemdir/RESTART/${sPDY}.${scyc}0000.*.nc); do file2=$(echo $(basename $file)) file2=$(echo $file2 | cut -d. -f3-) # remove the date from file fsuf=$(echo $file2 | cut -d. -f1) - if [ $fsuf != "sfc_data" ]; then - $NLN $file $DATA/INPUT/$file2 - fi + $NLN $file $DATA/INPUT/$file2 done - # Link sfcanl_data restart files from $memdir - for file in $(ls $memdir/RESTART/${sPDY}.${scyc}0000.*.nc); do - file2=$(echo $(basename $file)) - file2=$(echo $file2 | cut -d. -f3-) # remove the date from file - fsufanl=$(echo $file2 | cut -d. -f1) - if [ $fsufanl = "sfcanl_data" ]; then + # Replace sfc_data with sfcanl_data restart files from $memdir (if found) + for file in $(ls $memdir/RESTART/${sPDY}.${scyc}0000.sfcanl_data.tile?.nc); do + if [[ -f $file ]]; then + file2=$(echo $(basename $file)) + file2=$(echo $file2 | cut -d. -f3-) # remove the date from file + fsufanl=$(echo $file2 | cut -d. -f1) file2=$(echo $file2 | sed -e "s/sfcanl_data/sfc_data/g") + rm -f $DATA/INPUT/$file2 $NLN $file $DATA/INPUT/$file2 fi done @@ -144,14 +143,10 @@ EOF fi - if [ $machine = 'sandbox' ]; then - echo SUB ${FUNCNAME[0]}: Checking initial condition, overriden in sandbox mode! - else - nfiles=$(ls -1 $DATA/INPUT/* | wc -l) - if [ $nfiles -le 0 ]; then - echo SUB ${FUNCNAME[0]}: Initial conditions must exist in $DATA/INPUT, ABORT! - exit 1 - fi + nfiles=$(ls -1 $DATA/INPUT/* | wc -l) + if [ $nfiles -le 0 ]; then + echo SUB ${FUNCNAME[0]}: Initial conditions must exist in $DATA/INPUT, ABORT! + exit 1 fi # If doing IAU, change forecast hours @@ -546,10 +541,6 @@ EOF FV3_GFS_nml(){ # namelist output for a certain component echo SUB ${FUNCNAME[0]}: Creating name lists and model configure file for FV3 - if [ $machine = 'sandbox' ]; then - cd $SCRIPTDIR - echo "MAIN: !!!Sandbox mode, writing to current directory!!!" - fi # Call child scripts in current script directory source $SCRIPTDIR/parsing_namelists_FV3.sh FV3_namelists @@ -869,65 +860,68 @@ MOM6_postdet() { last_fhr=$fhr done - $NLN ${COMOUTocean}/MOM_input $DATA/INPUT/MOM_input - - echo "SUB ${FUNCNAME[0]}: MOM6 input data linked/copied" - -} - -MOM6_nml() { - echo "SUB ${FUNCNAME[0]}: Creating name list for MOM6" - source $SCRIPTDIR/parsing_namelists_MOM6.sh - MOM6_namelists -} - -MOM6_out() { - echo "SUB ${FUNCNAME[0]}: Copying output data for MOM6" # Link ocean restarts from DATA to COM - local ocean_com_dir="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ocean" - mkdir -p "${ocean_com_dir}/RESTART" + mkdir -p "${COMOUTocean}/RESTART" # end point restart does not have a timestamp, calculate local rdate=$($NDATE $FHMAX $CDATE) - $NLN "${DATA}/MOM6_RESTART/MOM.res.nc" "${ocean_com_dir}/RESTART/${rdate:0:8}.${rdate:8:2}0000.res.nc" # Greater than 1/2 degree have a single MOM restart - # Less than 1/2 degree have 3 additional restarts + $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.res.nc" "${DATA}/MOM6_RESTART/MOM.res.nc" + # 1/4 degree have 3 additional restarts case ${OCNRES} in "025") - $NLN "${DATA}/MOM6_RESTART/MOM.res_1.nc" "${ocean_com_dir}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_1.nc" - $NLN "${DATA}/MOM6_RESTART/MOM.res_2.nc" "${ocean_com_dir}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_2.nc" - $NLN "${DATA}/MOM6_RESTART/MOM.res_3.nc" "${ocean_com_dir}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_3.nc" + $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_1.nc" "${DATA}/MOM6_RESTART/MOM.res_1.nc" + $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_2.nc" "${DATA}/MOM6_RESTART/MOM.res_2.nc" + $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_3.nc" "${DATA}/MOM6_RESTART/MOM.res_3.nc" ;; *) ;; esac - # Loop over restart_interval_nems and link restarts from DATA to COM - local idate=$($NDATE $restart_interval_nems $CDATE) + + # Loop over restart_interval frequency and link restarts from DATA to COM + local res_int=$(echo $restart_interval | cut -d' ' -f1) # If this is a list, get the frequency. # This is bound to break w/ IAU + local idate=$($NDATE $res_int $CDATE) while [[ $idate -lt $rdate ]]; do local idatestr=$(date +%Y-%m-%d-%H -d "${idate:0:8} ${idate:8:2}") - $NLN "${DATA}/MOM6_RESTART/MOM.res.${idatestr}-00-00.nc" "${ocean_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000.res.nc" + $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.res.nc" "${DATA}/MOM6_RESTART/MOM.res.${idatestr}-00-00.nc" case ${OCNRES} in "025") - $NLN "${DATA}/MOM6_RESTART/MOM.res_1.${idatestr}-00-00.nc" "${ocean_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_1.nc" - $NLN "${DATA}/MOM6_RESTART/MOM.res_2.${idatestr}-00-00.nc" "${ocean_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_2.nc" - $NLN "${DATA}/MOM6_RESTART/MOM.res_3.${idatestr}-00-00.nc" "${ocean_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_3.nc" - ;; - *) + $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_1.nc" "${DATA}/MOM6_RESTART/MOM.res_1.${idatestr}-00-00.nc" + $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_2.nc" "${DATA}/MOM6_RESTART/MOM.res_2.${idatestr}-00-00.nc" + $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_3.nc" "${DATA}/MOM6_RESTART/MOM.res_3.${idatestr}-00-00.nc" ;; esac - local idate=$($NDATE $restart_interval_nems $idate) + local idate=$($NDATE $res_int $idate) done - # TODO: mediator should have its own CMEPS_out() function + # TODO: mediator should have its own CMEPS_postdet() function # Link mediator restarts from DATA to COM - local med_com_dir="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/med" - mkdir -p "${med_com_dir}/RESTART" - local idate=$($NDATE $restart_interval_nems $CDATE) + local COMOUTmed="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/med" + mkdir -p "${COMOUTmed}/RESTART" + local idate=$($NDATE $res_int $CDATE) while [[ $idate -le $rdate ]]; do - local seconds=$(to_seconds ${idatestr:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds + local seconds=$(to_seconds ${idate:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" - $NLN "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}" "${med_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000."ufs.cpld.cpl.r.nc + $NLN "${COMOUTmed}/RESTART/${idate:0:8}.${idate:8:2}0000.ufs.cpld.cpl.r.nc" "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" + local idate=$($NDATE $res_int $idate) done + + echo "SUB ${FUNCNAME[0]}: MOM6 input data linked/copied" + +} + +MOM6_nml() { + echo "SUB ${FUNCNAME[0]}: Creating name list for MOM6" + source $SCRIPTDIR/parsing_namelists_MOM6.sh + MOM6_namelists +} + +MOM6_out() { + echo "SUB ${FUNCNAME[0]}: Copying output data for MOM6" + + # Copy MOM_input from DATA to COMOUToucean after the forecast is run (and successfull) + $NCP ${DATA}/INPUT/MOM_input ${COMOUTocean}/MOM_input + } CICE_postdet() { @@ -998,12 +992,10 @@ CICE_postdet() { $NLN -sf $FIXcice/$ICERES/${ice_kmt_file} $DATA/ $NLN -sf $FIXcice/$ICERES/$MESH_OCN_ICE $DATA/ - # TODO: shouldn't this be in CICE_out()? - # Link output files + # Link CICE output files export ENSMEM=${ENSMEM:-01} export IDATE=$CDATE [[ ! -d $COMOUTice ]] && mkdir -p $COMOUTice - $NLN $COMOUTice/ice_in $DATA/ice_in fhrlst=$OUTPUT_FH for fhr in $fhrlst; do @@ -1025,6 +1017,19 @@ CICE_postdet() { fi last_fhr=$fhr done + + # Link CICE restarts to COMOUTice/RESTART + # Loop over restart_interval and link restarts from DATA to COM + mkdir -p ${COMOUTice}/RESTART + local res_int=$(echo ${restart_interval} | cut -d' ' -f1) # If this is a list, get the frequency. # This is bound to break w/ IAU + local rdate=$(${NDATE} ${FHMAX} ${CDATE}) + local idate=$(${NDATE} ${res_int} ${CDATE}) + while [[ $idate -le $rdate ]]; do + local seconds=$(to_seconds ${idate:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds + local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" + $NLN "${COMOUTice}/RESTART/${idate:0:8}.${idate:8:2}0000.cice_model.res.nc" "${DATA}/RESTART/iced.${idatestr}.nc" + local idate=$(${NDATE} ${res_int} ${idate}) + done } CICE_nml() { @@ -1035,20 +1040,9 @@ CICE_nml() { CICE_out() { echo "SUB ${FUNCNAME[0]}: Copying output data for CICE" - # TODO: Why is this empty? Is there no cice output being copied back to COM? There is output linked to COMOUTice in CICE_postdet() - # And people as why this needs refactoring. - - local ice_com_dir="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ice" - mkdir -p "${ice_com_dir}/RESTART" - # Link ice restarts to COMOUTice - # Loop over restart_interval_nems and link restarts from DATA to COM - local idate=$($NDATE $restart_interval_nems $CDATE) - while [[ $idate -le $rdate ]]; do - local seconds=$(to_seconds ${idatestr:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds - local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" - $NLN "${DATA}/RESTART/iced.${idatestr}" "${ice_com_dir}/RESTART/${idate:0:8}.${idate:8:2}0000.cice_model.res.nc" - done + # Copy ice_in namelist from DATA to COMOUTice after the forecast is run (and successfull) + $NCP ${DATA}/ice_in $COMOUTice/ice_in } GOCART_rc() { diff --git a/ush/parsing_namelists_CICE.sh b/ush/parsing_namelists_CICE.sh index 9584d2cdfa..a08fb06df9 100755 --- a/ush/parsing_namelists_CICE.sh +++ b/ush/parsing_namelists_CICE.sh @@ -10,6 +10,13 @@ else cmeps_run_type='initial' fi +# C48, 5degree Ocean does not work with this formula +# Supply from config.ice +# TODO: figure out why +local _block_size_x=$(( 2 * ( $NX_GLB / $ICEPETS ) )) +local _block_size_y=$(( $NY_GLB / 2 )) +block_size_x=${block_size_x:-_block_size_x} +block_size_y=${block_size_y:-_block_size_y} cat > ice_in < ice_in < Date: Tue, 24 Jan 2023 21:39:40 -0500 Subject: [PATCH 09/27] C48 runs --- jobs/JGLOBAL_FORECAST | 2 +- ush/forecast_postdet.sh | 54 ++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/jobs/JGLOBAL_FORECAST b/jobs/JGLOBAL_FORECAST index dc9759040b..a7d50c1191 100755 --- a/jobs/JGLOBAL_FORECAST +++ b/jobs/JGLOBAL_FORECAST @@ -1,7 +1,7 @@ #! /usr/bin/env bash source "${HOMEgfs}/ush/preamble.sh" -export DATA=${DATAROOT}/debug_fcst # TODO: (RM) remove before PR +#export DATA=${DATAROOT}/debug_fcst # TODO: (RM) remove before PR source "${HOMEgfs}/ush/jjob_header.sh" -e "fcst" -c "base fcst" ############################################## diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 2300907b10..876c074871 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -865,9 +865,9 @@ MOM6_postdet() { mkdir -p "${COMOUTocean}/RESTART" # end point restart does not have a timestamp, calculate local rdate=$($NDATE $FHMAX $CDATE) - # Greater than 1/2 degree have a single MOM restart - $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.res.nc" "${DATA}/MOM6_RESTART/MOM.res.nc" - # 1/4 degree have 3 additional restarts + # Coarser than 1/2 degree has a single MOM restart + $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res.nc" "${DATA}/MOM6_RESTART/MOM.res.nc" + # 1/4 degree resolution has 3 additional restarts case ${OCNRES} in "025") $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_1.nc" "${DATA}/MOM6_RESTART/MOM.res_1.nc" @@ -896,15 +896,18 @@ MOM6_postdet() { # TODO: mediator should have its own CMEPS_postdet() function # Link mediator restarts from DATA to COM - local COMOUTmed="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/med" - mkdir -p "${COMOUTmed}/RESTART" - local idate=$($NDATE $res_int $CDATE) - while [[ $idate -le $rdate ]]; do - local seconds=$(to_seconds ${idate:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds - local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" - $NLN "${COMOUTmed}/RESTART/${idate:0:8}.${idate:8:2}0000.ufs.cpld.cpl.r.nc" "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" - local idate=$($NDATE $res_int $idate) - done + # DANGER DANGER DANGER - Linking mediator restarts to COM causes the model to fail with a message like this below: + # Abort with message NetCDF: File exists && NC_NOCLOBBER in file pio-2.5.7/src/clib/pioc_support.c at line 2173 + # Instead of linking, copy the mediator files after the model finishes + #local COMOUTmed="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/med" + #mkdir -p "${COMOUTmed}/RESTART" + #local idate=$($NDATE $res_int $CDATE) + #while [[ $idate -le $rdate ]]; do + # local seconds=$(to_seconds ${idate:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds + # local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" + # $NLN "${COMOUTmed}/RESTART/${idate:0:8}.${idate:8:2}0000.ufs.cpld.cpl.r.nc" "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" + # local idate=$($NDATE $res_int $idate) + #done echo "SUB ${FUNCNAME[0]}: MOM6 input data linked/copied" @@ -922,6 +925,21 @@ MOM6_out() { # Copy MOM_input from DATA to COMOUToucean after the forecast is run (and successfull) $NCP ${DATA}/INPUT/MOM_input ${COMOUTocean}/MOM_input + # TODO: mediator should have its own CMEPS_out() function + # Copy mediator restarts from DATA to COM + # Linking mediator restarts to COM causes the model to fail with a message. + # See MOM6_postdet() function for error message + local COMOUTmed="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/med" + mkdir -p "${COMOUTmed}/RESTART" + local rdate=$($NDATE $FHMAX $CDATE) + local res_int=$(echo $restart_interval | cut -d' ' -f1) # If this is a list, get the frequency. # This is bound to break w/ IAU + local idate=$($NDATE $res_int $CDATE) + while [[ $idate -le $rdate ]]; do + local seconds=$(to_seconds ${idate:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds + local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" + $NCP "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" "${COMOUTmed}/RESTART/${idate:0:8}.${idate:8:2}0000.ufs.cpld.cpl.r.nc" + local idate=$($NDATE $res_int $idate) + done } CICE_postdet() { @@ -937,16 +955,8 @@ CICE_postdet() { npt=$((FHMAX*$stepsperhr)) # Need this in order for dump_last to work histfreq_n=${histfreq_n:-6} - if [[ "${MODE}" = "cycled" ]]; then # TODO: this needs to be improved to include CDUMP = GDAS | GFS - if [[ "${CDUMP}" = "gdas" ]]; then # TODO: improve and remove this default of dumping hourly restarts for cycled system - dumpfreq_n=1 - elif [[ "${CDUMP}" = "gfs" ]]; then - dumpfreq_n=${dumpfreq_n:-24} - fi - else - dumpfreq_n=${dumpfreq_n:-840} # default 35 days (840 hours) for forecast-only - fi - dumpfreq=${dumpfreq:-"h"} # "h","d","m" or "y" for restarts at intervals of "hours", "days", "months" or "years" + dumpfreq_n=${dumpfreq_n:-1000} # Set this to a really large value, as cice, mom6 and cmeps restart interval is controlled by nems.configure + dumpfreq=${dumpfreq:-"y"} # "h","d","m" or "y" for restarts at intervals of "hours", "days", "months" or "years" cice_hist_avg=${cice_hist_avg:-".true."} FRAZIL_FWSALT=${FRAZIL_FWSALT:-".true."} From 2c82642a694e716f1c3b0a8ca6765ce762434e54 Mon Sep 17 00:00:00 2001 From: Neil Barton <103681022+NeilBarton-NOAA@users.noreply.github.com> Date: Tue, 24 Jan 2023 21:40:27 -0500 Subject: [PATCH 10/27] simplify ice MPI layout and add cold_start dirs for ocean and ice (#1) --- parm/config/config.base.emc.dyn | 5 +--- parm/config/config.ice | 9 ++++--- parm/config/config.ocn | 12 ++++------ parm/config/config.resources | 6 ++++- ush/forecast_postdet.sh | 42 +++++++++++++++++++++------------ ush/nems_configure.sh | 10 ++++---- ush/parsing_namelists_CICE.sh | 38 +++++++++++++++++++---------- 7 files changed, 71 insertions(+), 51 deletions(-) diff --git a/parm/config/config.base.emc.dyn b/parm/config/config.base.emc.dyn index 62cdf1d2af..a3a71e3213 100755 --- a/parm/config/config.base.emc.dyn +++ b/parm/config/config.base.emc.dyn @@ -173,10 +173,7 @@ export LEVS=128 export CASE="@CASECTL@" export CASE_ENKF="@CASEENS@" case "$CASE" in - "C48") - export OCNRES=500 - export OCNTIM=3600 # TODO: add OCNTIM for other resolutions? - ;; + "C48") export OCNRES=500;; "C96") export OCNRES=100;; "C192") export OCNRES=050;; "C384") export OCNRES=025;; diff --git a/parm/config/config.ice b/parm/config/config.ice index ff0bc7c18c..10d34ec753 100644 --- a/parm/config/config.ice +++ b/parm/config/config.ice @@ -5,11 +5,10 @@ case "${ICERES}" in export NX_GLB="1440" export NY_GLB="1080" ;; - "500") # TODO: From GV, check w/ DW - export NX_GLB="36" - export NY_GLB="70" - export block_size_x="18" # TODO: These are calculated in parsing_namelists_CICE.sh, but the model does not like those values - export block_size_y="35" + "500") + export NX_GLB="72" + export NY_GLB="35" + export cice_processor_shape='slenderX1' ;; *) echo "FATAL ERROR: Unsupported ICERES = ${ICERES}, ABORT!" diff --git a/parm/config/config.ocn b/parm/config/config.ocn index 4d24c0d87f..d224dd3267 100644 --- a/parm/config/config.ocn +++ b/parm/config/config.ocn @@ -1,11 +1,7 @@ #! /usr/bin/env bash # OCNRES is currently being set in config.base -# case "$CASE" in -# "C48") export OCNRES=500;; -# "C96") export OCNRES=100;; -# "C192") export OCNRES=050;; -# "C384") export OCNRES=025;; -# "C768") export OCNRES=025;; -# *) export OCNRES=025;; -# esac + case "$CASE" in + "C48") export OCNTIM=3600;; + *) export OCNTIM=1800;; + esac diff --git a/parm/config/config.resources b/parm/config/config.resources index b71d1c9b0b..6e96b21a23 100755 --- a/parm/config/config.resources +++ b/parm/config/config.resources @@ -370,7 +370,11 @@ elif [ ${step} = "gldas" ]; then elif [ ${step} = "fcst" ]; then - export wtime_fcst="00:30:00" + if [ ${CASE} = "C48" ]; then + export wtime_fcst="00:30:00" + else + export wtime_fcst="00:40:00" + fi if [ ${CASE} = "C768" ]; then export wtime_fcst_gfs="06:00:00" elif [ ${CASE} = "C384" ]; then diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 876c074871..c827145ded 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -768,12 +768,17 @@ MOM6_postdet() { # Copy MOM6 ICs if [[ "${MODE}" = 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only - $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res.nc" "${DATA}/INPUT/MOM.res.nc" + if [ ${warm_start} = '.true.' ]; then + res_dir=${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART + else + res_dir=${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ocean/RESTART + fi + $NLN "${res_dir}/${PDY}.${cyc}0000.MOM.res.nc" "${DATA}/INPUT/MOM.res.nc" case $OCNRES in "025") - $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_1.nc" "${DATA}/INPUT/MOM.res_1.nc" - $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_2.nc" "${DATA}/INPUT/MOM.res_2.nc" - $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_3.nc" "${DATA}/INPUT/MOM.res_3.nc" + $NLN "${res_dir}/${PDY}.${cyc}0000.MOM.res_1.nc" "${DATA}/INPUT/MOM.res_1.nc" + $NLN "${res_dir}/${PDY}.${cyc}0000.MOM.res_2.nc" "${DATA}/INPUT/MOM.res_2.nc" + $NLN "${res_dir}/${PDY}.${cyc}0000.MOM.res_3.nc" "${DATA}/INPUT/MOM.res_3.nc" ;; *) ;; @@ -781,7 +786,7 @@ MOM6_postdet() { else $NCP -pf "${ICSDIR}/${CDATE}/ocn/MOM*nc" "${DATA}/INPUT/" # TODO: Update files in ICSDIR to reflect COM structure naming convention fi - + # Copy MOM6 fixed files $NCP -pf $FIXmom/$OCNRES/* $DATA/INPUT/ @@ -795,15 +800,17 @@ MOM6_postdet() { fi # Copy mediator restart file to RUNDIR # TODO: mediator should have its own CMEPS_postdet() function - local mediator_file="${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/med/${PDY}.${cyc}0000.ufs.cpld.cpl.r.nc" - if [[ -f "${mediator_file}" ]]; then - $NLN "${mediator_file}" "${DATA}/ufs.cpld.cpl.r.nc" - rm -f "${DATA}/rpointer.cpl" - touch "${DATA}/rpointer.cpl" - echo "ufs.cpld.cpl.r.nc" >> "${DATA}/rpointer.cpl" - else - echo "FATAL ERROR: ${mediator_file} does not exist, ABORT!" - exit 4 + if [ ${warm_start} = 'true' ]; then + local mediator_file="${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/med/${PDY}.${cyc}0000.ufs.cpld.cpl.r.nc" + if [[ -f "${mediator_file}" ]]; then + $NLN "${mediator_file}" "${DATA}/ufs.cpld.cpl.r.nc" + rm -f "${DATA}/rpointer.cpl" + touch "${DATA}/rpointer.cpl" + echo "ufs.cpld.cpl.r.nc" >> "${DATA}/rpointer.cpl" + else + echo "FATAL ERROR: ${mediator_file} does not exist, ABORT!" + exit 4 + fi fi if [ $DO_OCN_SPPT = "YES" -o $DO_OCN_PERT_EPBL = "YES" ]; then @@ -988,7 +995,12 @@ CICE_postdet() { # Copy/link CICE IC to DATA if [[ "${MODE}" = 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only - $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ice/RESTART/${PDY}.${cyc}0000.cice_model.res.nc" "${DATA}/cice_model.res.nc" + if [ ${warm_start} = '.true.' ]; then + res_dir=${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ice/RESTART + else + res_dir=${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ice/RESTART + fi + $NLN "${res_dir}/${PDY}.${cyc}0000.cice_model.res.nc" "${DATA}/cice_model.res.nc" else $NCP -p $ICSDIR/$CDATE/ice/cice_model_${ICERESdec}.res_$CDATE.nc $DATA/cice_model.res.nc fi diff --git a/ush/nems_configure.sh b/ush/nems_configure.sh index 04fea90f35..14eeec397a 100755 --- a/ush/nems_configure.sh +++ b/ush/nems_configure.sh @@ -42,11 +42,11 @@ CHMPETS=${CHMPETS:-${ATMPETS}} USE_MOMMESH=${USE_MOMMESH:-"true"} MESH_OCN_ICE=${MESH_OCN_ICE:-"mesh.mx${ICERES}.nc"} -if [[ $OCNRES = "100" ]]; then - EPS_IMESH='2.5e-1' -else - EPS_IMESH='1.0e-1' -fi +case ${OCNRES} in + "100" ) EPS_IMESH="2.5e-1";; + "500" ) EPS_IMESH="4.0e-1";; + * ) EPS_IMESH="1.0e-1";; +esac rm -f $DATA/nems.configure diff --git a/ush/parsing_namelists_CICE.sh b/ush/parsing_namelists_CICE.sh index a08fb06df9..5d974636f2 100755 --- a/ush/parsing_namelists_CICE.sh +++ b/ush/parsing_namelists_CICE.sh @@ -10,13 +10,25 @@ else cmeps_run_type='initial' fi -# C48, 5degree Ocean does not work with this formula -# Supply from config.ice -# TODO: figure out why -local _block_size_x=$(( 2 * ( $NX_GLB / $ICEPETS ) )) -local _block_size_y=$(( $NY_GLB / 2 )) -block_size_x=${block_size_x:-_block_size_x} -block_size_y=${block_size_y:-_block_size_y} +#Get correct MPI options for NPROC and grid +cice_processor_shape=${cice_processor_shape:-'slenderX2'} +shape=${cice_processor_shape#${cice_processor_shape%?}} +NPX=$(( ICEPETS / shape )) #number of processors in x direction +NPY=$(( ICEPETS / NPX )) #number of processors in y direction +if (( $(( NX_GLB % NPX )) == 0 )); then + block_size_x=$(( NX_GLB / NPX )) +else + block_size_x=$(( (NX_GLB / NPX) + 1 )) +fi +if (( $(( NY_GLB % NPY )) == 0 )); then + block_size_y=$(( NY_GLB / NPY )) +else + block_size_y=$(( (NY_GLB / NPY) + 1 )) +fi +max_blocks=$(( (NX_GLB * NY_GLB) / (block_size_x * block_size_y * ICEPETS) )) +if (( max_blocks == 0 )) || (( max_blocks % 2 != 0 )); then + max_blocks=-1 +fi cat > ice_in < ice_in < ice_in < Date: Tue, 24 Jan 2023 22:59:28 -0500 Subject: [PATCH 11/27] minor updates and a typo --- parm/config/config.ice | 4 ++-- ush/forecast_postdet.sh | 18 +++++++++--------- ush/nems_configure.sh | 8 ++++---- ush/parsing_namelists_CICE.sh | 24 ++++++++++++------------ 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/parm/config/config.ice b/parm/config/config.ice index 10d34ec753..3b82a1468f 100644 --- a/parm/config/config.ice +++ b/parm/config/config.ice @@ -5,10 +5,10 @@ case "${ICERES}" in export NX_GLB="1440" export NY_GLB="1080" ;; - "500") + "500") export NX_GLB="72" export NY_GLB="35" - export cice_processor_shape='slenderX1' + export cice_processor_shape="slenderX1" ;; *) echo "FATAL ERROR: Unsupported ICERES = ${ICERES}, ABORT!" diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index c827145ded..30d7ab9235 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -768,10 +768,10 @@ MOM6_postdet() { # Copy MOM6 ICs if [[ "${MODE}" = 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only - if [ ${warm_start} = '.true.' ]; then - res_dir=${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART + if [[ "${warm_start}" = '.true.' ]]; then + local res_dir=${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART else - res_dir=${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ocean/RESTART + local res_dir=${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ocean/RESTART # TODO: clarify what is the difference in the two cases here. They are both valid at the same time as seen on the next line where the files are being linked. fi $NLN "${res_dir}/${PDY}.${cyc}0000.MOM.res.nc" "${DATA}/INPUT/MOM.res.nc" case $OCNRES in @@ -786,7 +786,7 @@ MOM6_postdet() { else $NCP -pf "${ICSDIR}/${CDATE}/ocn/MOM*nc" "${DATA}/INPUT/" # TODO: Update files in ICSDIR to reflect COM structure naming convention fi - + # Copy MOM6 fixed files $NCP -pf $FIXmom/$OCNRES/* $DATA/INPUT/ @@ -800,7 +800,7 @@ MOM6_postdet() { fi # Copy mediator restart file to RUNDIR # TODO: mediator should have its own CMEPS_postdet() function - if [ ${warm_start} = 'true' ]; then + if [[ "${warm_start}" = '.true.' ]]; then local mediator_file="${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/med/${PDY}.${cyc}0000.ufs.cpld.cpl.r.nc" if [[ -f "${mediator_file}" ]]; then $NLN "${mediator_file}" "${DATA}/ufs.cpld.cpl.r.nc" @@ -808,7 +808,7 @@ MOM6_postdet() { touch "${DATA}/rpointer.cpl" echo "ufs.cpld.cpl.r.nc" >> "${DATA}/rpointer.cpl" else - echo "FATAL ERROR: ${mediator_file} does not exist, ABORT!" + echo "FATAL ERROR: ${mediator_file} must exist for warm_start = .true. and does not, ABORT!" exit 4 fi fi @@ -995,10 +995,10 @@ CICE_postdet() { # Copy/link CICE IC to DATA if [[ "${MODE}" = 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only - if [ ${warm_start} = '.true.' ]; then - res_dir=${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ice/RESTART + if [[ "${warm_start}" = '.true.' ]]; then + local res_dir=${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ice/RESTART else - res_dir=${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ice/RESTART + local res_dir=${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ice/RESTART fi $NLN "${res_dir}/${PDY}.${cyc}0000.cice_model.res.nc" "${DATA}/cice_model.res.nc" else diff --git a/ush/nems_configure.sh b/ush/nems_configure.sh index 14eeec397a..a2f687b7b5 100755 --- a/ush/nems_configure.sh +++ b/ush/nems_configure.sh @@ -42,10 +42,10 @@ CHMPETS=${CHMPETS:-${ATMPETS}} USE_MOMMESH=${USE_MOMMESH:-"true"} MESH_OCN_ICE=${MESH_OCN_ICE:-"mesh.mx${ICERES}.nc"} -case ${OCNRES} in - "100" ) EPS_IMESH="2.5e-1";; - "500" ) EPS_IMESH="4.0e-1";; - * ) EPS_IMESH="1.0e-1";; +case "${OCNRES}" in + "500") EPS_IMESH="4.0e-1";; + "100") EPS_IMESH="2.5e-1";; + *) EPS_IMESH="1.0e-1";; esac rm -f $DATA/nems.configure diff --git a/ush/parsing_namelists_CICE.sh b/ush/parsing_namelists_CICE.sh index 5d974636f2..1c160de017 100755 --- a/ush/parsing_namelists_CICE.sh +++ b/ush/parsing_namelists_CICE.sh @@ -10,24 +10,24 @@ else cmeps_run_type='initial' fi -#Get correct MPI options for NPROC and grid -cice_processor_shape=${cice_processor_shape:-'slenderX2'} -shape=${cice_processor_shape#${cice_processor_shape%?}} -NPX=$(( ICEPETS / shape )) #number of processors in x direction -NPY=$(( ICEPETS / NPX )) #number of processors in y direction +# Get correct MPI options for NPROC and grid +local cice_processor_shape=${cice_processor_shape:-'slenderX2'} +local shape=${cice_processor_shape#${cice_processor_shape%?}} +local NPX=$(( ICEPETS / shape )) #number of processors in x direction +local NPY=$(( ICEPETS / NPX )) #number of processors in y direction if (( $(( NX_GLB % NPX )) == 0 )); then - block_size_x=$(( NX_GLB / NPX )) + local block_size_x=$(( NX_GLB / NPX )) else - block_size_x=$(( (NX_GLB / NPX) + 1 )) + local block_size_x=$(( (NX_GLB / NPX) + 1 )) fi if (( $(( NY_GLB % NPY )) == 0 )); then - block_size_y=$(( NY_GLB / NPY )) + local block_size_y=$(( NY_GLB / NPY )) else - block_size_y=$(( (NY_GLB / NPY) + 1 )) + local block_size_y=$(( (NY_GLB / NPY) + 1 )) fi -max_blocks=$(( (NX_GLB * NY_GLB) / (block_size_x * block_size_y * ICEPETS) )) +local max_blocks=$(( (NX_GLB * NY_GLB) / (block_size_x * block_size_y * ICEPETS) )) if (( max_blocks == 0 )) || (( max_blocks % 2 != 0 )); then - max_blocks=-1 + local max_blocks=-1 fi cat > ice_in < ice_in < Date: Wed, 25 Jan 2023 16:12:05 -0500 Subject: [PATCH 12/27] update diag_table to include ocean fields --- parm/parm_fv3diag/diag_table | 77 ++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/parm/parm_fv3diag/diag_table b/parm/parm_fv3diag/diag_table index bcd9a882e4..8b7982a058 100644 --- a/parm/parm_fv3diag/diag_table +++ b/parm/parm_fv3diag/diag_table @@ -1,6 +1,83 @@ "fv3_history", 0, "hours", 1, "hours", "time" "fv3_history2d", 0, "hours", 1, "hours", "time" +"ocn%4yr%2mo%2dy%2hr", 6, "hours", 1, "hours", "time", 6, "hours", "1901 1 1 0 0 0" +"ocn_daily%4yr%2mo%2dy", 1, "days", 1, "days", "time", 1, "days", "1901 1 1 0 0 0" +############## +# Ocean fields +############## +# static fields +"ocean_model", "geolon", "geolon", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolat", "geolat", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolon_c", "geolon_c", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolat_c", "geolat_c", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolon_u", "geolon_u", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolat_u", "geolat_u", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolon_v", "geolon_v", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolat_v", "geolat_v", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +# "ocean_model", "depth_ocean", "depth_ocean", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +# "ocean_model", "wet", "wet", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "wet_c", "wet_c", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "wet_u", "wet_u", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "wet_v", "wet_v", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "sin_rot", "sin_rot", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "cos_rot", "cos_rot", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 + +# ocean output TSUV and others +"ocean_model", "SSH", "SSH", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "SST", "SST", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "SSS", "SSS", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "speed", "speed", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "SSU", "SSU", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "SSV", "SSV", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "frazil", "frazil", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "ePBL_h_ML", "ePBL", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "MLD_003", "MLD_003", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "MLD_0125", "MLD_0125", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 + +# Z-Space Fields Provided for CMIP6 (CMOR Names): +"ocean_model_z", "uo", "uo", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model_z", "vo", "vo", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model_z", "so", "so", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model_z", "temp", "temp", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 + +# forcing +"ocean_model", "taux", "taux", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "tauy", "tauy", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "latent", "latent", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "sensible", "sensible", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "SW", "SW", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "LW", "LW", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "evap", "evap", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "lprec", "lprec", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "lrunoff", "lrunoff", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +# "ocean_model", "frunoff", "frunoff", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "fprec", "fprec", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "LwLatSens", "LwLatSens", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "Heat_PmE", "Heat_PmE", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 + +# Daily fields +"ocean_model", "geolon", "geolon", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolat", "geolat", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolon_c", "geolon_c", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolat_c", "geolat_c", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolon_u", "geolon_u", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolat_u", "geolat_u", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolon_v", "geolon_v", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolat_v", "geolat_v", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "SST", "sst", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "latent", "latent", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "sensible", "sensible", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "SW", "SW", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "LW", "LW", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "evap", "evap", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "lprec", "lprec", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "taux", "taux", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "tauy", "tauy", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 + +################### +# Atmosphere fields +################### "gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 "gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 "gfs_dyn", "sphum", "spfh", "fv3_history", "all", .false., "none", 2 From 87c3aea519caf53ae1f7ab856959e21276f30611 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Wed, 25 Jan 2023 23:08:20 -0500 Subject: [PATCH 13/27] cycled for a full day. ocnpost still crapping out --- parm/config/config.fcst | 30 ++---- parm/parm_fv3diag/diag_table_da | 11 ++ ush/forecast_postdet.sh | 176 +++++++++++++++++++------------- ush/forecast_predet.sh | 19 +++- workflow/setup_expt.py | 3 +- 5 files changed, 142 insertions(+), 97 deletions(-) diff --git a/parm/config/config.fcst b/parm/config/config.fcst index 6a57a804a5..dcedf7ec2f 100755 --- a/parm/config/config.fcst +++ b/parm/config/config.fcst @@ -93,7 +93,7 @@ export h2o_phys=".true." # Options of stratosphere O3 physics reaction coefficients export new_o3forc="YES" -export gwd_opt=2 +export gwd_opt=2 # --GFS.v16 uGWD.v0, used for suite FV3_GFS_v16 and UFS p6 etc # do_ugwp=T: use unified CGWD and OGWD, and turbulent orographic form drag (TOFD) @@ -121,8 +121,8 @@ if [[ "$gwd_opt" -eq 2 ]]; then #export do_gsl_drag_ss=".true." #export do_gsl_drag_tofd=".true." #export do_ugwp_v1_orog_only=".false." - - #--used for UFS p8 + + #--used for UFS p8 export knob_ugwp_version=0 export do_ugwp=".false." export do_tofd=".false." @@ -272,7 +272,7 @@ export FSICS="0" export ideflate=1 export nbits=14 export ishuffle=0 -# compression for RESTART files written by FMS +# compression for RESTART files written by FMS export shuffle=1 export deflate_level=1 @@ -283,20 +283,16 @@ export USE_COUPLER_RES="NO" if [[ "$CDUMP" == "gdas" ]] ; then # GDAS cycle specific parameters # Variables used in DA cycling - if [[ "$QUILTING" = ".true." && "$OUTPUT_GRID" = "gaussian_grid" ]]; then - export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table_da" - else - export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table_da_orig" - fi + export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table_da" - # Write restart files, where $number is current model start time. + # Write restart files, where $number is current model start time. # restart_interval: $number - # number=0, writes out restart files at the end of forecast. + # number=0, writes out restart files at the end of forecast. # number>0, writes out restart files at the frequency of $number and at the end of forecast. # restart_interval: "$number -1" # writes out restart files only once at $number forecast hour. # restart_interval: "$number1 $number2 $number3 ..." - # writes out restart file at the specified forecast hours + # writes out restart file at the specified forecast hours export restart_interval=${restart_interval:-6} # For IAU, write restarts at beginning of window also @@ -313,11 +309,7 @@ if [[ "$CDUMP" == "gdas" ]] ; then # GDAS cycle specific parameters elif [[ "$CDUMP" == "gfs" ]] ; then # GFS cycle specific parameters # Write more variables to output - if [[ "$QUILTING" = ".true." && $OUTPUT_GRID = "gaussian_grid" ]]; then - export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table" - else - export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table_orig" - fi + export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table" # Write gfs restart files to rerun fcst from any break point export restart_interval_gfs=${restart_interval_gfs:-0} @@ -359,10 +351,6 @@ elif [[ "$CDUMP" == "gfs" ]] ; then # GFS cycle specific parameters fi -if [[ "$DO_COUPLED" = "YES" ]] ; then # coupled model - export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table_cpl" -fi - if [[ "$DO_AERO" = "YES" ]]; then # temporary settings for aerosol coupling export AERO_DIAG_TABLE="${AERO_DIAG_TABLE:-$HOMEgfs/parm/parm_fv3diag/diag_table.aero}" export AERO_FIELD_TABLE="${AERO_FIELD_TABLE:-$HOMEgfs/parm/parm_fv3diag/field_table.aero}" diff --git a/parm/parm_fv3diag/diag_table_da b/parm/parm_fv3diag/diag_table_da index d040748237..5e5bc76e5e 100644 --- a/parm/parm_fv3diag/diag_table_da +++ b/parm/parm_fv3diag/diag_table_da @@ -1,5 +1,16 @@ "fv3_history", 0, "hours", 1, "hours", "time" "fv3_history2d", 0, "hours", 1, "hours", "time" +"ocn_da%4yr%2mo%2dy%2hr", 0, "hours", 1, "hours", "time", 1, "hours", "1901 1 1 0 0 0" + +"ocean_model", "geolon", "geolon", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolat", "geolat", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "SSH", "ave_ssh", "ocn_da%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "MLD_0125", "MLD", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "u", "u", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "v", "v", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "h", "h", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "salt", "Salt", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "temp", "Temp", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 "gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 "gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 266702fdf3..8134017612 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -54,16 +54,18 @@ FV3_GFS_postdet(){ done # Replace sfc_data with sfcanl_data restart files from $memdir (if found) - for file in $(ls $memdir/RESTART/${sPDY}.${scyc}0000.sfcanl_data.tile?.nc); do - if [[ -f $file ]]; then - file2=$(echo $(basename $file)) - file2=$(echo $file2 | cut -d. -f3-) # remove the date from file - fsufanl=$(echo $file2 | cut -d. -f1) - file2=$(echo $file2 | sed -e "s/sfcanl_data/sfc_data/g") - rm -f $DATA/INPUT/$file2 - $NLN $file $DATA/INPUT/$file2 - fi - done + if [ "${MODE}" = "cycled" ] && [ "${APP}" = "ATM" ]; then # TODO: remove if-block when global_cycle can handle NOAHMP + for file in $(ls $memdir/RESTART/${sPDY}.${scyc}0000.sfcanl_data.tile?.nc); do + if [[ -f $file ]]; then + file2=$(echo $(basename $file)) + file2=$(echo $file2 | cut -d. -f3-) # remove the date from file + fsufanl=$(echo $file2 | cut -d. -f1) + file2=$(echo $file2 | sed -e "s/sfcanl_data/sfc_data/g") + rm -f $DATA/INPUT/$file2 + $NLN $file $DATA/INPUT/$file2 + fi + done + fi # Need a coupler.res when doing IAU if [ $DOIAU = "YES" ]; then @@ -795,7 +797,7 @@ MOM6_postdet() { # Copy mediator restart file to RUNDIR # TODO: mediator should have its own CMEPS_postdet() function if [[ "${warm_start}" = '.true.' ]]; then - local mediator_file="${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/med/${PDY}.${cyc}0000.ufs.cpld.cpl.r.nc" + local mediator_file="${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/med/RESTART/${PDY}.${cyc}0000.ufs.cpld.cpl.r.nc" if [[ -f "${mediator_file}" ]]; then $NLN "${mediator_file}" "${DATA}/ufs.cpld.cpl.r.nc" rm -f "${DATA}/rpointer.cpl" @@ -807,6 +809,7 @@ MOM6_postdet() { fi fi + # TODO: some documentation would be nice to see here, e.g. whose phone number is in here? if [ $DO_OCN_SPPT = "YES" -o $DO_OCN_PERT_EPBL = "YES" ]; then if [ ${SET_STP_SEED:-"YES"} = "YES" ]; then ISEED_OCNSPPT=$(( (CDATE*1000 + MEMBER*10 + 6) % 2147483647 )) @@ -816,51 +819,69 @@ MOM6_postdet() { fi fi + # Create COMOUTocean + [[ ! -d $COMOUTocean ]] && mkdir -p $COMOUTocean + # Link output files + if [[ "${CDUMP}" = "gfs" ]]; then + # Link output files for CDUMP = gfs - export ENSMEM=${ENSMEM:-01} - export IDATE=$CDATE + # TODO: get requirements on what files need to be written out and what these dates here are and what they mean + export ENSMEM=${ENSMEM:-01} + export IDATE=$CDATE - [[ ! -d $COMOUTocean ]] && mkdir -p $COMOUTocean + fhrlst=$OUTPUT_FH - fhrlst=$OUTPUT_FH + for fhr in $fhrlst; do + if [ $fhr = 'anl' ]; then # Looking at OUTPUT_FH, this is never true, TODO: remove this block + continue + fi + if [ -z ${last_fhr:-} ]; then + last_fhr=$fhr + continue + fi + (( interval = fhr - last_fhr )) + (( midpoint = last_fhr + interval/2 )) + VDATE=$($NDATE $fhr $IDATE) + YYYY=$(echo $VDATE | cut -c1-4) + MM=$(echo $VDATE | cut -c5-6) + DD=$(echo $VDATE | cut -c7-8) + HH=$(echo $VDATE | cut -c9-10) + SS=$((10#$HH*3600)) + + VDATE_MID=$($NDATE $midpoint $IDATE) + YYYY_MID=$(echo $VDATE_MID | cut -c1-4) + MM_MID=$(echo $VDATE_MID | cut -c5-6) + DD_MID=$(echo $VDATE_MID | cut -c7-8) + HH_MID=$(echo $VDATE_MID | cut -c9-10) + SS_MID=$((10#$HH_MID*3600)) + + source_file="ocn_${YYYY_MID}_${MM_MID}_${DD_MID}_${HH_MID}.nc" + dest_file="ocn${VDATE}.${ENSMEM}.${IDATE}.nc" + ${NLN} ${COMOUTocean}/${dest_file} ${DATA}/${source_file} + + source_file="ocn_daily_${YYYY}_${MM}_${DD}.nc" + dest_file=${source_file} + if [ ! -a "${DATA}/${source_file}" ]; then + $NLN ${COMOUTocean}/${dest_file} ${DATA}/${source_file} + fi - for fhr in $fhrlst; do - if [ $fhr = 'anl' ]; then - continue - fi - if [ -z ${last_fhr:-} ]; then last_fhr=$fhr - continue - fi - (( interval = fhr - last_fhr )) - (( midpoint = last_fhr + interval/2 )) - VDATE=$($NDATE $fhr $IDATE) - YYYY=$(echo $VDATE | cut -c1-4) - MM=$(echo $VDATE | cut -c5-6) - DD=$(echo $VDATE | cut -c7-8) - HH=$(echo $VDATE | cut -c9-10) - SS=$((10#$HH*3600)) + done - VDATE_MID=$($NDATE $midpoint $IDATE) - YYYY_MID=$(echo $VDATE_MID | cut -c1-4) - MM_MID=$(echo $VDATE_MID | cut -c5-6) - DD_MID=$(echo $VDATE_MID | cut -c7-8) - HH_MID=$(echo $VDATE_MID | cut -c9-10) - SS_MID=$((10#$HH_MID*3600)) - - source_file="ocn_${YYYY_MID}_${MM_MID}_${DD_MID}_${HH_MID}.nc" - dest_file="ocn${VDATE}.${ENSMEM}.${IDATE}.nc" - ${NLN} ${COMOUTocean}/${dest_file} ${DATA}/${source_file} - - source_file="ocn_daily_${YYYY}_${MM}_${DD}.nc" - dest_file=${source_file} - if [ ! -a "${DATA}/${source_file}" ]; then - $NLN ${COMOUTocean}/${dest_file} ${DATA}/${source_file} - fi + elif [[ "${CDUMP}" = "gdas" ]]; then + # Link output files for CDUMP = gdas - last_fhr=$fhr - done + # MOM6 does not write out the first forecast hour, so start at FHOUT + local fhr="${FHOUT}" + while [[ "${fhr}" -le "${FHMAX}" ]]; do + local idatestr=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${fhr} hours" +%Y_%m_%d_%H) + local fhr3=$(printf %03i ${fhr}) + $NLN "${COMOUTocean}/${CDUMP}.t${cyc}z.ocnf${fhr3}.nc" "${DATA}/ocn_da_${idatestr}.nc" + local fhr=$((fhr + FHOUT)) + done + + fi # Link ocean restarts from DATA to COM mkdir -p "${COMOUTocean}/RESTART" @@ -884,13 +905,13 @@ MOM6_postdet() { local idate=$($NDATE $res_int $CDATE) while [[ $idate -lt $rdate ]]; do local idatestr=$(date +%Y-%m-%d-%H -d "${idate:0:8} ${idate:8:2}") - $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.res.nc" "${DATA}/MOM6_RESTART/MOM.res.${idatestr}-00-00.nc" + $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res.nc" "${DATA}/MOM6_RESTART/MOM.res.${idatestr}-00-00.nc" case ${OCNRES} in "025") $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_1.nc" "${DATA}/MOM6_RESTART/MOM.res_1.${idatestr}-00-00.nc" $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_2.nc" "${DATA}/MOM6_RESTART/MOM.res_2.${idatestr}-00-00.nc" $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_3.nc" "${DATA}/MOM6_RESTART/MOM.res_3.${idatestr}-00-00.nc" - ;; + ;; esac local idate=$($NDATE $res_int $idate) done @@ -1009,30 +1030,43 @@ CICE_postdet() { $NLN -sf $FIXcice/$ICERES/$MESH_OCN_ICE $DATA/ # Link CICE output files - export ENSMEM=${ENSMEM:-01} - export IDATE=$CDATE [[ ! -d $COMOUTice ]] && mkdir -p $COMOUTice - fhrlst=$OUTPUT_FH - for fhr in $fhrlst; do - if [ $fhr = 'anl' ]; then - continue - fi - VDATE=$($NDATE $fhr $IDATE) - YYYY=$(echo $VDATE | cut -c1-4) - MM=$(echo $VDATE | cut -c5-6) - DD=$(echo $VDATE | cut -c7-8) - HH=$(echo $VDATE | cut -c9-10) - SS=$((10#$HH*3600)) + if [[ "${CDUMP}" = "gfs" ]]; then + # Link output files for CDUMP = gfs - if [[ 10#$fhr -eq 0 ]]; then - $NLN $COMOUTice/iceic$VDATE.$ENSMEM.$IDATE.nc $DATA/history/iceh_ic.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc - else - (( interval = fhr - last_fhr )) - $NLN $COMOUTice/ice$VDATE.$ENSMEM.$IDATE.nc $DATA/history/iceh_$(printf "%0.2d" $interval)h.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc - fi - last_fhr=$fhr - done + export ENSMEM=${ENSMEM:-01} + export IDATE=$CDATE + + fhrlst=$OUTPUT_FH + + # TODO: consult w/ NB on how to improve on this. Gather requirements and more information on what these files are and how they are used to properly catalog them + for fhr in $fhrlst; do + if [ $fhr = 'anl' ]; then # Looking at OUTPUT_FH, this is never true. TODO: remove this block + continue + fi + VDATE=$($NDATE $fhr $IDATE) + YYYY=$(echo $VDATE | cut -c1-4) + MM=$(echo $VDATE | cut -c5-6) + DD=$(echo $VDATE | cut -c7-8) + HH=$(echo $VDATE | cut -c9-10) + SS=$((10#$HH*3600)) + + if [[ 10#$fhr -eq 0 ]]; then + $NLN $COMOUTice/iceic$VDATE.$ENSMEM.$IDATE.nc $DATA/history/iceh_ic.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc + else + (( interval = fhr - last_fhr )) + $NLN $COMOUTice/ice$VDATE.$ENSMEM.$IDATE.nc $DATA/history/iceh_$(printf "%0.2d" $interval)h.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc + fi + last_fhr=$fhr + done + + elif [[ "${CDUMP}" = "gdas" ]]; then + # Link output files for CDUMP = gdas + + echo "Link CICE forecast output files for CDUMP = gdas" + + fi # Link CICE restarts to COMOUTice/RESTART # Loop over restart_interval and link restarts from DATA to COM diff --git a/ush/forecast_predet.sh b/ush/forecast_predet.sh index 4a29968b25..8706868611 100755 --- a/ush/forecast_predet.sh +++ b/ush/forecast_predet.sh @@ -12,12 +12,25 @@ # Cycling and forecast hour specific parameters to_seconds() { -# Function to convert HHMMSS to seconds since 00Z - local hhmmss=${1} + # Function to convert HHMMSS to seconds since 00Z + local hhmmss=${1:?} local hh=${hhmmss:0:2} local mm=${hhmmss:2:2} local ss=${hhmmss:4:2} - echo $(((hh*3600+mm*60+ss))) + local seconds=$(((hh*3600+mm*60+ss))) + local padded_seconds=$(printf "%05d" ${seconds}) + echo ${padded_seconds} +} + +middle_date(){ + # Function to calculate mid-point date in YYYYMMDDHH between two dates also in YYYYMMDDHH + local date1=${1:?} + local date2=${2:?} + local date1s=$(date -d "${date1:0:8} ${date1:8:2}" +%s) + local date2s=$(date -d "${date2:0:8} ${date2:8:2}" +%s) + local dtsecsby2=$(( $((date2s - date1s)) / 2 )) + local mid_date=$(date -d "${date1:0:8} ${date1:8:2} + ${dtsecsby2} seconds" +%Y%m%d%H%M%S) + echo ${mid_date:0:10} } common_predet(){ diff --git a/workflow/setup_expt.py b/workflow/setup_expt.py index e23be16fb9..7999e3d004 100755 --- a/workflow/setup_expt.py +++ b/workflow/setup_expt.py @@ -67,8 +67,7 @@ def fill_COMROT_cycled(host, inputs): if inputs.start in ['warm']: # This is warm start experiment idatestr = datetime_to_YMDH(inputs.idate - to_timedelta('T06H')) - atmos_dir = ocean_dir = ice_dir = 'RESTART' - med_dir = '' + atmos_dir = ocean_dir = ice_dir = med_dir = 'RESTART' elif inputs.start in ['cold']: # This is a cold start experiment idatestr = datetime_to_YMDH(inputs.idate) atmos_dir = 'INPUT' From 6865065190ed9933e7dacb1f8ca9de28d399ebee Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Thu, 26 Jan 2023 10:04:59 -0500 Subject: [PATCH 14/27] configs do not need exec perms. do not run ocnpost in cycled mode of s2s --- parm/config/config.aero | 0 parm/config/config.aeroanl | 0 parm/config/config.aeroanlfinal | 0 parm/config/config.aeroanlinit | 0 parm/config/config.aeroanlrun | 0 parm/config/config.aerosol_init | 0 parm/config/config.anal | 0 parm/config/config.analcalc | 0 parm/config/config.analdiag | 0 parm/config/config.arch | 0 parm/config/config.atmanal | 0 parm/config/config.atmanalpost | 0 parm/config/config.atmanalprep | 0 parm/config/config.atmanalrun | 0 parm/config/config.atmensanal | 0 parm/config/config.atmensanalpost | 0 parm/config/config.atmensanalprep | 0 parm/config/config.atmensanalrun | 0 parm/config/config.awips | 0 parm/config/config.base.emc.dyn | 2 +- parm/config/config.base.nco.static | 0 parm/config/config.coupled_ic | 0 parm/config/config.defaults.s2sw | 0 parm/config/config.earc | 0 parm/config/config.ecen | 0 parm/config/config.echgres | 0 parm/config/config.ediag | 0 parm/config/config.efcs | 0 parm/config/config.eobs | 0 parm/config/config.epos | 0 parm/config/config.esfc | 0 parm/config/config.eupd | 0 parm/config/config.fcst | 0 parm/config/config.fv3 | 0 parm/config/config.fv3.nco.static | 0 parm/config/config.gempak | 0 parm/config/config.getic | 0 parm/config/config.gldas | 0 parm/config/config.ice | 0 parm/config/config.init | 0 parm/config/config.metp | 0 parm/config/config.nsst | 0 parm/config/config.ocn | 0 parm/config/config.ocnanal | 0 parm/config/config.ocnanalpost | 0 parm/config/config.ocnanalprep | 0 parm/config/config.ocnanalrun | 0 parm/config/config.ocnpost | 0 parm/config/config.post | 0 parm/config/config.postsnd | 0 parm/config/config.prep | 0 parm/config/config.resources | 0 parm/config/config.resources.nco.static | 0 parm/config/config.sfcanl | 0 parm/config/config.vrfy | 0 parm/config/config.wafs | 0 parm/config/config.wafsblending | 0 parm/config/config.wafsblending0p25 | 0 parm/config/config.wafsgcip | 0 parm/config/config.wafsgrib2 | 0 parm/config/config.wafsgrib20p25 | 0 parm/config/config.wave | 0 parm/config/config.waveawipsbulls | 0 parm/config/config.waveawipsgridded | 0 parm/config/config.wavegempak | 0 parm/config/config.waveinit | 0 parm/config/config.wavepostbndpnt | 0 parm/config/config.wavepostbndpntbll | 0 parm/config/config.wavepostpnt | 0 parm/config/config.wavepostsbs | 0 parm/config/config.waveprep | 0 workflow/applications.py | 4 ++-- workflow/rocoto/workflow_tasks.py | 8 +++++--- 73 files changed, 8 insertions(+), 6 deletions(-) mode change 100755 => 100644 parm/config/config.aero mode change 100755 => 100644 parm/config/config.aeroanl mode change 100755 => 100644 parm/config/config.aeroanlfinal mode change 100755 => 100644 parm/config/config.aeroanlinit mode change 100755 => 100644 parm/config/config.aeroanlrun mode change 100755 => 100644 parm/config/config.aerosol_init mode change 100755 => 100644 parm/config/config.anal mode change 100755 => 100644 parm/config/config.analcalc mode change 100755 => 100644 parm/config/config.analdiag mode change 100755 => 100644 parm/config/config.arch mode change 100755 => 100644 parm/config/config.atmanal mode change 100755 => 100644 parm/config/config.atmanalpost mode change 100755 => 100644 parm/config/config.atmanalprep mode change 100755 => 100644 parm/config/config.atmanalrun mode change 100755 => 100644 parm/config/config.atmensanal mode change 100755 => 100644 parm/config/config.atmensanalpost mode change 100755 => 100644 parm/config/config.atmensanalprep mode change 100755 => 100644 parm/config/config.atmensanalrun mode change 100755 => 100644 parm/config/config.awips mode change 100755 => 100644 parm/config/config.base.emc.dyn mode change 100755 => 100644 parm/config/config.base.nco.static mode change 100755 => 100644 parm/config/config.coupled_ic mode change 100755 => 100644 parm/config/config.defaults.s2sw mode change 100755 => 100644 parm/config/config.earc mode change 100755 => 100644 parm/config/config.ecen mode change 100755 => 100644 parm/config/config.echgres mode change 100755 => 100644 parm/config/config.ediag mode change 100755 => 100644 parm/config/config.efcs mode change 100755 => 100644 parm/config/config.eobs mode change 100755 => 100644 parm/config/config.epos mode change 100755 => 100644 parm/config/config.esfc mode change 100755 => 100644 parm/config/config.eupd mode change 100755 => 100644 parm/config/config.fcst mode change 100755 => 100644 parm/config/config.fv3 mode change 100755 => 100644 parm/config/config.fv3.nco.static mode change 100755 => 100644 parm/config/config.gempak mode change 100755 => 100644 parm/config/config.getic mode change 100755 => 100644 parm/config/config.gldas mode change 100755 => 100644 parm/config/config.ice mode change 100755 => 100644 parm/config/config.init mode change 100755 => 100644 parm/config/config.metp mode change 100755 => 100644 parm/config/config.nsst mode change 100755 => 100644 parm/config/config.ocn mode change 100755 => 100644 parm/config/config.ocnanal mode change 100755 => 100644 parm/config/config.ocnanalpost mode change 100755 => 100644 parm/config/config.ocnanalprep mode change 100755 => 100644 parm/config/config.ocnanalrun mode change 100755 => 100644 parm/config/config.ocnpost mode change 100755 => 100644 parm/config/config.post mode change 100755 => 100644 parm/config/config.postsnd mode change 100755 => 100644 parm/config/config.prep mode change 100755 => 100644 parm/config/config.resources mode change 100755 => 100644 parm/config/config.resources.nco.static mode change 100755 => 100644 parm/config/config.sfcanl mode change 100755 => 100644 parm/config/config.vrfy mode change 100755 => 100644 parm/config/config.wafs mode change 100755 => 100644 parm/config/config.wafsblending mode change 100755 => 100644 parm/config/config.wafsblending0p25 mode change 100755 => 100644 parm/config/config.wafsgcip mode change 100755 => 100644 parm/config/config.wafsgrib2 mode change 100755 => 100644 parm/config/config.wafsgrib20p25 mode change 100755 => 100644 parm/config/config.wave mode change 100755 => 100644 parm/config/config.waveawipsbulls mode change 100755 => 100644 parm/config/config.waveawipsgridded mode change 100755 => 100644 parm/config/config.wavegempak mode change 100755 => 100644 parm/config/config.waveinit mode change 100755 => 100644 parm/config/config.wavepostbndpnt mode change 100755 => 100644 parm/config/config.wavepostbndpntbll mode change 100755 => 100644 parm/config/config.wavepostpnt mode change 100755 => 100644 parm/config/config.wavepostsbs mode change 100755 => 100644 parm/config/config.waveprep diff --git a/parm/config/config.aero b/parm/config/config.aero old mode 100755 new mode 100644 diff --git a/parm/config/config.aeroanl b/parm/config/config.aeroanl old mode 100755 new mode 100644 diff --git a/parm/config/config.aeroanlfinal b/parm/config/config.aeroanlfinal old mode 100755 new mode 100644 diff --git a/parm/config/config.aeroanlinit b/parm/config/config.aeroanlinit old mode 100755 new mode 100644 diff --git a/parm/config/config.aeroanlrun b/parm/config/config.aeroanlrun old mode 100755 new mode 100644 diff --git a/parm/config/config.aerosol_init b/parm/config/config.aerosol_init old mode 100755 new mode 100644 diff --git a/parm/config/config.anal b/parm/config/config.anal old mode 100755 new mode 100644 diff --git a/parm/config/config.analcalc b/parm/config/config.analcalc old mode 100755 new mode 100644 diff --git a/parm/config/config.analdiag b/parm/config/config.analdiag old mode 100755 new mode 100644 diff --git a/parm/config/config.arch b/parm/config/config.arch old mode 100755 new mode 100644 diff --git a/parm/config/config.atmanal b/parm/config/config.atmanal old mode 100755 new mode 100644 diff --git a/parm/config/config.atmanalpost b/parm/config/config.atmanalpost old mode 100755 new mode 100644 diff --git a/parm/config/config.atmanalprep b/parm/config/config.atmanalprep old mode 100755 new mode 100644 diff --git a/parm/config/config.atmanalrun b/parm/config/config.atmanalrun old mode 100755 new mode 100644 diff --git a/parm/config/config.atmensanal b/parm/config/config.atmensanal old mode 100755 new mode 100644 diff --git a/parm/config/config.atmensanalpost b/parm/config/config.atmensanalpost old mode 100755 new mode 100644 diff --git a/parm/config/config.atmensanalprep b/parm/config/config.atmensanalprep old mode 100755 new mode 100644 diff --git a/parm/config/config.atmensanalrun b/parm/config/config.atmensanalrun old mode 100755 new mode 100644 diff --git a/parm/config/config.awips b/parm/config/config.awips old mode 100755 new mode 100644 diff --git a/parm/config/config.base.emc.dyn b/parm/config/config.base.emc.dyn old mode 100755 new mode 100644 index 359eee919f..d9c8b876f6 --- a/parm/config/config.base.emc.dyn +++ b/parm/config/config.base.emc.dyn @@ -362,7 +362,7 @@ export MAKE_ACFTBUFR="@MAKE_ACFTBUFR@" # Analysis increments to zero in CALCINCEXEC export INCREMENTS_TO_ZERO="'liq_wat_inc','icmr_inc'" -# Write analysis files for early cycle EnKF +# Write analysis files for early cycle EnKF export DO_CALC_INCREMENT_ENKF_GFS="YES" # Stratospheric increments to zero diff --git a/parm/config/config.base.nco.static b/parm/config/config.base.nco.static old mode 100755 new mode 100644 diff --git a/parm/config/config.coupled_ic b/parm/config/config.coupled_ic old mode 100755 new mode 100644 diff --git a/parm/config/config.defaults.s2sw b/parm/config/config.defaults.s2sw old mode 100755 new mode 100644 diff --git a/parm/config/config.earc b/parm/config/config.earc old mode 100755 new mode 100644 diff --git a/parm/config/config.ecen b/parm/config/config.ecen old mode 100755 new mode 100644 diff --git a/parm/config/config.echgres b/parm/config/config.echgres old mode 100755 new mode 100644 diff --git a/parm/config/config.ediag b/parm/config/config.ediag old mode 100755 new mode 100644 diff --git a/parm/config/config.efcs b/parm/config/config.efcs old mode 100755 new mode 100644 diff --git a/parm/config/config.eobs b/parm/config/config.eobs old mode 100755 new mode 100644 diff --git a/parm/config/config.epos b/parm/config/config.epos old mode 100755 new mode 100644 diff --git a/parm/config/config.esfc b/parm/config/config.esfc old mode 100755 new mode 100644 diff --git a/parm/config/config.eupd b/parm/config/config.eupd old mode 100755 new mode 100644 diff --git a/parm/config/config.fcst b/parm/config/config.fcst old mode 100755 new mode 100644 diff --git a/parm/config/config.fv3 b/parm/config/config.fv3 old mode 100755 new mode 100644 diff --git a/parm/config/config.fv3.nco.static b/parm/config/config.fv3.nco.static old mode 100755 new mode 100644 diff --git a/parm/config/config.gempak b/parm/config/config.gempak old mode 100755 new mode 100644 diff --git a/parm/config/config.getic b/parm/config/config.getic old mode 100755 new mode 100644 diff --git a/parm/config/config.gldas b/parm/config/config.gldas old mode 100755 new mode 100644 diff --git a/parm/config/config.ice b/parm/config/config.ice old mode 100755 new mode 100644 diff --git a/parm/config/config.init b/parm/config/config.init old mode 100755 new mode 100644 diff --git a/parm/config/config.metp b/parm/config/config.metp old mode 100755 new mode 100644 diff --git a/parm/config/config.nsst b/parm/config/config.nsst old mode 100755 new mode 100644 diff --git a/parm/config/config.ocn b/parm/config/config.ocn old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanal b/parm/config/config.ocnanal old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanalpost b/parm/config/config.ocnanalpost old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanalprep b/parm/config/config.ocnanalprep old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanalrun b/parm/config/config.ocnanalrun old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnpost b/parm/config/config.ocnpost old mode 100755 new mode 100644 diff --git a/parm/config/config.post b/parm/config/config.post old mode 100755 new mode 100644 diff --git a/parm/config/config.postsnd b/parm/config/config.postsnd old mode 100755 new mode 100644 diff --git a/parm/config/config.prep b/parm/config/config.prep old mode 100755 new mode 100644 diff --git a/parm/config/config.resources b/parm/config/config.resources old mode 100755 new mode 100644 diff --git a/parm/config/config.resources.nco.static b/parm/config/config.resources.nco.static old mode 100755 new mode 100644 diff --git a/parm/config/config.sfcanl b/parm/config/config.sfcanl old mode 100755 new mode 100644 diff --git a/parm/config/config.vrfy b/parm/config/config.vrfy old mode 100755 new mode 100644 diff --git a/parm/config/config.wafs b/parm/config/config.wafs old mode 100755 new mode 100644 diff --git a/parm/config/config.wafsblending b/parm/config/config.wafsblending old mode 100755 new mode 100644 diff --git a/parm/config/config.wafsblending0p25 b/parm/config/config.wafsblending0p25 old mode 100755 new mode 100644 diff --git a/parm/config/config.wafsgcip b/parm/config/config.wafsgcip old mode 100755 new mode 100644 diff --git a/parm/config/config.wafsgrib2 b/parm/config/config.wafsgrib2 old mode 100755 new mode 100644 diff --git a/parm/config/config.wafsgrib20p25 b/parm/config/config.wafsgrib20p25 old mode 100755 new mode 100644 diff --git a/parm/config/config.wave b/parm/config/config.wave old mode 100755 new mode 100644 diff --git a/parm/config/config.waveawipsbulls b/parm/config/config.waveawipsbulls old mode 100755 new mode 100644 diff --git a/parm/config/config.waveawipsgridded b/parm/config/config.waveawipsgridded old mode 100755 new mode 100644 diff --git a/parm/config/config.wavegempak b/parm/config/config.wavegempak old mode 100755 new mode 100644 diff --git a/parm/config/config.waveinit b/parm/config/config.waveinit old mode 100755 new mode 100644 diff --git a/parm/config/config.wavepostbndpnt b/parm/config/config.wavepostbndpnt old mode 100755 new mode 100644 diff --git a/parm/config/config.wavepostbndpntbll b/parm/config/config.wavepostbndpntbll old mode 100755 new mode 100644 diff --git a/parm/config/config.wavepostpnt b/parm/config/config.wavepostpnt old mode 100755 new mode 100644 diff --git a/parm/config/config.wavepostsbs b/parm/config/config.wavepostsbs old mode 100755 new mode 100644 diff --git a/parm/config/config.waveprep b/parm/config/config.waveprep old mode 100755 new mode 100644 diff --git a/workflow/applications.py b/workflow/applications.py index e29f55bcea..51b5c89080 100644 --- a/workflow/applications.py +++ b/workflow/applications.py @@ -345,8 +345,8 @@ def _get_cycled_task_names(self): gdas_gfs_common_tasks_before_fcst = ['prep'] gdas_gfs_common_tasks_after_fcst = ['post'] - if self.do_ocean: - gdas_gfs_common_tasks_after_fcst += ['ocnpost'] + #if self.do_ocean: # TODO: uncomment when ocnpost is fixed in cycled mode + # gdas_gfs_common_tasks_after_fcst += ['ocnpost'] gdas_gfs_common_tasks_after_fcst += ['vrfy'] gdas_gfs_common_cleanup_tasks = ['arch'] diff --git a/workflow/rocoto/workflow_tasks.py b/workflow/rocoto/workflow_tasks.py index ba517260e4..b990382540 100644 --- a/workflow/rocoto/workflow_tasks.py +++ b/workflow/rocoto/workflow_tasks.py @@ -668,7 +668,8 @@ def post(self): return self._post_task('post', add_anl_to_post=add_anl_to_post) def ocnpost(self): - return self._post_task('ocnpost', add_anl_to_post=False) + if self.app_config.mode in ['forecast-only']: # TODO: fix ocnpost in cycled mode + return self._post_task('ocnpost', add_anl_to_post=False) def _post_task(self, task_name, add_anl_to_post=False): if task_name not in ['post', 'ocnpost']: @@ -1013,8 +1014,9 @@ def arch(self): dep_dict = {'type': 'task', 'name': f'{self.cdump}wavepostbndpnt'} deps.append(rocoto.add_dependency(dep_dict)) if self.app_config.do_ocean: - dep_dict = {'type': 'metatask', 'name': f'{self.cdump}ocnpost'} - deps.append(rocoto.add_dependency(dep_dict)) + 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)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) cycledef = 'gdas_half,gdas' if self.cdump in ['gdas'] else self.cdump From cd695480f959180d9ee9d93a4d8405a0875ce0d5 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Thu, 26 Jan 2023 10:10:43 -0500 Subject: [PATCH 15/27] fix pynorms failure --- workflow/applications.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow/applications.py b/workflow/applications.py index 51b5c89080..a21f2f01cb 100644 --- a/workflow/applications.py +++ b/workflow/applications.py @@ -345,7 +345,7 @@ def _get_cycled_task_names(self): gdas_gfs_common_tasks_before_fcst = ['prep'] gdas_gfs_common_tasks_after_fcst = ['post'] - #if self.do_ocean: # TODO: uncomment when ocnpost is fixed in cycled mode + # if self.do_ocean: # TODO: uncomment when ocnpost is fixed in cycled mode # gdas_gfs_common_tasks_after_fcst += ['ocnpost'] gdas_gfs_common_tasks_after_fcst += ['vrfy'] From 22c91a06ea66df57662c7cc3ff8b5744fd8137e3 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Thu, 26 Jan 2023 23:13:04 -0500 Subject: [PATCH 16/27] update CICE_OUTPUT and CICE_RESTART after discussing w/ NB --- ush/forecast_postdet.sh | 88 +++++++++++++++++++---------------- ush/forecast_predet.sh | 18 ++----- ush/parsing_namelists_CICE.sh | 10 ++-- 3 files changed, 56 insertions(+), 60 deletions(-) diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index eab13fb85d..720bef0f66 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -759,19 +759,12 @@ MOM6_postdet() { # Copy MOM6 ICs if [[ "${MODE}" = 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only - if [[ "${warm_start}" = '.true.' ]]; then - local res_dir=${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART - else - local res_dir=${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ocean/RESTART # TODO: clarify what is the difference in the two cases here. They are both valid at the same time as seen on the next line where the files are being linked. - fi - $NLN "${res_dir}/${PDY}.${cyc}0000.MOM.res.nc" "${DATA}/INPUT/MOM.res.nc" + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res.nc" "${DATA}/INPUT/MOM.res.nc" case $OCNRES in "025") - $NLN "${res_dir}/${PDY}.${cyc}0000.MOM.res_1.nc" "${DATA}/INPUT/MOM.res_1.nc" - $NLN "${res_dir}/${PDY}.${cyc}0000.MOM.res_2.nc" "${DATA}/INPUT/MOM.res_2.nc" - $NLN "${res_dir}/${PDY}.${cyc}0000.MOM.res_3.nc" "${DATA}/INPUT/MOM.res_3.nc" - ;; - *) + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_1.nc" "${DATA}/INPUT/MOM.res_1.nc" + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_2.nc" "${DATA}/INPUT/MOM.res_2.nc" + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_3.nc" "${DATA}/INPUT/MOM.res_3.nc" ;; esac else @@ -878,10 +871,12 @@ MOM6_postdet() { fi - # Link ocean restarts from DATA to COM mkdir -p "${COMOUTocean}/RESTART" + # end point restart does not have a timestamp, calculate - local rdate=$($NDATE $FHMAX $CDATE) + local rdate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${FHMAX} hours" +%Y%m%d%H) + + # Link ocean restarts from DATA to COM # Coarser than 1/2 degree has a single MOM restart $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res.nc" "${DATA}/MOM6_RESTART/MOM.res.nc" # 1/4 degree resolution has 3 additional restarts @@ -897,7 +892,7 @@ MOM6_postdet() { # Loop over restart_interval frequency and link restarts from DATA to COM local res_int=$(echo $restart_interval | cut -d' ' -f1) # If this is a list, get the frequency. # This is bound to break w/ IAU - local idate=$($NDATE $res_int $CDATE) + local idate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${res_int} hours" +%Y%m%d%H) while [[ $idate -lt $rdate ]]; do local idatestr=$(date +%Y-%m-%d-%H -d "${idate:0:8} ${idate:8:2}") $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res.nc" "${DATA}/MOM6_RESTART/MOM.res.${idatestr}-00-00.nc" @@ -908,7 +903,7 @@ MOM6_postdet() { $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_3.nc" "${DATA}/MOM6_RESTART/MOM.res_3.${idatestr}-00-00.nc" ;; esac - local idate=$($NDATE $res_int $idate) + local idate=$(date -d "${idate:0:8} ${idate:8:2} + ${res_int} hours" +%Y%m%d%H) done # TODO: mediator should have its own CMEPS_postdet() function @@ -918,12 +913,12 @@ MOM6_postdet() { # Instead of linking, copy the mediator files after the model finishes #local COMOUTmed="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/med" #mkdir -p "${COMOUTmed}/RESTART" - #local idate=$($NDATE $res_int $CDATE) + #local idate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${res_int} hours" +%Y%m%d%H) #while [[ $idate -le $rdate ]]; do # local seconds=$(to_seconds ${idate:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds # local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" # $NLN "${COMOUTmed}/RESTART/${idate:0:8}.${idate:8:2}0000.ufs.cpld.cpl.r.nc" "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" - # local idate=$($NDATE $res_int $idate) + # local idate=$(date -d "${idate:0:8} ${idate:8:2} + ${res_int} hours" +%Y%m%d%H) #done echo "SUB ${FUNCNAME[0]}: MOM6 input data linked/copied" @@ -948,14 +943,14 @@ MOM6_out() { # See MOM6_postdet() function for error message local COMOUTmed="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/med" mkdir -p "${COMOUTmed}/RESTART" - local rdate=$($NDATE $FHMAX $CDATE) local res_int=$(echo $restart_interval | cut -d' ' -f1) # If this is a list, get the frequency. # This is bound to break w/ IAU - local idate=$($NDATE $res_int $CDATE) + local idate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${res_int} hours" +%Y%m%d%H) + local rdate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${FHMAX} hours" +%Y%m%d%H) while [[ $idate -le $rdate ]]; do local seconds=$(to_seconds ${idate:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" $NCP "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" "${COMOUTmed}/RESTART/${idate:0:8}.${idate:8:2}0000.ufs.cpld.cpl.r.nc" - local idate=$($NDATE $res_int $idate) + local idate=$(date -d "${idate:0:8} ${idate:8:2} + ${res_int} hours" +%Y%m%d%H) done } @@ -971,10 +966,16 @@ CICE_postdet() { steps=$((nhours*stepsperhr)) npt=$((FHMAX*$stepsperhr)) # Need this in order for dump_last to work + # TODO: These settings should be elevated to config.ice histfreq_n=${histfreq_n:-6} dumpfreq_n=${dumpfreq_n:-1000} # Set this to a really large value, as cice, mom6 and cmeps restart interval is controlled by nems.configure dumpfreq=${dumpfreq:-"y"} # "h","d","m" or "y" for restarts at intervals of "hours", "days", "months" or "years" - cice_hist_avg=${cice_hist_avg:-".true."} + + if [[ "${CDUMP}" == "gdas" ]]; then + cice_hist_avg=".false." # DA needs instantaneous + elif [[ "${CDUMP}" == "gfs" ]]; then + cice_hist_avg=".true." # P8 wants averaged over histfreq_n + fi FRAZIL_FWSALT=${FRAZIL_FWSALT:-".true."} ktherm=${ktherm:-2} @@ -1005,12 +1006,7 @@ CICE_postdet() { # Copy/link CICE IC to DATA if [[ "${MODE}" = 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only - if [[ "${warm_start}" = '.true.' ]]; then - local res_dir=${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ice/RESTART - else - local res_dir=${ROTDIR}/${CDUMP}.${PDY}/${cyc}/ice/RESTART - fi - $NLN "${res_dir}/${PDY}.${cyc}0000.cice_model.res.nc" "${DATA}/cice_model.res.nc" + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ice/RESTART/${PDY}.${cyc}0000.cice_model.res.nc" "${DATA}/cice_model.res.nc" else $NCP -p $ICSDIR/$CDATE/ice/cice_model_${ICERESdec}.res_$CDATE.nc $DATA/cice_model.res.nc fi @@ -1026,6 +1022,7 @@ CICE_postdet() { # Link CICE output files [[ ! -d $COMOUTice ]] && mkdir -p $COMOUTice + mkdir -p ${COMOUTice}/RESTART if [[ "${CDUMP}" = "gfs" ]]; then # Link output files for CDUMP = gfs @@ -1048,32 +1045,43 @@ CICE_postdet() { SS=$((10#$HH*3600)) if [[ 10#$fhr -eq 0 ]]; then - $NLN $COMOUTice/iceic$VDATE.$ENSMEM.$IDATE.nc $DATA/history/iceh_ic.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc + $NLN $COMOUTice/iceic$VDATE.$ENSMEM.$IDATE.nc $DATA/CICE_OUTPUT/iceh_ic.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc else - (( interval = fhr - last_fhr )) - $NLN $COMOUTice/ice$VDATE.$ENSMEM.$IDATE.nc $DATA/history/iceh_$(printf "%0.2d" $interval)h.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc + (( interval = fhr - last_fhr )) # Umm.. isn't this histfreq_n? + $NLN $COMOUTice/ice$VDATE.$ENSMEM.$IDATE.nc $DATA/CICE_OUTPUT/iceh_$(printf "%0.2d" $interval)h.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc fi last_fhr=$fhr done elif [[ "${CDUMP}" = "gdas" ]]; then - # Link output files for CDUMP = gdas - echo "Link CICE forecast output files for CDUMP = gdas" + # Link CICE generated initial condition file from DATA/CICE_OUTPUT to COMOUTice + # This can be thought of as the f000 output from the CICE model + local seconds=$(to_seconds ${CDATE:8:2}0000) # convert HHMMSS to seconds + $NLN "${COMOUTice}/${CDUMP}.t${cyc}z.iceic.nc" "${DATA}/CICE_OUTPUT/iceh_ic.${CDATE:0:4}-${CDATE:4:2}-${CDATE:6:2}-${seconds}.nc" + + # Link instantaneous CICE forecast output files from DATA/CICE_OUTPUT to COMOUTice + local fhr="${FHOUT}" + while [[ "${fhr}" -le "${FHMAX}" ]]; do + local idate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${fhr} hours" +%Y%m%d%H) + local seconds=$(to_seconds ${idate:8:2}0000) # convert HHMMSS to seconds + local fhr3=$(printf %03i ${fhr}) + $NLN "${COMOUTice}/${CDUMP}.t${cyc}z.icef${fhr3}.nc" "${DATA}/CICE_OUTPUT/iceh_inst.${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}.nc" + local fhr=$((fhr + FHOUT)) + done fi - # Link CICE restarts to COMOUTice/RESTART + # Link CICE restarts from CICE_RESTART to COMOUTice/RESTART # Loop over restart_interval and link restarts from DATA to COM - mkdir -p ${COMOUTice}/RESTART local res_int=$(echo ${restart_interval} | cut -d' ' -f1) # If this is a list, get the frequency. # This is bound to break w/ IAU - local rdate=$(${NDATE} ${FHMAX} ${CDATE}) - local idate=$(${NDATE} ${res_int} ${CDATE}) - while [[ $idate -le $rdate ]]; do - local seconds=$(to_seconds ${idate:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds + local rdate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${FHMAX} hours" +%Y%m%d%H) + local idate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${res_int} hours" +%Y%m%d%H) + while [[ ${idate} -le ${rdate} ]]; do + local seconds=$(to_seconds ${idate:8:2}0000) # convert HHMMSS to seconds local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" - $NLN "${COMOUTice}/RESTART/${idate:0:8}.${idate:8:2}0000.cice_model.res.nc" "${DATA}/RESTART/iced.${idatestr}.nc" - local idate=$(${NDATE} ${res_int} ${idate}) + $NLN "${COMOUTice}/RESTART/${idate:0:8}.${idate:8:2}0000.cice_model.res.nc" "${DATA}/CICE_RESTART/cice_model.res.${idatestr}.nc" + local idate=$(date -d "${idate:0:8} ${idate:8:2} + ${res_int} hours" +%Y%m%d%H) done } diff --git a/ush/forecast_predet.sh b/ush/forecast_predet.sh index 84c9ff4cf8..3d5ef4d5dc 100755 --- a/ush/forecast_predet.sh +++ b/ush/forecast_predet.sh @@ -17,7 +17,7 @@ to_seconds() { local hh=${hhmmss:0:2} local mm=${hhmmss:2:2} local ss=${hhmmss:4:2} - local seconds=$(((hh*3600+mm*60+ss))) + local seconds=$((10#${hh}*3600+10#${mm}*60+10#${ss})) local padded_seconds=$(printf "%05d" ${seconds}) echo ${padded_seconds} } @@ -301,24 +301,12 @@ WW3_predet(){ CICE_predet(){ echo "SUB ${FUNCNAME[0]}: CICE before run type determination" - if [ ! -d $ROTDIR ]; then mkdir -p $ROTDIR; fi - if [ ! -d $DATA ]; then mkdir -p $DATA; fi - if [ ! -d $DATA/RESTART ]; then mkdir -p $DATA/RESTART; fi - if [ ! -d $DATA/INPUT ]; then mkdir -p $DATA/INPUT; fi - if [ ! -d $DATA/restart ]; then mkdir -p $DATA/restart; fi - if [ ! -d $DATA/history ]; then mkdir -p $DATA/history; fi - if [ ! -d $DATA/OUTPUT ]; then mkdir -p $DATA/OUTPUT; fi + if [ ! -d $DATA/CICE_OUTPUT ]; then mkdir -p $DATA/CICE_OUTPUT; fi + if [ ! -d $DATA/CICE_RESTART ]; then mkdir -p $DATA/CICE_RESTART; fi } MOM6_predet(){ echo "SUB ${FUNCNAME[0]}: MOM6 before run type determination" - if [ ! -d $ROTDIR ]; then mkdir -p $ROTDIR; fi - if [ ! -d $DATA ]; then mkdir -p $DATA; fi - if [ ! -d $DATA/RESTART ]; then mkdir -p $DATA/RESTART; fi - if [ ! -d $DATA/INPUT ]; then mkdir -p $DATA/INPUT; fi - if [ ! -d $DATA/restart ]; then mkdir -p $DATA/restart; fi - if [ ! -d $DATA/history ]; then mkdir -p $DATA/history; fi - if [ ! -d $DATA/OUTPUT ]; then mkdir -p $DATA/OUTPUT; fi if [ ! -d $DATA/MOM6_OUTPUT ]; then mkdir -p $DATA/MOM6_OUTPUT; fi if [ ! -d $DATA/MOM6_RESTART ]; then mkdir -p $DATA/MOM6_RESTART; fi cd "${DATA}" || exit 8 diff --git a/ush/parsing_namelists_CICE.sh b/ush/parsing_namelists_CICE.sh index 1c160de017..a6524865b7 100755 --- a/ush/parsing_namelists_CICE.sh +++ b/ush/parsing_namelists_CICE.sh @@ -51,8 +51,8 @@ cat > ice_in < ice_in < Date: Fri, 27 Jan 2023 00:17:44 -0500 Subject: [PATCH 17/27] at 1/4 degree MOM has 4 additional restarts. update setup_expt.py to handle cold atmos and warm other ics --- ush/forecast_postdet.sh | 5 ++++- workflow/setup_expt.py | 30 ++++++++++++++++++++---------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 720bef0f66..41b8ef9d80 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -765,6 +765,7 @@ MOM6_postdet() { $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_1.nc" "${DATA}/INPUT/MOM.res_1.nc" $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_2.nc" "${DATA}/INPUT/MOM.res_2.nc" $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_3.nc" "${DATA}/INPUT/MOM.res_3.nc" + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_4.nc" "${DATA}/INPUT/MOM.res_4.nc" ;; esac else @@ -879,12 +880,13 @@ MOM6_postdet() { # Link ocean restarts from DATA to COM # Coarser than 1/2 degree has a single MOM restart $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res.nc" "${DATA}/MOM6_RESTART/MOM.res.nc" - # 1/4 degree resolution has 3 additional restarts + # 1/4 degree resolution has 4 additional restarts case ${OCNRES} in "025") $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_1.nc" "${DATA}/MOM6_RESTART/MOM.res_1.nc" $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_2.nc" "${DATA}/MOM6_RESTART/MOM.res_2.nc" $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_3.nc" "${DATA}/MOM6_RESTART/MOM.res_3.nc" + $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_4.nc" "${DATA}/MOM6_RESTART/MOM.res_4.nc" ;; *) ;; @@ -901,6 +903,7 @@ MOM6_postdet() { $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_1.nc" "${DATA}/MOM6_RESTART/MOM.res_1.${idatestr}-00-00.nc" $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_2.nc" "${DATA}/MOM6_RESTART/MOM.res_2.${idatestr}-00-00.nc" $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_3.nc" "${DATA}/MOM6_RESTART/MOM.res_3.${idatestr}-00-00.nc" + $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_4.nc" "${DATA}/MOM6_RESTART/MOM.res_4.${idatestr}-00-00.nc" ;; esac local idate=$(date -d "${idate:0:8} ${idate:8:2} + ${res_int} hours" +%Y%m%d%H) diff --git a/workflow/setup_expt.py b/workflow/setup_expt.py index 7999e3d004..b1aa7096a7 100755 --- a/workflow/setup_expt.py +++ b/workflow/setup_expt.py @@ -65,13 +65,16 @@ def fill_COMROT_cycled(host, inputs): print("User did not provide path to stage initial conditions in COMROT") return - if inputs.start in ['warm']: # This is warm start experiment - idatestr = datetime_to_YMDH(inputs.idate - to_timedelta('T06H')) - atmos_dir = ocean_dir = ice_dir = med_dir = 'RESTART' + rdatestr = datetime_to_YMDH(inputs.idate - to_timedelta('T06H')) + idatestr = datetime_to_YMDH(inputs.idate) + + if inputs.start in ['warm']: # This is warm start experiment (only meaningful for atmos) + atmos_dir = med_dir = 'RESTART' elif inputs.start in ['cold']: # This is a cold start experiment - idatestr = datetime_to_YMDH(inputs.idate) atmos_dir = 'INPUT' - # ocean_dir, ice_dir TBD for cold start cases + med_dir = '' # no mediator files for a "cold start" + do_med = False + ocean_dir = ice_dir = 'RESTART' # ocean and ice have the same filenames for warm and cold def link_files_from_src_to_dst(src_dir, dst_dir): files = os.listdir(src_dir) @@ -82,8 +85,10 @@ def link_files_from_src_to_dst(src_dir, dst_dir): # Link ensemble member initial conditions if inputs.nens > 0: - enkfdir = f'enkf{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' - makedirs_if_missing(os.path.join(comrot, enkfdir)) + if inputs.start in ['warm']: + enkfdir = f'enkf{inputs.cdump}.{rdatestr[:8]}/{rdatestr[8:]}' + elif inputs.start in ['cold']: + enkfdir = f'enkf{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' for ii in range(1, inputs.nens + 1): memdir = f'mem{ii:03d}' @@ -95,10 +100,13 @@ def link_files_from_src_to_dst(src_dir, dst_dir): # ocean, ice, etc. TBD ... # Link deterministic initial conditions - detdir = f'{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' - makedirs_if_missing(os.path.join(comrot, detdir)) # Link atmospheric files + if inputs.start in ['warm']: + detdir = f'{inputs.cdump}.{rdatestr[:8]}/{rdatestr[8:]}' + elif inputs.start in ['cold']: + detdir = f'{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' + dst_dir = os.path.join(comrot, detdir, 'atmos', atmos_dir) src_dir = os.path.join(inputs.icsdir, detdir, 'atmos', atmos_dir) makedirs_if_missing(dst_dir) @@ -106,6 +114,7 @@ def link_files_from_src_to_dst(src_dir, dst_dir): # Link ocean files if do_ocean: + detdir = f'{inputs.cdump}.{rdatestr[:8]}/{rdatestr[8:]}' dst_dir = os.path.join(comrot, detdir, 'ocean', ocean_dir) src_dir = os.path.join(inputs.icsdir, detdir, 'ocean', ocean_dir) makedirs_if_missing(dst_dir) @@ -113,6 +122,7 @@ def link_files_from_src_to_dst(src_dir, dst_dir): # Link ice files if do_ice: + detdir = f'{inputs.cdump}.{rdatestr[:8]}/{rdatestr[8:]}' dst_dir = os.path.join(comrot, detdir, 'ice', ice_dir) src_dir = os.path.join(inputs.icsdir, detdir, 'ice', ice_dir) makedirs_if_missing(dst_dir) @@ -120,13 +130,13 @@ def link_files_from_src_to_dst(src_dir, dst_dir): # Link mediator files if do_med: + detdir = f'{inputs.cdump}.{rdatestr[:8]}/{rdatestr[8:]}' dst_dir = os.path.join(comrot, detdir, 'med', med_dir) src_dir = os.path.join(inputs.icsdir, detdir, 'med', med_dir) makedirs_if_missing(dst_dir) link_files_from_src_to_dst(src_dir, dst_dir) # Link bias correction and radiance diagnostics files - idatestr = datetime_to_YMDH(inputs.idate) detdir = f'{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' src_dir = os.path.join(inputs.icsdir, detdir, 'atmos') dst_dir = os.path.join(comrot, detdir, 'atmos') From 44ceaafe9588519b0fc7a52a9abec7c0b0c0dc65 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Fri, 27 Jan 2023 16:41:54 -0500 Subject: [PATCH 18/27] update mediator restart file logic triggering runtype. --- ush/forecast_postdet.sh | 19 +++++++++++++------ ush/forecast_predet.sh | 4 ++-- ush/nems_configure.sh | 6 +++++- ush/parsing_namelists_CICE.sh | 17 ++++++++--------- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 41b8ef9d80..41f48f21ac 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -788,14 +788,21 @@ MOM6_postdet() { if [[ "${warm_start}" = '.true.' ]]; then local mediator_file="${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/med/RESTART/${PDY}.${cyc}0000.ufs.cpld.cpl.r.nc" if [[ -f "${mediator_file}" ]]; then - $NLN "${mediator_file}" "${DATA}/ufs.cpld.cpl.r.nc" - rm -f "${DATA}/rpointer.cpl" - touch "${DATA}/rpointer.cpl" - echo "ufs.cpld.cpl.r.nc" >> "${DATA}/rpointer.cpl" + $NLN "${mediator_file}" "${DATA}/ufs.cpld.cpl.r.nc" + rm -f "${DATA}/rpointer.cpl" + touch "${DATA}/rpointer.cpl" + echo "ufs.cpld.cpl.r.nc" >> "${DATA}/rpointer.cpl" else - echo "FATAL ERROR: ${mediator_file} must exist for warm_start = .true. and does not, ABORT!" - exit 4 + # We have a choice to make here. + # Either we can FATAL ERROR out, or we can let the coupling fields initialize from zero + # cmeps_run_type is determined based on the availability of the mediator restart file + echo "WARNING: ${mediator_file} does not exist for warm_start = .true., initializing!" + #echo "FATAL ERROR: ${mediator_file} must exist for warm_start = .true. and does not, ABORT!" + #exit 4 fi + else + # This is a cold start, so initialize the coupling fields from zero + export cmeps_run_type="startup" fi # TODO: some documentation would be nice to see here, e.g. whose phone number is in here? diff --git a/ush/forecast_predet.sh b/ush/forecast_predet.sh index 3d5ef4d5dc..976a3decab 100755 --- a/ush/forecast_predet.sh +++ b/ush/forecast_predet.sh @@ -232,7 +232,7 @@ FV3_GFS_predet(){ RSTDIR_ATM=${RSTDIR_ATM:-${ROTDIR}/${CDUMP}.${PDY}/${cyc}/atmos/RERUN_RESTART} if [ ! -d $RSTDIR_ATM ]; then mkdir -p $RSTDIR_ATM ; fi $NLN $RSTDIR_ATM RESTART - if [[ $(( ${FHMAX_GFS} % ${restart_interval_gfs} )) == 0 ]]; then + #if [[ $(( ${FHMAX_GFS} % ${restart_interval_gfs} )) == 0 ]]; then # TODO: Xianwu's hotfix will remove this if statement # The final restart written at the end doesn't include the valid date # Create links that keep the same name pattern for these files VDATE=$($NDATE +$FHMAX_GFS $CDATE) @@ -247,7 +247,7 @@ FV3_GFS_predet(){ for file in $files; do $NLN $RSTDIR_ATM/$file $RSTDIR_ATM/${vPDY}.${vcyc}0000.$file done - fi + #fi # TODO: Xianwu's hotfix will remove this fi statement else mkdir -p $DATA/RESTART fi diff --git a/ush/nems_configure.sh b/ush/nems_configure.sh index a2f687b7b5..c49d35a2c0 100755 --- a/ush/nems_configure.sh +++ b/ush/nems_configure.sh @@ -19,7 +19,11 @@ fi # Setup nems.configure DumpFields=${NEMSDumpFields:-false} cap_dbug_flag=${cap_dbug_flag:-0} -if [ $warm_start = ".true." ]; then +# Determine "cmeps_run_type" based on the availability of the mediator restart file +# If it is a warm_start, we already copied the mediator restart to DATA, if it was present +# If the mediator restart was not present, despite being a "warm_start", we put out a WARNING +# in forecast_postdet.sh +if [[ -f "${DATA}/ufs.cpld.cpl.r.nc" ]]; then cmeps_run_type='continue' else cmeps_run_type='startup' diff --git a/ush/parsing_namelists_CICE.sh b/ush/parsing_namelists_CICE.sh index a6524865b7..387b9ad03f 100755 --- a/ush/parsing_namelists_CICE.sh +++ b/ush/parsing_namelists_CICE.sh @@ -4,11 +4,10 @@ CICE_namelists(){ -if [ $warm_start = ".true." ]; then - cmeps_run_type='continue' -else - cmeps_run_type='initial' -fi +# There is no chance that the workflow will try and spin-up CICE, +# so, runtype should always be "continue" as the ICs +# will be read from the initial condition file mentioned in "pointer_file" +local runtype="continue" # Get correct MPI options for NPROC and grid local cice_processor_shape=${cice_processor_shape:-'slenderX2'} @@ -41,7 +40,7 @@ cat > ice_in < ice_in < ice_in < Date: Fri, 27 Jan 2023 16:56:06 -0500 Subject: [PATCH 19/27] remove debug statement from JGLOBAL_FORECAST --- jobs/JGLOBAL_FORECAST | 1 - 1 file changed, 1 deletion(-) diff --git a/jobs/JGLOBAL_FORECAST b/jobs/JGLOBAL_FORECAST index a7d50c1191..9027512761 100755 --- a/jobs/JGLOBAL_FORECAST +++ b/jobs/JGLOBAL_FORECAST @@ -1,7 +1,6 @@ #! /usr/bin/env bash source "${HOMEgfs}/ush/preamble.sh" -#export DATA=${DATAROOT}/debug_fcst # TODO: (RM) remove before PR source "${HOMEgfs}/ush/jjob_header.sh" -e "fcst" -c "base fcst" ############################################## From d8a14d7b608bd1efbfddc8b71322420629e6abca Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Fri, 27 Jan 2023 17:45:33 -0500 Subject: [PATCH 20/27] replace 4 lines with a loop --- ush/forecast_postdet.sh | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 41f48f21ac..bf98179ebc 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -762,10 +762,11 @@ MOM6_postdet() { $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res.nc" "${DATA}/INPUT/MOM.res.nc" case $OCNRES in "025") - $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_1.nc" "${DATA}/INPUT/MOM.res_1.nc" - $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_2.nc" "${DATA}/INPUT/MOM.res_2.nc" - $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_3.nc" "${DATA}/INPUT/MOM.res_3.nc" - $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_4.nc" "${DATA}/INPUT/MOM.res_4.nc" + for nn in $(seq 1 4); do + if [[ -f "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_${nn}.nc" ]]; then + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_${nn}.nc" "${DATA}/INPUT/MOM.res_${nn}.nc" + fi + done ;; esac else @@ -890,10 +891,9 @@ MOM6_postdet() { # 1/4 degree resolution has 4 additional restarts case ${OCNRES} in "025") - $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_1.nc" "${DATA}/MOM6_RESTART/MOM.res_1.nc" - $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_2.nc" "${DATA}/MOM6_RESTART/MOM.res_2.nc" - $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_3.nc" "${DATA}/MOM6_RESTART/MOM.res_3.nc" - $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_4.nc" "${DATA}/MOM6_RESTART/MOM.res_4.nc" + for nn in $(seq 1 4); do + $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_${nn}.nc" "${DATA}/MOM6_RESTART/MOM.res_${nn}.nc" + done ;; *) ;; @@ -907,10 +907,9 @@ MOM6_postdet() { $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res.nc" "${DATA}/MOM6_RESTART/MOM.res.${idatestr}-00-00.nc" case ${OCNRES} in "025") - $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_1.nc" "${DATA}/MOM6_RESTART/MOM.res_1.${idatestr}-00-00.nc" - $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_2.nc" "${DATA}/MOM6_RESTART/MOM.res_2.${idatestr}-00-00.nc" - $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_3.nc" "${DATA}/MOM6_RESTART/MOM.res_3.${idatestr}-00-00.nc" - $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_4.nc" "${DATA}/MOM6_RESTART/MOM.res_4.${idatestr}-00-00.nc" + for nn in $(seq 1 4); do + $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_${nn}.nc" "${DATA}/MOM6_RESTART/MOM.res_${nn}.${idatestr}-00-00.nc" + done ;; esac local idate=$(date -d "${idate:0:8} ${idate:8:2} + ${res_int} hours" +%Y%m%d%H) From 42beaf9deec754a2446ac5da24a20dad06daf37c Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Fri, 27 Jan 2023 22:49:39 -0500 Subject: [PATCH 21/27] allow atmDA cycling w/ FV3_GFS_v16 suite. allow CICE initialization for prototypes. --- ush/forecast_postdet.sh | 22 +++++++++------------- ush/parsing_namelists_CICE.sh | 21 ++++++++++++++++----- workflow/setup_expt.py | 15 ++++++++++----- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index bf98179ebc..219d7ddca9 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -49,7 +49,7 @@ FV3_GFS_postdet(){ done # Replace sfc_data with sfcanl_data restart files from $memdir (if found) - if [ "${MODE}" = "cycled" ] && [ "${APP}" = "ATM" ]; then # TODO: remove if-block when global_cycle can handle NOAHMP + if [ "${MODE}" = "cycled" ] && [ "${CCPP_SUITE}" = "FV3_GFS_v16" ]; then # TODO: remove if statement when global_cycle can handle NOAHMP for file in $(ls $memdir/RESTART/${sPDY}.${scyc}0000.sfcanl_data.tile?.nc); do if [[ -f $file ]]; then file2=$(echo $(basename $file)) @@ -770,7 +770,7 @@ MOM6_postdet() { ;; esac else - $NCP -pf "${ICSDIR}/${CDATE}/ocn/MOM*nc" "${DATA}/INPUT/" # TODO: Update files in ICSDIR to reflect COM structure naming convention + $NCP -pf "${ICSDIR}/${CDATE}"/ocn/MOM*.nc "${DATA}/INPUT/" # TODO: Update files in ICSDIR to reflect COM structure naming convention fi # Copy MOM6 fixed files @@ -966,6 +966,9 @@ MOM6_out() { CICE_postdet() { echo "SUB ${FUNCNAME[0]}: CICE after run type determination" + # TODO: move configuration settings to config.ice + + # TODO: These need to be calculated in the parsing_namelists_CICE.sh script CICE_namelists() function and set as local year=$(echo $CDATE|cut -c 1-4) month=$(echo $CDATE|cut -c 5-6) day=$(echo $CDATE|cut -c 7-8) @@ -994,20 +997,9 @@ CICE_postdet() { # restart_pond_lvl (if tr_pond_lvl=true): # -- if true, initialize the level ponds from restart (if runtype=continue) # -- if false, re-initialize level ponds to zero (if runtype=initial or continue) - - #TODO: Determine the proper way to determine if it's a 'hot start' or not - #note this is not mediator cold start or not - #if [ hotstart ]; then - # #continuing run "hot start" - # RUNTYPE='continue' - # USE_RESTART_TIME='.true.' - #fi - RUNTYPE='initial' - USE_RESTART_TIME='.false.' restart_pond_lvl=${restart_pond_lvl:-".false."} ICERES=${ICERES:-"025"} # TODO: similar to MOM_out, lift this higher - ICERESdec=echo "$ICERES" | awk '{printf "%0.2f", $1/100}' ice_grid_file=${ice_grid_file:-"grid_cice_NEMS_mx${ICERES}.nc"} ice_kmt_file=${ice_kmt_file:-"kmtu_cice_NEMS_mx${ICERES}.nc"} @@ -1017,6 +1009,7 @@ CICE_postdet() { if [[ "${MODE}" = 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ice/RESTART/${PDY}.${cyc}0000.cice_model.res.nc" "${DATA}/cice_model.res.nc" else + ICERESdec=$(echo "${ICERES}" | awk '{printf "%0.2f", $1/100}') $NCP -p $ICSDIR/$CDATE/ice/cice_model_${ICERESdec}.res_$CDATE.nc $DATA/cice_model.res.nc fi # TODO: add a check for the restarts to exist, if not, exit eloquently @@ -1036,6 +1029,9 @@ CICE_postdet() { if [[ "${CDUMP}" = "gfs" ]]; then # Link output files for CDUMP = gfs + # TODO: make these forecast output files consistent w/ GFS output + # TODO: Work w/ NB to determine appropriate naming convention for these files + export ENSMEM=${ENSMEM:-01} export IDATE=$CDATE diff --git a/ush/parsing_namelists_CICE.sh b/ush/parsing_namelists_CICE.sh index 387b9ad03f..dc91efd666 100755 --- a/ush/parsing_namelists_CICE.sh +++ b/ush/parsing_namelists_CICE.sh @@ -4,10 +4,21 @@ CICE_namelists(){ -# There is no chance that the workflow will try and spin-up CICE, -# so, runtype should always be "continue" as the ICs -# will be read from the initial condition file mentioned in "pointer_file" -local runtype="continue" +# "warm_start" here refers to whether CICE model is warm starting or not. +# In the case of the Prototypes, the CICE ICs were obtained from Travis Sluka. +# Travis's system was using SIS2, so the prototypes always set this to "initial" +# in order for the CICE model to _initialize_ from the SIS2 ICs. +# However, in the SOCA cycled system, if starting from a previously cycled SOCA run, +# the CICE ICs are obtained from the previous cycle of the UFS S2S, +# so the CICE namelist should be set to "continue" +# TODO: confirm w/ NB and GV +if [[ "${warm_start}" = ".true." ]]; then + local runtype="continue" + local use_restart_time=".true." +else + local runtype="initial" + local use_restart_time=".false." +fi # Get correct MPI options for NPROC and grid local cice_processor_shape=${cice_processor_shape:-'slenderX2'} @@ -45,7 +56,7 @@ cat > ice_in < Date: Mon, 30 Jan 2023 10:42:57 -0500 Subject: [PATCH 22/27] remove SIS2 comment attribute to Travis --- ush/parsing_namelists_CICE.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ush/parsing_namelists_CICE.sh b/ush/parsing_namelists_CICE.sh index dc91efd666..90f60c5719 100755 --- a/ush/parsing_namelists_CICE.sh +++ b/ush/parsing_namelists_CICE.sh @@ -5,13 +5,15 @@ CICE_namelists(){ # "warm_start" here refers to whether CICE model is warm starting or not. -# In the case of the Prototypes, the CICE ICs were obtained from Travis Sluka. -# Travis's system was using SIS2, so the prototypes always set this to "initial" +# Per JM, in the case of the Prototypes, the sea-ice ICs were obtained from CPC. +# CPC sea-ice initial conditions are created from SIS2 sea-ice model. +# Hence, the prototypes always set this to "initial" # in order for the CICE model to _initialize_ from the SIS2 ICs. # However, in the SOCA cycled system, if starting from a previously cycled SOCA run, # the CICE ICs are obtained from the previous cycle of the UFS S2S, # so the CICE namelist should be set to "continue" -# TODO: confirm w/ NB and GV +# TODO: Is there a way to interrogate the restart file to know if this is a +# SIS2 restart or a CICE restart, instead of relying on "${warm_start}" if [[ "${warm_start}" = ".true." ]]; then local runtype="continue" local use_restart_time=".true." From 0254f89db0b5560b48deb8193b163e2e36fa547c Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Mon, 30 Jan 2023 11:06:32 -0500 Subject: [PATCH 23/27] update .gitignore to hold off adding nohup.out --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4f2d103a02..79607e39fd 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ __pycache__ *.sw[a-p] ._* .DS_Store -nohup.out +#nohup.out - some users do not want this to be a part of .gitignore. TODO: review against best practices .idea/ .vscode/ From 8afd36ab56069fb474e20c56dd6adadbddda5596 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Mon, 30 Jan 2023 13:58:18 -0500 Subject: [PATCH 24/27] explain why using largest signed int --- ush/forecast_postdet.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 219d7ddca9..5cc26fd9cf 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -806,7 +806,8 @@ MOM6_postdet() { export cmeps_run_type="startup" fi - # TODO: some documentation would be nice to see here, e.g. whose phone number is in here? + # If using stochatic parameterizations, create a seed that does not exceed the + # largest signed integer if [ $DO_OCN_SPPT = "YES" -o $DO_OCN_PERT_EPBL = "YES" ]; then if [ ${SET_STP_SEED:-"YES"} = "YES" ]; then ISEED_OCNSPPT=$(( (CDATE*1000 + MEMBER*10 + 6) % 2147483647 )) From 75165f7931e2c1a383fcba77cdf09844feaf8c58 Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Mon, 30 Jan 2023 16:19:32 -0500 Subject: [PATCH 25/27] undo permissions change from previous PR merge --- parm/config/config.aero | 0 parm/config/config.aerosol_init | 0 parm/config/config.defaults.s2sw | 0 parm/config/config.ice | 0 parm/config/config.ocn | 0 parm/config/config.ocnanal | 0 parm/config/config.ocnanalpost | 0 parm/config/config.ocnanalrun | 0 parm/config/config.sfcanl | 0 9 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 parm/config/config.aero mode change 100755 => 100644 parm/config/config.aerosol_init mode change 100755 => 100644 parm/config/config.defaults.s2sw mode change 100755 => 100644 parm/config/config.ice mode change 100755 => 100644 parm/config/config.ocn mode change 100755 => 100644 parm/config/config.ocnanal mode change 100755 => 100644 parm/config/config.ocnanalpost mode change 100755 => 100644 parm/config/config.ocnanalrun mode change 100755 => 100644 parm/config/config.sfcanl diff --git a/parm/config/config.aero b/parm/config/config.aero old mode 100755 new mode 100644 diff --git a/parm/config/config.aerosol_init b/parm/config/config.aerosol_init old mode 100755 new mode 100644 diff --git a/parm/config/config.defaults.s2sw b/parm/config/config.defaults.s2sw old mode 100755 new mode 100644 diff --git a/parm/config/config.ice b/parm/config/config.ice old mode 100755 new mode 100644 diff --git a/parm/config/config.ocn b/parm/config/config.ocn old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanal b/parm/config/config.ocnanal old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanalpost b/parm/config/config.ocnanalpost old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanalrun b/parm/config/config.ocnanalrun old mode 100755 new mode 100644 diff --git a/parm/config/config.sfcanl b/parm/config/config.sfcanl old mode 100755 new mode 100644 From 54aea10bc8e854dd16156b591ce55b0826b94c8e Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Tue, 31 Jan 2023 10:17:44 -0500 Subject: [PATCH 26/27] undo perms on config --- parm/config/config.aero | 0 parm/config/config.aerosol_init | 0 parm/config/config.defaults.s2sw | 0 parm/config/config.ice | 0 parm/config/config.ocn | 0 parm/config/config.ocnanal | 0 parm/config/config.ocnanalpost | 0 parm/config/config.ocnanalrun | 0 parm/config/config.sfcanl | 0 9 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 parm/config/config.aero mode change 100755 => 100644 parm/config/config.aerosol_init mode change 100755 => 100644 parm/config/config.defaults.s2sw mode change 100755 => 100644 parm/config/config.ice mode change 100755 => 100644 parm/config/config.ocn mode change 100755 => 100644 parm/config/config.ocnanal mode change 100755 => 100644 parm/config/config.ocnanalpost mode change 100755 => 100644 parm/config/config.ocnanalrun mode change 100755 => 100644 parm/config/config.sfcanl diff --git a/parm/config/config.aero b/parm/config/config.aero old mode 100755 new mode 100644 diff --git a/parm/config/config.aerosol_init b/parm/config/config.aerosol_init old mode 100755 new mode 100644 diff --git a/parm/config/config.defaults.s2sw b/parm/config/config.defaults.s2sw old mode 100755 new mode 100644 diff --git a/parm/config/config.ice b/parm/config/config.ice old mode 100755 new mode 100644 diff --git a/parm/config/config.ocn b/parm/config/config.ocn old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanal b/parm/config/config.ocnanal old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanalpost b/parm/config/config.ocnanalpost old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanalrun b/parm/config/config.ocnanalrun old mode 100755 new mode 100644 diff --git a/parm/config/config.sfcanl b/parm/config/config.sfcanl old mode 100755 new mode 100644 From 7686cea8f4c6339c80ec4cda78f6459a9823acfa Mon Sep 17 00:00:00 2001 From: Rahul Mahajan Date: Tue, 31 Jan 2023 15:23:59 -0500 Subject: [PATCH 27/27] when running in forecast-only mode, restart_interval_gfs=0 has implications on mediator restarts --- ush/forecast_postdet.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 5cc26fd9cf..2db53c5c53 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -959,7 +959,12 @@ MOM6_out() { while [[ $idate -le $rdate ]]; do local seconds=$(to_seconds ${idate:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" - $NCP "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" "${COMOUTmed}/RESTART/${idate:0:8}.${idate:8:2}0000.ufs.cpld.cpl.r.nc" + local mediator_file="${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" + if [[ -f ${mediator_file} ]]; then + $NCP "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" "${COMOUTmed}/RESTART/${idate:0:8}.${idate:8:2}0000.ufs.cpld.cpl.r.nc" + else + echo "Mediator restart ${mediator_file} not found." + fi local idate=$(date -d "${idate:0:8} ${idate:8:2} + ${res_int} hours" +%Y%m%d%H) done }