From 6db4fe9f9796fe95995d0049da741dcfd03c6aee Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Fri, 31 Oct 2025 22:59:18 +0000 Subject: [PATCH 01/22] Copy from feature/enkf_only --- dev/jobs/prep.sh | 13 ++++++ dev/parm/config/gfs/config.base.j2 | 13 ++++++ dev/parm/config/gfs/config.com | 4 ++ dev/parm/config/gfs/config.esfc | 5 +++ dev/parm/config/gfs/config.prep | 5 +++ dev/parm/config/gfs/yaml/defaults.yaml | 1 + dev/workflow/applications/gfs_cycled.py | 28 +++++++++--- dev/workflow/rocoto/gfs_tasks.py | 55 ++++++++++++++--------- jobs/JGDAS_ENKF_SELECT_OBS | 48 ++++++++++++++------ jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE | 19 +++++++- parm/archive/enkf.yaml.j2 | 57 +++++++++++++++++------- parm/archive/enkf_grp.yaml.j2 | 13 ++++-- parm/archive/enkf_restarta_grp.yaml.j2 | 6 +++ parm/stage/analysis.yaml.j2 | 42 ++++++++++++++--- parm/stage/atmosphere_cold.yaml.j2 | 18 ++++++++ parm/stage/master_gfs.yaml.j2 | 4 ++ scripts/exgdas_enkf_earc_tars.py | 3 +- scripts/exglobal_stage_ic.py | 3 +- sorc/gdas.cd | 2 +- ush/python/pygfs/task/atmens_analysis.py | 2 + 20 files changed, 271 insertions(+), 70 deletions(-) diff --git a/dev/jobs/prep.sh b/dev/jobs/prep.sh index 4ab3c6795ee..bde30e0c70d 100755 --- a/dev/jobs/prep.sh +++ b/dev/jobs/prep.sh @@ -115,6 +115,19 @@ export COMINgfs=${COMIN_ATMOS_HISTORY_GFS} export COMSP=${COMSP:-"${COMIN_OBS}/${RUN_local}.t${cyc}z."} +if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then + RUN="enkfgdas" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx COMIN_ENKF_ATMOS_HISTORY_GDAS_PREV:COM_ENS_ATMOS_HISTORY_TMPL + RUN="enkfgdas" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx COMIN_ENKF_MEM001_ATMOS_HISTORY_GDAS_PREV:COM_ENS_MEM001_ATMOS_HISTORY_TMPL + RUN="gdas" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx COMIN_ATMOS_HISTORY_GDAS_PREV:COM_ATMOS_HISTORY_TMPL + mkdir -p $COMIN_ATMOS_HISTORY_GDAS_PREV + ln -sf $COMIN_ENKF_MEM001_ATMOS_HISTORY_GDAS_PREV/enkfgdas.t${gcyc}z.log.f003.txt $COMIN_ATMOS_HISTORY_GDAS_PREV/gdas.t${gcyc}z.log.f003.txt + ln -sf $COMIN_ENKF_MEM001_ATMOS_HISTORY_GDAS_PREV/enkfgdas.t${gcyc}z.log.f006.txt $COMIN_ATMOS_HISTORY_GDAS_PREV/gdas.t${gcyc}z.log.f006.txt + ln -sf $COMIN_ENKF_MEM001_ATMOS_HISTORY_GDAS_PREV/enkfgdas.t${gcyc}z.log.f009.txt $COMIN_ATMOS_HISTORY_GDAS_PREV/gdas.t${gcyc}z.log.f009.txt + ln -sf $COMIN_ENKF_ATMOS_HISTORY_GDAS_PREV/enkfgdas.t${gcyc}z.ensmean.atm.f003.nc $COMIN_ATMOS_HISTORY_GDAS_PREV/gdas.t${gcyc}z.atm.f003.nc + ln -sf $COMIN_ENKF_ATMOS_HISTORY_GDAS_PREV/enkfgdas.t${gcyc}z.ensmean.atm.f006.nc $COMIN_ATMOS_HISTORY_GDAS_PREV/gdas.t${gcyc}z.atm.f006.nc + ln -sf $COMIN_ENKF_ATMOS_HISTORY_GDAS_PREV/enkfgdas.t${gcyc}z.ensmean.atm.f009.nc $COMIN_ATMOS_HISTORY_GDAS_PREV/gdas.t${gcyc}z.atm.f009.nc +fi + # Create or Copy prepbufr, prepbufr.acft_profiles, nsstbufr files # Do not fail on external errors if [[ ${MAKE_PREPBUFR:-"YES"} == "YES" ]]; then diff --git a/dev/parm/config/gfs/config.base.j2 b/dev/parm/config/gfs/config.base.j2 index ead9840c1c6..c2ae27a9f89 100644 --- a/dev/parm/config/gfs/config.base.j2 +++ b/dev/parm/config/gfs/config.base.j2 @@ -389,6 +389,7 @@ export DO_CALC_INCREMENT="NO" export NMEM_ENS_GFS="{{ NMEM_ENS_GFS }}" export NMEM_ENS_GFS_OFFSET="{{ NMEM_ENS_GFS_OFFSET }}" export DO_CALC_INCREMENT_ENKF_GFS="NO" +export DOENKFONLY_ATM="{{ DOENKFONLY_ATM }}" # EnKF output frequency if [[ "${DOHYBVAR}" = "YES" ]]; then @@ -507,6 +508,18 @@ if [[ "${machine}" == "URSA" || "${machine}" == "GAEAC6" || "${machine}" == "ORI export DO_METP=NO fi +if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then + export RECENTER_ENKF="NO" # Turn off recentering ensemble analysis + export DO_VERFOZN="NO" # Ozone data assimilation monitoring + export DO_VERFRAD="NO" # Radiance data assimilation monitoring + export DO_VMINMON="NO" # GSI minimization monitoring + export DO_METP="NO" # Run METPLUS jobs - set METPLUS settings in config.metp + export DO_FIT2OBS="NO" # Run fit to observations package + export DO_TRACKER="NO" # Hurricane track verification + export DO_GENESIS="NO" # Cyclone genesis verification + export GSIBIAS="/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/Data/testSatBiasConverter/output" +fi + # If starting ICs that are not at cycle hour export OFFSET_START_HOUR=0 diff --git a/dev/parm/config/gfs/config.com b/dev/parm/config/gfs/config.com index bba449b0db3..88c2995eb97 100644 --- a/dev/parm/config/gfs/config.com +++ b/dev/parm/config/gfs/config.com @@ -48,6 +48,7 @@ declare -rx COM_OBS_TMPL='${ROTDIR}/${RUN}.${YMD}/${HH}/obs' declare -rx COM_OBSPROC_TMPL COM_RTOFS_TMPL COM_BASE='${ROTDIR}/${RUN}.${YMD}/${HH}/${MEMDIR}' +COM_BASE_NOMEM='${ROTDIR}/${RUN}.${YMD}/${HH}/' declare -rx COM_TOP_TMPL='${ROTDIR}/${RUN}.${YMD}/${HH}' @@ -57,9 +58,12 @@ declare -rx COM_OBS_JEDI=${COM_BASE}'/obs_jedi' declare -rx COM_ATMOS_INPUT_TMPL=${COM_BASE}'/model/atmos/input' declare -rx COM_ATMOS_RESTART_TMPL=${COM_BASE}'/model/atmos/restart' declare -rx COM_ATMOS_ANALYSIS_TMPL=${COM_BASE}'/analysis/atmos' +declare -rx COM_ENS_ATMOS_ANALYSIS_TMPL=${COM_BASE_NOMEM}'/ensstat/analysis/atmos' declare -rx COM_SNOW_ANALYSIS_TMPL=${COM_BASE}'/analysis/snow' declare -rx COM_SNOW_ANLMON_TMPL=${COM_BASE}'/products/snow/anlmon' declare -rx COM_ATMOS_HISTORY_TMPL=${COM_BASE}'/model/atmos/history' +declare -rx COM_ENS_ATMOS_HISTORY_TMPL=${COM_BASE}'/ensstat/model/atmos/history' +declare -rx COM_ENS_MEM001_ATMOS_HISTORY_TMPL=${COM_BASE}'/mem001/model/atmos/history' declare -rx COM_ATMOS_MASTER_TMPL=${COM_BASE}'/model/atmos/master' declare -rx COM_ATMOS_GRIB_TMPL=${COM_BASE}'/products/atmos/grib2' declare -rx COM_ATMOS_GRIB_GRID_TMPL=${COM_ATMOS_GRIB_TMPL}'/${GRID}' diff --git a/dev/parm/config/gfs/config.esfc b/dev/parm/config/gfs/config.esfc index 156649ace36..50ddfd31c35 100644 --- a/dev/parm/config/gfs/config.esfc +++ b/dev/parm/config/gfs/config.esfc @@ -26,6 +26,11 @@ if [[ "${DO_JEDIATMENS}" == "YES" ]]; then export DONST="NO" fi +# Turn off NST if DOENKFONLY_ATM is YES +if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then + export DONST="NO" +fi + if [[ "${RUN/enkf}" == "gfs" ]]; then echo "turning off gsi soilda for gfs run" DO_GSISOILDA="NO" diff --git a/dev/parm/config/gfs/config.prep b/dev/parm/config/gfs/config.prep index c10e5012e76..d150f2336e5 100644 --- a/dev/parm/config/gfs/config.prep +++ b/dev/parm/config/gfs/config.prep @@ -15,6 +15,11 @@ export PROCESS_TROPCY=${PROCESS_TROPCY:-NO} export TROPCYQCRELOSH="${SCRgfs}/exglobal_atmos_tropcy_qc_reloc.sh" export COMINsyn=${COMINsyn:-$(compath.py "${envir}/com/gfs/${gfs_ver}")/syndat} +# If DOENKFONLY_ATM="YES", skip PROCESS_TROPCY +if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then + export PROCESS_TROPCY="NO" +fi + # Allow users to control the generation or use of either operational or # their processed prepbufr, prepbufr.acft_profiles, nsstbufr files export MAKE_PREPBUFR="YES" # Generate prepbufr, etc. files by executing obsproc diff --git a/dev/parm/config/gfs/yaml/defaults.yaml b/dev/parm/config/gfs/yaml/defaults.yaml index 15ed548d145..b76dcb8ca93 100644 --- a/dev/parm/config/gfs/yaml/defaults.yaml +++ b/dev/parm/config/gfs/yaml/defaults.yaml @@ -24,6 +24,7 @@ base: FHMAX_ENKF_GFS: 12 DOHYBVAR_OCN: "NO" DOLETKF_OCN: "NO" + DOENKFONLY_ATM: "NO" DO_TEST_MODE: "NO" NMEM_ENS_GFS: 30 NMEM_ENS_GFS_OFFSET: 20 diff --git a/dev/workflow/applications/gfs_cycled.py b/dev/workflow/applications/gfs_cycled.py index 8a5114c1f82..b197a091ac8 100644 --- a/dev/workflow/applications/gfs_cycled.py +++ b/dev/workflow/applications/gfs_cycled.py @@ -73,6 +73,7 @@ def _get_run_options(self, conf: Configuration) -> Dict[str, Any]: run_options[run]['do_hybvar'] = base.get('DOHYBVAR', False) run_options[run]['do_hybvar_ocn'] = base.get('DOHYBVAR_OCN', False) + run_options[run]['do_enkfonly_atm'] = base.get('DOENKFONLY_ATM', False) run_options[run]['do_letkf_ocn'] = base.get('DOLETKF_OCN', False) run_options[run]['nens'] = base.get('NMEM_ENS', 0) if run_options[run]['do_hybvar']: @@ -377,22 +378,38 @@ def get_task_names(self): task_names[run] += ['cleanup'] + # Remove unnecessary tasks if do_enkfonly_atm=true + if options['do_enkfonly_atm']: + rmtasks=['anlstat', 'sfcanl', 'analcalc', 'fcst', 'atmanlprod', 'stage_ic', 'arch_tars', 'arch_vrfy', 'atmos_prod', 'atmanlupp', 'cleanup'] + if options['do_jediatmvar']: + rmtasks.extend(['atmanlinit', 'atmanlvar', 'atmanlfv3inc', 'atmanlfinal', 'analcalc_fv3jedi']) + else: + rmtasks.extend(['anal', 'analdiag', 'analcalc']) + for task in rmtasks: + if task in task_names['gdas']: + task_names['gdas'].remove(task) + # Ensemble tasks elif 'enkf' in run: task_names[run] += ['stage_ic'] if options['do_jediatmens']: - task_names[run] += ['atmensanlinit', 'atmensanlfv3inc', 'atmensanlfinal', 'ecen_fv3jedi'] + if options['do_enkfonly_atm']: + task_names[run] += ['atmensanlinit', 'atmensanlfv3inc', 'atmensanlfinal'] + else: + task_names[run] += ['atmensanlinit', 'atmensanlfv3inc', 'atmensanlfinal', 'ecen_fv3jedi'] if options['lobsdiag_forenkf']: task_names[run] += ['atmensanlobs', 'atmensanlsol'] else: task_names[run] += ['atmensanlletkf'] - task_names[run].append('efcs') if 'gdas' in run else 0 - task_names[run].append('epos') if 'gdas' in run else 0 + if not options['do_enkfonly_atm']: + task_names[run].append('efcs') if 'gdas' in run else 0 + task_names[run].append('epos') if 'gdas' in run else 0 else: task_names[run] += ['eobs', 'eupd', 'ecen'] - task_names[run].append('echgres') if 'gdas' in run else 0 + if not options['do_enkfonly_atm']: + task_names[run].append('echgres') if 'gdas' in run else 0 task_names[run] += ['ediag'] if options['do_jediocnvar']: @@ -406,7 +423,8 @@ def get_task_names(self): task_names[run].append('epos') if 'gdas' in run else 0 task_names[run] += ['esfc'] - task_names[run] += ['earc_vrfy'] + if not options['do_enkfonly_atm']: + task_names[run] += ['earc_vrfy'] if options['do_archcom']: task_names[run] += ['earc_tars'] diff --git a/dev/workflow/rocoto/gfs_tasks.py b/dev/workflow/rocoto/gfs_tasks.py index 6fdff9ee19c..0193f8634b8 100644 --- a/dev/workflow/rocoto/gfs_tasks.py +++ b/dev/workflow/rocoto/gfs_tasks.py @@ -106,15 +106,19 @@ def prep(self): deps = [] - dep_dict = {'type': 'metatask', 'name': 'gdas_atmos_prod', 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} - deps.append(rocoto.add_dependency(dep_dict)) - data = f'{atm_hist_path}/gdas.t@Hz.atm.f009.nc' - dep_dict = {'type': 'data', 'data': data, 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} - deps.append(rocoto.add_dependency(dep_dict)) + if not self.options['do_enkfonly_atm']: + dep_dict = {'type': 'metatask', 'name': 'gdas_atmos_prod', 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} + deps.append(rocoto.add_dependency(dep_dict)) + data = f'{atm_hist_path}/gdas.t@Hz.atmf009.nc' + dep_dict = {'type': 'data', 'data': data, 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} + deps.append(rocoto.add_dependency(dep_dict)) data = f'{dump_path}/{self.run}.t@Hz.updated.status.tm00.bufr_d' dep_dict = {'type': 'data', 'data': data} deps.append(rocoto.add_dependency(dep_dict)) - dep_dict = {'type': 'metatask', 'name': 'gdas_fcst', 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} + if self.options['do_enkfonly_atm']: + dep_dict = {'type': 'metatask', 'name': 'enkfgdas_epmn', 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} + else: + dep_dict = {'type': 'metatask', 'name': 'gdas_fcst', 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} deps.append(rocoto.add_dependency(dep_dict)) if self.options['do_prep_sfc']: dep_dict = {'type': 'task', 'name': f'{self.run}_prep_sfc'} @@ -2402,8 +2406,9 @@ def cleanup(self): dep_next_fcst_seg = rocoto.create_dependency(dep_condition='or', dep=deps) deps = [] if 'enkf' in self.run: - dep_dict = {'type': 'task', 'name': f'{self.run}_earc_vrfy'} - deps.append(rocoto.add_dependency(dep_dict)) + if not self.options['do_enkfonly_atm']: + dep_dict = {'type': 'task', 'name': f'{self.run}_earc_vrfy'} + deps.append(rocoto.add_dependency(dep_dict)) if self.options['do_archcom']: if self.options['do_globusarch']: dep_dict = {'type': 'metatask', 'name': f'{self.run}_globus_earc'} @@ -2793,8 +2798,9 @@ def _get_ecengroups(): return grp, dep, lst deps = [] - dep_dict = {'type': 'task', 'name': f'{self.run.replace("enkf", "")}_analcalc'} - deps.append(rocoto.add_dependency(dep_dict)) + if not self.options['do_enkfonly_atm']: + dep_dict = {'type': 'task', 'name': f'{self.run.replace("enkf", "")}_analcalc'} + deps.append(rocoto.add_dependency(dep_dict)) dep_dict = {'type': 'task', 'name': f'{self.run}_eupd'} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) @@ -2834,8 +2840,9 @@ def _get_ecengroups(): def ecen_fv3jedi(self): deps = [] - dep_dict = {'type': 'task', 'name': f"{self.run.replace('enkf', '')}_atmanlfinal"} - deps.append(rocoto.add_dependency(dep_dict)) + if not self.options['do_enkfonly_atm']: + dep_dict = {'type': 'task', 'name': f"{self.run.replace('enkf', '')}_atmanlfinal"} + deps.append(rocoto.add_dependency(dep_dict)) dep_dict = {'type': 'task', 'name': f'{self.run}_atmensanlfinal'} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) @@ -2894,8 +2901,9 @@ def esfc(self): dep_dict = {'type': 'task', 'name': f'{self.run}_atmensanlfinal'} deps.append(rocoto.add_dependency(dep_dict)) else: - dep_dict = {'type': 'task', 'name': f'{self.run.replace("enkf", "")}_analcalc'} - deps.append(rocoto.add_dependency(dep_dict)) + if not self.options['do_enkfonly_atm']: + dep_dict = {'type': 'task', 'name': f'{self.run.replace("enkf", "")}_analcalc'} + deps.append(rocoto.add_dependency(dep_dict)) dep_dict = {'type': 'task', 'name': f'{self.run}_eupd'} deps.append(rocoto.add_dependency(dep_dict)) if self.options['do_jedisnowda']: @@ -2924,8 +2932,9 @@ def efcs(self): deps = [] if self.options['do_jediatmens']: - dep_dict = {'type': 'task', 'name': f'{self.run}_ecen_fv3jedi'} - deps.append(rocoto.add_dependency(dep_dict)) + if not self.options['do_enkfonly_atm']: + dep_dict = {'type': 'task', 'name': f'{self.run}_ecen_fv3jedi'} + deps.append(rocoto.add_dependency(dep_dict)) else: dep_dict = {'type': 'metatask', 'name': f'{self.run}_ecmn'} deps.append(rocoto.add_dependency(dep_dict)) @@ -3071,9 +3080,10 @@ def earc_vrfy(self): if 'enkfgdas' in self.run: dep_dict = {'type': 'metatask', 'name': f'{self.run}_epmn'} deps.append(rocoto.add_dependency(dep_dict)) - if not self.options['do_jediatmvar']: - dep_dict = {'type': 'task', 'name': f'{self.run}_echgres'} - deps.append(rocoto.add_dependency(dep_dict)) + if not self.options['do_enkfonly_atm']: + if not self.options['do_jediatmvar']: + dep_dict = {'type': 'task', 'name': f'{self.run}_echgres'} + deps.append(rocoto.add_dependency(dep_dict)) else: dep_dict = {'type': 'task', 'name': f'{self.run}_esfc'} deps.append(rocoto.add_dependency(dep_dict)) @@ -3106,9 +3116,10 @@ def earc_tars(self): if 'enkfgdas' in self.run: dep_dict = {'type': 'metatask', 'name': f'{self.run}_epmn'} deps.append(rocoto.add_dependency(dep_dict)) - if not self.options['do_jediatmvar']: - dep_dict = {'type': 'task', 'name': f'{self.run}_echgres'} - deps.append(rocoto.add_dependency(dep_dict)) + if not self.options['do_enkfonly_atm']: + if not self.options['do_jediatmvar']: + dep_dict = {'type': 'task', 'name': f'{self.run}_echgres'} + deps.append(rocoto.add_dependency(dep_dict)) if self._base.get('DOLETKF_OCN', True): dep_dict = {'type': 'task', 'name': f'{self.run}_marineanlletkf'} deps.append(rocoto.add_dependency(dep_dict)) diff --git a/jobs/JGDAS_ENKF_SELECT_OBS b/jobs/JGDAS_ENKF_SELECT_OBS index ab3a426808e..117ba12d87c 100755 --- a/jobs/JGDAS_ENKF_SELECT_OBS +++ b/jobs/JGDAS_ENKF_SELECT_OBS @@ -37,8 +37,13 @@ MEMDIR='ensstat' RUN=${GDUMP_ENS} YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ COMIN_ATMOS_ANALYSIS_PREV:COM_ATMOS_ANALYSIS_TMPL \ COMIN_ATMOS_HISTORY_PREV:COM_ATMOS_HISTORY_TMPL -RUN="${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -r \ - COMIN_ATMOS_ANALYSIS_DET_PREV:COM_ATMOS_ANALYSIS_TMPL +if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then + RUN="enkfgdas" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ + COMIN_ATMOS_ANALYSIS_DET_PREV:COM_ENS_ATMOS_ANALYSIS_TMPL +else + RUN="${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -r \ + COMIN_ATMOS_ANALYSIS_DET_PREV:COM_ATMOS_ANALYSIS_TMPL +fi mkdir -p "${COMOUT_ATMOS_ANALYSIS}" @@ -65,17 +70,34 @@ if [[ ${DONST} == "YES" ]]; then fi export PREPQCPF="${COMIN_OBS}/${OPREFIX}prepbufr.acft_profiles" -# Deterministic analysis and increment files -export SFCANL="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}analysis.sfc.a006.nc" -export DTFANL="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}analysis.dtf.a006.nc" -export ATMANL="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}analysis.atm.a006.nc" -export ATMINC="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}increment.atm.i006.nc" - -# Guess Bias correction coefficients related to control -export GBIAS=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias.txt -export GBIASPC=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias_pc.txt -export GBIASAIR=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias_air.txt -export GRADSTAT=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}radstat.tar +if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then + # Ensemble analysis and increment files + export SFCANL="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}analysis.sfc.a006.nc" + export DTFANL="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}analysis.dtf.a006.nc" + export ATMANL="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}analysis.atm.a006.nc" + export ATMINC="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}increment.atm.i006.nc" + # Copy and untar GSI BC files for ensemble + GSIBIAS_SRC=${GSIBIAS}/${GDATE}/gdas.t${gcyc}z.rad_varbc_params.tar + GSIBIAS_DET=${COMIN_ATMOS_ANALYSIS_DET_PREV}/GSIOPE/ + mkdir -p ${GSIBIAS_DET} + tar -xvf ${GSIBIAS_SRC} -C ${GSIBIAS_DET} + export GBIAS=${GSIBIAS_DET}/${GPREFIX}abias.ensmean + export GBIASPC=${GSIBIAS_DET}/${GPREFIX}abias_pc.ensmean + export GBIASAIR=${GSIBIAS_DET}/${GPREFIX}abias_air.ensmean + export GRADSTAT=${GSIBIAS_DET}/${GPREFIX}radstat.ensmean +else + # Deterministic analysis and increment files + export SFCANL="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}analysis.sfc.a006.nc" + export DTFANL="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}analysis.dtf.a006.nc" + export ATMANL="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}analysis.atm.a006.nc" + export ATMINC="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}increment.atm.i006.nc" + + # Guess Bias correction coefficients related to control + export GBIAS=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias.txt + export GBIASPC=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias_pc.txt + export GBIASAIR=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias_air.txt + export GRADSTAT=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}radstat.tar +fi # Bias correction coefficients related to ensemble mean export ABIAS="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}abias.txt" diff --git a/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE b/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE index 35e2b21611c..8c43e43552e 100755 --- a/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE +++ b/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE @@ -19,8 +19,23 @@ GDUMP="gdas" RUN=${GDUMP} YMD=${PDY} HH=${cyc} declare_from_tmpl -rx \ COMIN_OBS:COM_OBS_TMPL -RUN=${GDUMP} YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ - COMIN_ATMOS_ANALYSIS_PREV:COM_ATMOS_ANALYSIS_TMPL +if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then + RUN="enkfgdas" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ + COMIN_ATMOS_ANALYSIS_PREV:COM_ENS_ATMOS_ANALYSIS_TMPL +else + RUN=${GDUMP} YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ + COMIN_ATMOS_ANALYSIS_PREV:COM_ATMOS_ANALYSIS_TMPL +fi + + +# Copy GSI BC files +if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then + GSIBIAS_SRC=${GSIBIAS}/${GDATE}/gdas.t${gcyc}z.rad_varbc_params.tar + # Need to Change + GSIBIAS_DET=${ROTDIR}/enkfgdas.${gPDY}/${gcyc}/ensstat/analysis/atmos/gdas.t${gcyc}z.rad_varbc_params.tar + + cp -r ${GSIBIAS_SRC} ${GSIBIAS_DET} +fi ############################################################### # Run relevant script diff --git a/parm/archive/enkf.yaml.j2 b/parm/archive/enkf.yaml.j2 index c13bf32a58a..313787d9b45 100644 --- a/parm/archive/enkf.yaml.j2 +++ b/parm/archive/enkf.yaml.j2 @@ -10,9 +10,11 @@ enkf: {% for fhr in range(fhmin, fhmax + 1, fhout) %} - "logs/{{ cycle_YMDH }}/{{ RUN }}_epos{{ '%03d' % (fhr - fhmin) }}.log" {% endfor %} - {% if not DO_JEDIATMENS %} + {% if not DOENKFONLY_ATM %} + {% if not DO_JEDIATMENS %} - "logs/{{ cycle_YMDH }}/{{ RUN }}_echgres.log" - {% endif %} + {% endif %} + {% endif %} {% endif %} - "logs/{{ cycle_YMDH }}/{{ RUN }}_esfc.log" {% if not DO_JEDIATMENS %} @@ -23,13 +25,21 @@ enkf: {% if lobsdiag_forenkf %} {% if DO_JEDIATMENS %} - {% set steps = ["atmensanlinit", "atmensanlobs", "atmensanlsol", "atmensanlfv3inc", "atmensanlfinal", "ecen_fv3jedi"] %} + {% if DOENKFONLY_ATM %} + {% set steps = ["atmensanlinit", "atmensanlobs", "atmensanlsol", "atmensanlfv3inc", "atmensanlfinal"] %} + {% else %} + {% set steps = ["atmensanlinit", "atmensanlobs", "atmensanlsol", "atmensanlfv3inc", "atmensanlfinal", "ecen_fv3jedi"] %} + {% endif %} {% else %} {% set steps = ["eobs", "ediag", "eupd"] %} {% endif %} {% else %} {% if DO_JEDIATMENS %} - {% set steps = ["atmensanlinit", "atmensanlletkf", "atmensanlfv3inc", "atmensanlfinal", "ecen_fv3jedi"] %} + {% if DOENKFONLY_ATM %} + {% set steps = ["atmensanlinit", "atmensanlletkf", "atmensanlfv3inc", "atmensanlfinal"] %} + {% else %} + {% set steps = ["atmensanlinit", "atmensanlletkf", "atmensanlfv3inc", "atmensanlfinal", "ecen_fv3jedi"] %} + {% endif %} {% else %} {% set steps = ["eobs", "eupd"] %} {% endif %} @@ -44,7 +54,7 @@ enkf: # Ensemble resolution {% if is_gdas %} - {% if DOHYBVAR %} + {% if DOHYBVAR and not DOENKFONLY_ATM %} {% if DOIAU %} {% for fhr in range(3, fhmax + 1, 3) %} - "{{ COMIN_ATMOS_HISTORY | relpath(ROTDIR) }}/{{ head |replace('enkf','')}}ensres.atm.f{{ '%03d' % fhr }}.nc" @@ -74,18 +84,31 @@ enkf: {% set da_conf_files = [] %} {% else %} {% if lobsdiag_forenkf %} - {% set da_stat_files = [] %} - {% set da_conf_files = ["atmensanlobs.yaml", - "atmensanlsol.yaml", - "atmensanlfv3inc.yaml", - "correction_increment.yaml", - "ensemble_recenter.yaml"] %} + {% if DOENKFONLY_ATM %} + {% set da_stat_files = ["atmensstat"] %} + {% set da_conf_files = ["atmensanlobs.yaml", + "atmensanlsol.yaml", + "atmensanlfv3inc.yaml"] %} + {% else %} + {% set da_stat_files = [] %} + {% set da_conf_files = ["atmensanlobs.yaml", + "atmensanlsol.yaml", + "atmensanlfv3inc.yaml", + "correction_increment.yaml", + "ensemble_recenter.yaml"] %} + {% endif %} {% else %} - {% set da_stat_files = ["stat.atm.tar"]%} - {% set da_conf_files = ["atmensanlletkf.yaml", - "atmensanlfv3inc.yaml", - "correction_increment.yaml", - "ensemble_recenter.yaml"] %} + {% if DOENKFONLY_ATM %} + {% set da_stat_files = ["stat.atm.tar"]%} + {% set da_conf_files = ["atmensanlletkf.yaml", + "atmensanlfv3inc.yaml"] %} + {% else %} + {% set da_stat_files = ["stat.atm.tar"]%} + {% set da_conf_files = ["atmensanlletkf.yaml", + "atmensanlfv3inc.yaml", + "correction_increment.yaml", + "ensemble_recenter.yaml"] %} + {% endif %} {% endif %} {% endif %} {% for file in da_stat_files %} @@ -110,7 +133,7 @@ enkf: {% endif %} # Atmospheric analyses/increment - {% for fhr in IAUFHRS %} + {% for fhr in IAUFHRS if fhr != 6 %} {% if not DO_JEDIATMENS %} {% if do_calc_increment %} # Store analyses instead of increments diff --git a/parm/archive/enkf_grp.yaml.j2 b/parm/archive/enkf_grp.yaml.j2 index fda546f23c2..0b407919234 100644 --- a/parm/archive/enkf_grp.yaml.j2 +++ b/parm/archive/enkf_grp.yaml.j2 @@ -24,17 +24,24 @@ enkf_grp: {% if DO_JEDIATMENS %} {% for iaufhr in IAUFHRS %} {% for itile in range(6) %} + {% if DOENKFONLY_ATM %} + - "{{ COMIN_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ head }}_jedi_increment.atm.i{{ '%03d' % iaufhr }}.tile{{ itile+1 }}.nc" + {% else %} - "{{ COMIN_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ head }}recentered_jedi_increment.atm.i{{ '%03d' % iaufhr }}.tile{{ itile+1 }}.nc" + {% endif %} + {% endfor %} {% endfor %} {% else %} {% if do_calc_increment %} - "{{ COMIN_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ head }}analysis.atm.a006.nc" {% else %} - {% for iaufhr in IAUFHRS %} - {% set iaufhr = iaufhr %} + {% if not DOENKFONLY_ATM %} + {% for iaufhr in IAUFHRS %} + {% set iaufhr = iaufhr %} - "{{ COMIN_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ head }}recentered_increment.atm.i{{ '%03d' % iaufhr }}.nc" - {% endfor %} # iaufhr in IAUFHRS + {% endfor %} # iaufhr in IAUFHRS + {% endif %} {% endif %} {% endif %} diff --git a/parm/archive/enkf_restarta_grp.yaml.j2 b/parm/archive/enkf_restarta_grp.yaml.j2 index 49afd2a788e..3f6ce178fcd 100644 --- a/parm/archive/enkf_restarta_grp.yaml.j2 +++ b/parm/archive/enkf_restarta_grp.yaml.j2 @@ -37,7 +37,11 @@ enkf_restarta_grp: {% if DO_JEDIATMENS %} {% for iaufhr in IAUFHRS %} {% for itile in range(6) %} + {% if DOENKFONLY_ATM %} + - "{{ COMIN_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ head }}_jedi_increment.atm.i{{ '%03d' % iaufhr }}.tile{{ itile+1 }}.nc" + {% else %} - "{{ COMIN_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ head }}recentered_jedi_increment.atm.i{{ '%03d' % iaufhr }}.tile{{ itile+1 }}.nc" + {% endif %} {% endfor %} {% endfor %} {% else %} @@ -45,7 +49,9 @@ enkf_restarta_grp: {% if do_calc_increment %} - "{{ COMIN_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ head }}analysis.atm.a{{ '%03d' % iaufhr }}.nc" {% else %} + {% if not DOENKFONLY_ATM %} - "{{ COMIN_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ head }}recentered_increment.atm.i{{ '%03d' % iaufhr }}.nc" + {% endif %} {% endif %} {% endfor %} # iaufhr in IAUFHRS {% endif %} diff --git a/parm/stage/analysis.yaml.j2 b/parm/stage/analysis.yaml.j2 index 4853cc55d25..c8a233477f0 100644 --- a/parm/stage/analysis.yaml.j2 +++ b/parm/stage/analysis.yaml.j2 @@ -1,12 +1,19 @@ {% if path_exists(ICSDIR ~ "/" ~ COMOUT_ATMOS_ANALYSIS_MEM_list[0] | relpath(ROTDIR)) %} analysis: mkdir: + {% if DOENKFONLY_ATM %} + {% set COMOUT_ATMOS_ANALYSIS_MEM = COMOUT_ATMOS_ANALYSIS_MEM_list[enssat] %} + - "{{ COMOUT_ATMOS_ANALYSIS_MEM }}" + {% endif %} {% for mem in range(first_mem, last_mem + 1) %} {% set imem = mem - first_mem %} {% set COMOUT_ATMOS_ANALYSIS_MEM = COMOUT_ATMOS_ANALYSIS_MEM_list[imem] %} - "{{ COMOUT_ATMOS_ANALYSIS_MEM }}" {% endfor %} link_req: + {% if DOENKFONLY_ATM %} + {% set COMOUT_ATMOS_ANALYSIS_MEM = COMOUT_ATMOS_ANALYSIS_MEM_list[enssat] %} + {% endif %} {% for mem in range(first_mem, last_mem + 1) %} {% set imem = mem - first_mem %} {% set COMOUT_ATMOS_ANALYSIS_MEM = COMOUT_ATMOS_ANALYSIS_MEM_list[imem] %} @@ -30,12 +37,22 @@ analysis: {% endfor %} # TODO: make these filenames the same after RE-staging inputs with EE2-compliant filenames - {% for source_ftype, dest_ftype in [ + {% if DOENKFONLY_ATM %} + {% set ftypes = [ + ("abias", "abias.ensmean.txt"), + ("abias_air", "abias_air.ensmean.txt"), + ("abias_int", "abias_int.ensmean.txt"), + ("abias_pc", "abias_pc.ensmean.txt"), + ("rad_varbc_params.tar", "rad_varbc_params.tar")] %} + {% else %} + {% set ftypes = [ ("abias", "abias.txt"), ("abias_air", "abias_air.txt"), ("abias_int", "abias_int.txt"), ("abias_pc", "abias_pc.txt"), ("rad_varbc_params.tar", "rad_varbc_params.tar")] %} + {% endif %} + {% for source_ftype, dest_ftype in ftypes %} {% if path_exists(ICSDIR ~ "/" ~ COMOUT_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) ~ "/" ~ RUN ~ ".t" ~ current_cycle_HH ~ "z." ~ source_ftype) %} - ["{{ ICSDIR }}/{{ COMOUT_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ RUN }}.t{{ current_cycle_HH }}z.{{ source_ftype }}", "{{ COMOUT_ATMOS_ANALYSIS_MEM }}/{{ RUN }}.t{{ current_cycle_HH }}z.{{ dest_ftype }}"] @@ -45,8 +62,22 @@ analysis: {% else %} # TODO: make these filenames the same after RE-staging inputs with EE2-compliant filenames - {% for source_ftype, dest_ftype in - [ + {% if DOENKFONLY_ATM %} + {% set ftypes = [ + ("atminc.nc", "increment.atm.i006.nc"), + ("atmi009.nc", "increment.atm.i009.nc"), + ("atmi003.nc", "increment.atm.i003.nc"), + ("ratmi009.nc", "recentered_increment.atm.i009.nc"), + ("ratminc.nc", "recentered_increment.atm.i006.nc"), + ("ratmi003.nc", "recentered_increment.atm.i003.nc"), + ("abias", "abias.ensmean.txt"), + ("radstat", "radstat.tar"), + ("abias_air", "abias_air.ensmean.txt"), + ("abias_int", "abias_int.ensmean.txt"), + ("abias_pc", "abias_pc.ensmean.txt"), + ("rad_varbc_params.tar", "rad_varbc_params.tar") ] %} + {% else %} + {% set ftypes = [ ("atminc.nc", "increment.atm.i006.nc"), ("atmi009.nc", "increment.atm.i009.nc"), ("atmi003.nc", "increment.atm.i003.nc"), @@ -58,8 +89,9 @@ analysis: ("abias_air", "abias_air.txt"), ("abias_int", "abias_int.txt"), ("abias_pc", "abias_pc.txt"), - ("rad_varbc_params.tar", "rad_varbc_params.tar") - ] %} + ("rad_varbc_params.tar", "rad_varbc_params.tar") ] %} + {% endif %} + {% for source_ftype, dest_ftype in ftypes %} {% if path_exists(ICSDIR ~ "/" ~ COMOUT_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) ~ "/" ~ RUN ~ ".t" ~ current_cycle_HH ~ "z." ~ source_ftype) %} - ["{{ ICSDIR }}/{{ COMOUT_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ RUN }}.t{{ current_cycle_HH }}z.{{ source_ftype }}", "{{ COMOUT_ATMOS_ANALYSIS_MEM }}/{{ RUN }}.t{{ current_cycle_HH }}z.{{ dest_ftype }}"] diff --git a/parm/stage/atmosphere_cold.yaml.j2 b/parm/stage/atmosphere_cold.yaml.j2 index c742b28c8d3..62cef375d1d 100644 --- a/parm/stage/atmosphere_cold.yaml.j2 +++ b/parm/stage/atmosphere_cold.yaml.j2 @@ -5,6 +5,14 @@ atmosphere_cold: {% set COMOUT_ATMOS_INPUT_MEM = COMOUT_ATMOS_INPUT_MEM_list[imem] %} - "{{ COMOUT_ATMOS_INPUT_MEM }}" {% endfor %} # mem loop + + {% if DOENKFONLY_ATM %} + {% for mem in range(first_mem, last_mem + 1) %} + {% set imem = mem - first_mem %} + {% set COMOUT_ENS_ATMOS_ANALYSIS_MEM = COMOUT_ENS_ATMOS_ANALYSIS_MEM_list[imem] %} + - "{{ COMOUT_ENS_ATMOS_ANALYSIS_MEM }}" + {% endfor %} # mem loop + {% endif %} link_req: {% for mem in range(first_mem, last_mem + 1) %} {% set imem = mem - first_mem %} @@ -16,3 +24,13 @@ atmosphere_cold: {% endfor %} # ntile {% endfor %} # ftype {% endfor %} # mem loop + + {% if DOENKFONLY_ATM %} + {% for mem in range(first_mem, last_mem + 1) %} + {% set imem = mem - first_mem %} + {% set COMOUT_ENS_ATMOS_ANALYSIS_MEM = COMOUT_ENS_ATMOS_ANALYSIS_MEM_list[imem] %} + {% for ftype in ["abias.ensmean", "abias_air.ensmean", "abias_int.ensmean", "abias_pc.ensmean", "radstat.ensmean"] %} + - ["{{ ICSDIR }}/{{ COMOUT_ENS_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ RUN }}.t{{ current_cycle_HH }}z.{{ ftype }}", "{{ COMOUT_ENS_ATMOS_ANALYSIS_MEM }}"] + {% endfor %} # ftype + {% endfor %} # mem loop + {% endif %} diff --git a/parm/stage/master_gfs.yaml.j2 b/parm/stage/master_gfs.yaml.j2 index 35fa21cd8af..58678caee93 100644 --- a/parm/stage/master_gfs.yaml.j2 +++ b/parm/stage/master_gfs.yaml.j2 @@ -65,9 +65,11 @@ # Declare to-be-filled lists of member COM directories # ---------------------------------------------------- {% set COMOUT_ATMOS_INPUT_MEM_list = [] %} +{% set COMOUT_ENS_ATMOS_INPUT_MEM_list = [] %} {% set COMOUT_ATMOS_RESTART_PREV_MEM_list = [] %} {% set COMOUT_ATMOS_RESTART_MEM_list = [] %} {% set COMOUT_ATMOS_ANALYSIS_MEM_list = [] %} +{% set COMOUT_ENS_ATMOS_ANALYSIS_MEM_list = [] %} {% set COMOUT_ICE_ANALYSIS_MEM_list = [] %} {% set COMOUT_ICE_RESTART_PREV_MEM_list = [] %} {% set COMOUT_OCEAN_RESTART_PREV_MEM_list = [] %} @@ -101,6 +103,7 @@ {% set COMOUT_ATMOS_RESTART_PREV_MEM = COM_ATMOS_RESTART_TMPL | replace_tmpl(previous_cycle_dict) %} {% set COMOUT_ATMOS_RESTART_MEM = COM_ATMOS_RESTART_TMPL | replace_tmpl(current_cycle_dict) %} {% set COMOUT_ATMOS_ANALYSIS_MEM = COM_ATMOS_ANALYSIS_TMPL | replace_tmpl(current_cycle_dict) %} + {% set COMOUT_ENS_ATMOS_ANALYSIS_MEM = COM_ENS_ATMOS_ANALYSIS_TMPL | replace_tmpl(current_cycle_dict) %} {% set COMOUT_ICE_ANALYSIS_MEM = COM_ICE_ANALYSIS_TMPL | replace_tmpl(current_cycle_dict) %} {% set COMOUT_ICE_RESTART_PREV_MEM = COM_ICE_RESTART_TMPL | replace_tmpl(previous_cycle_dict) %} {% set COMOUT_OCEAN_RESTART_PREV_MEM = COM_OCEAN_RESTART_TMPL | replace_tmpl(previous_cycle_dict) %} @@ -114,6 +117,7 @@ {% do COMOUT_ATMOS_RESTART_PREV_MEM_list.append(COMOUT_ATMOS_RESTART_PREV_MEM)%} {% do COMOUT_ATMOS_RESTART_MEM_list.append(COMOUT_ATMOS_RESTART_MEM)%} {% do COMOUT_ATMOS_ANALYSIS_MEM_list.append(COMOUT_ATMOS_ANALYSIS_MEM)%} + {% do COMOUT_ENS_ATMOS_ANALYSIS_MEM_list.append(COMOUT_ENS_ATMOS_ANALYSIS_MEM)%} {% do COMOUT_ICE_ANALYSIS_MEM_list.append(COMOUT_ICE_ANALYSIS_MEM)%} {% do COMOUT_ICE_RESTART_PREV_MEM_list.append(COMOUT_ICE_RESTART_PREV_MEM)%} {% do COMOUT_OCEAN_RESTART_PREV_MEM_list.append(COMOUT_OCEAN_RESTART_PREV_MEM)%} diff --git a/scripts/exgdas_enkf_earc_tars.py b/scripts/exgdas_enkf_earc_tars.py index 354d374a0c2..8c662192a2a 100755 --- a/scripts/exgdas_enkf_earc_tars.py +++ b/scripts/exgdas_enkf_earc_tars.py @@ -28,7 +28,8 @@ def main(): 'DOHYBVAR', 'DOIAU_ENKF', 'IAU_OFFSET', 'DOIAU', 'DO_CA', 'DO_CALC_INCREMENT', 'assim_freq', 'ARCH_CYC', 'DO_JEDISNOWDA', 'ARCH_WARMICFREQ', 'ARCH_FCSTICFREQ', 'DOHYBVAR_OCN', - 'DOLETKF_OCN', 'IAUFHRS_ENKF', 'NET', 'NMEM_ENS_GFS', 'DO_GSISOILDA', 'DO_LAND_IAU'] + 'DOLETKF_OCN', 'IAUFHRS_ENKF', 'NET', 'NMEM_ENS_GFS', 'DO_GSISOILDA', 'DO_LAND_IAU', + 'DOENKFONLY_ATM'] archive_dict = AttrDict() for key in keys: diff --git a/scripts/exglobal_stage_ic.py b/scripts/exglobal_stage_ic.py index e0af18b42fa..cbce5d50dcd 100755 --- a/scripts/exglobal_stage_ic.py +++ b/scripts/exglobal_stage_ic.py @@ -24,7 +24,8 @@ def main(): 'OCNRES', 'waveGRD', 'ntiles', 'DOIAU', 'DO_JEDIOCNVAR', 'DO_STARTMEM_FROM_JEDIICE', 'DO_WAVE', 'DO_OCN', 'DO_ICE', 'DO_NEST', 'DO_CA', 'DO_AERO_ANL', - 'USE_ATM_ENS_PERTURB_FILES', 'USE_OCN_ENS_PERTURB_FILES', 'DO_GSISOILDA', 'DO_LAND_IAU'] + 'USE_ATM_ENS_PERTURB_FILES', 'USE_OCN_ENS_PERTURB_FILES', 'DO_GSISOILDA', 'DO_LAND_IAU', + 'DOENKFONLY_ATM'] stage_dict = AttrDict() for key in keys: diff --git a/sorc/gdas.cd b/sorc/gdas.cd index e2b780da168..f24180713d0 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit e2b780da168c1b9a45fb6487fa71ff148e42754d +Subproject commit f24180713d02ccc01dc3778cb631022bf6c9481b diff --git a/ush/python/pygfs/task/atmens_analysis.py b/ush/python/pygfs/task/atmens_analysis.py index 99cc210408c..646dda268f3 100644 --- a/ush/python/pygfs/task/atmens_analysis.py +++ b/ush/python/pygfs/task/atmens_analysis.py @@ -35,6 +35,8 @@ def __init__(self, config: Dict[str, Any]): _res = int(self.task_config.CASE_ENS[1:]) + self.task_config.letkf_app = "true" + # Create a local dictionary that is repeatedly used across this class self.task_config.update(AttrDict( { From e694072c39ba615db7b7c6bf614ae116484a8497 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Mon, 3 Nov 2025 22:56:56 +0000 Subject: [PATCH 02/22] GSI and JEDI test passed after EE name change. csg in JEDI file names hard-coded (need to revisit) --- parm/archive/enkf.yaml.j2 | 2 +- parm/archive/enkf_grp.yaml.j2 | 2 +- sorc/gdas.cd | 2 +- ush/forecast_postdet.sh | 10 +++++++--- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/parm/archive/enkf.yaml.j2 b/parm/archive/enkf.yaml.j2 index 313787d9b45..3bfe78d6891 100644 --- a/parm/archive/enkf.yaml.j2 +++ b/parm/archive/enkf.yaml.j2 @@ -85,7 +85,7 @@ enkf: {% else %} {% if lobsdiag_forenkf %} {% if DOENKFONLY_ATM %} - {% set da_stat_files = ["atmensstat"] %} + {% set da_stat_files = ["stat.atm.tar"] %} {% set da_conf_files = ["atmensanlobs.yaml", "atmensanlsol.yaml", "atmensanlfv3inc.yaml"] %} diff --git a/parm/archive/enkf_grp.yaml.j2 b/parm/archive/enkf_grp.yaml.j2 index 0b407919234..1c72f7f557b 100644 --- a/parm/archive/enkf_grp.yaml.j2 +++ b/parm/archive/enkf_grp.yaml.j2 @@ -25,7 +25,7 @@ enkf_grp: {% for iaufhr in IAUFHRS %} {% for itile in range(6) %} {% if DOENKFONLY_ATM %} - - "{{ COMIN_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ head }}_jedi_increment.atm.i{{ '%03d' % iaufhr }}.tile{{ itile+1 }}.nc" + - "{{ COMIN_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ head }}csg_jedi_increment.atm.i{{ '%03d' % iaufhr }}.tile{{ itile+1 }}.nc" {% else %} - "{{ COMIN_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ head }}recentered_jedi_increment.atm.i{{ '%03d' % iaufhr }}.tile{{ itile+1 }}.nc" {% endif %} diff --git a/sorc/gdas.cd b/sorc/gdas.cd index f24180713d0..30baa196233 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit f24180713d02ccc01dc3778cb631022bf6c9481b +Subproject commit 30baa196233c43468aaa9ad5c001fe1899e8aa94 diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 1f770bdfd73..9e3adf1c10d 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -196,9 +196,9 @@ EOF read_increment=".true." if [[ "${DO_JEDIATMVAR:-NO}" == "YES" ]]; then - inc_files=("jedi_increment.atm.i006.tile1.nc" "jedi_increment.atm.i006.tile2.nc" "jedi_increment.atm.i006.tile3.nc" "jedi_increment.atm.i006.tile4.nc" "jedi_increment.atm.i006.tile5.nc" "jedi_increment.atm.i006.tile6.nc") + inc_files=("csg_jedi_increment.atm.i006.tile1.nc" "csg_jedi_increment.atm.i006.tile2.nc" "csg_jedi_increment.atm.i006.tile3.nc" "csg_jedi_increment.atm.i006.tile4.nc" "csg_jedi_increment.atm.i006.tile5.nc" "csg_jedi_increment.atm.i006.tile6.nc") increment_file_on_native_grid=".true." - res_latlon_dynamics="jedi_increment.atm.i006" + res_latlon_dynamics="csg_jedi_increment.atm.i006" else inc_files=("increment.atm.i006.nc") res_latlon_dynamics="increment.atm.i006.nc" @@ -215,7 +215,11 @@ EOF fi if [[ "${RUN}" = "enkfgfs" ]] || [[ "${RUN}" = "enkfgdas" ]]; then - prefix_atminc="recentered_" + if [[ "${DOENKFONLY_ATM}" = "YES" ]]; then + prefix_atminc="" + else + prefix_atminc="recentered_" + fi else prefix_atminc="" fi From bed26ea085542ca343975460ea7a384801dbd46a Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Thu, 6 Nov 2025 00:21:34 +0000 Subject: [PATCH 03/22] add fetch and prepatmopeanlbc tasks and need to test them --- dev/jobs/prep.sh | 12 ++++ dev/parm/config/gfs/config.fetch | 29 ++++++++-- dev/parm/config/gfs/config.resources | 9 ++- dev/workflow/applications/gfs_cycled.py | 7 ++- dev/workflow/rocoto/gfs_tasks.py | 75 +++++++++++++++++++++---- dev/workflow/rocoto/tasks.py | 2 +- sorc/gdas.cd | 2 +- 7 files changed, 114 insertions(+), 22 deletions(-) diff --git a/dev/jobs/prep.sh b/dev/jobs/prep.sh index bde30e0c70d..599db2043d7 100755 --- a/dev/jobs/prep.sh +++ b/dev/jobs/prep.sh @@ -40,6 +40,7 @@ RUN=${GDUMP} YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ mkdir -p "${COMOUT_OBS}" + ############################################################### # Copy dump files to ROTDIR "${HOMEgfs}/ush/getdump.sh" "${PDY}" "${cyc}" "${RUN_local}" "${COMINobsproc}" "${COMOUT_OBS}" @@ -68,6 +69,16 @@ fi ############################################################### +# Download GSI deterministic bias correction files for EnKF-only model from HPSS +if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then + "${HOMEgfs}/ush/get_gsi_det_bc.sh" "${gPDY}" "${gcyc}" "${RUN_local}" + #"${RUN_local}" "${COMINobsproc}" "${COMOUT_OBS}" + status=$? + if [[ ${status} -ne 0 ]]; then + exit "${status}" + fi +fi + ############################################################### # For running real-time parallels, execute tropcy_qc and # copy files from operational syndata directory to a local directory. @@ -173,6 +184,7 @@ if [[ ${err} -ne 0 ]]; then err_exit "Failed to obtain/create ${files}, ABORT!" fi + ################################################################################ # Exit out cleanly diff --git a/dev/parm/config/gfs/config.fetch b/dev/parm/config/gfs/config.fetch index 86ab5e3e2f8..b98a28393d5 100644 --- a/dev/parm/config/gfs/config.fetch +++ b/dev/parm/config/gfs/config.fetch @@ -7,13 +7,30 @@ echo "BEGIN: config.fetch" # Get task specific resources source "${EXPDIR}/config.resources" fetch -# Determine start type -if [[ "${EXP_WARM_START}" == ".false." ]]; then - ic_type="cold" +if [[ "${PDY}${cyc}" -gt "${SDATE}" ]]; then + # fetch based on the second and following cycle + if [[ ${DOENKFONLY_ATM} == "YES" ]]; then + # determine GDAS version based on date + if [[ "${PDY}${cyc}" -ge "2022112900" ]]; then + gdas_version="v16.3" + elif [[ "${PDY}${cyc}" -ge "2022062700" ]]; then + gdas_version="v16.2" + else + gdas_version="prod" + fi + export gdas_version + export FETCH_YAML_TMPL="${PARMgfs}/fetch/${NET}_${APP}_gdas-anl-gsibc.yaml.j2" + fi else - ic_type="warm" -fi + # fetch based on first cycle + # Determine start type + if [[ "${EXP_WARM_START}" == ".false." ]]; then + ic_type="cold" + else + ic_type="warm" + fi -export FETCH_YAML_TMPL="${PARMgfs}/fetch/${NET}_${APP}_${ic_type}_${MODE}.yaml.j2" + export FETCH_YAML_TMPL="${PARMgfs}/fetch/${NET}_${APP}_${ic_type}_${MODE}.yaml.j2" +fi echo "END: config.fetch" diff --git a/dev/parm/config/gfs/config.resources b/dev/parm/config/gfs/config.resources index 8643b6b95d1..77d425449b0 100644 --- a/dev/parm/config/gfs/config.resources +++ b/dev/parm/config/gfs/config.resources @@ -12,7 +12,7 @@ if (( $# != 1 )); then echo "Must specify an input task argument to set resource variables!" echo "argument can be any one of the following:" echo "stage_ic aerosol_init fetch" - echo "prep prep_sfc prepatmiodaobs" + echo "prep prep_sfc prepatmiodaobs prepatmopeanlbc" echo "atmanlinit atmanlvar atmanlfv3inc atmanlfinal" echo "atmensanlinit atmensanlobs atmensanlsol atmensanlletkf atmensanlfv3inc atmensanlfinal ecen_fv3jedi analcalc_fv3jedi" echo "snowanl esnowanl" @@ -123,6 +123,13 @@ case ${step} in tasks_per_node=$(( max_tasks_per_node / threads_per_task )) ;; + "prepatmopeanlbc") + walltime="00:30:00" + ntasks=1 + threads_per_task=1 + tasks_per_node=1 + ;; + "aerosol_init") walltime="00:05:00" ntasks=1 diff --git a/dev/workflow/applications/gfs_cycled.py b/dev/workflow/applications/gfs_cycled.py index b197a091ac8..e91df43770f 100644 --- a/dev/workflow/applications/gfs_cycled.py +++ b/dev/workflow/applications/gfs_cycled.py @@ -107,6 +107,9 @@ def _get_app_configs(self, run): configs = ['prep'] + if options['do_enkfonly_atm']: + configs += ['fetch', 'prepatmopeanlbc'] + if options['do_prep_sfc']: configs += ['prep_sfc'] @@ -248,6 +251,7 @@ def get_task_names(self): # Common gdas and gfs tasks before fcst if run in ['gdas', 'gfs']: task_names[run] += ['prep'] + if options['do_prep_sfc']: task_names[run] += ['prep_sfc'] if options['do_jediatmvar']: @@ -378,8 +382,9 @@ def get_task_names(self): task_names[run] += ['cleanup'] - # Remove unnecessary tasks if do_enkfonly_atm=true + # Add or remove (un)necessary tasks if do_enkfonly_atm=true if options['do_enkfonly_atm']: + task_names['gdas'] += ['fetch', 'prepatmopeanlbc'] rmtasks=['anlstat', 'sfcanl', 'analcalc', 'fcst', 'atmanlprod', 'stage_ic', 'arch_tars', 'arch_vrfy', 'atmos_prod', 'atmanlupp', 'cleanup'] if options['do_jediatmvar']: rmtasks.extend(['atmanlinit', 'atmanlvar', 'atmanlfv3inc', 'atmanlfinal', 'analcalc_fv3jedi']) diff --git a/dev/workflow/rocoto/gfs_tasks.py b/dev/workflow/rocoto/gfs_tasks.py index 0193f8634b8..50ec22a8d84 100644 --- a/dev/workflow/rocoto/gfs_tasks.py +++ b/dev/workflow/rocoto/gfs_tasks.py @@ -18,19 +18,40 @@ def _is_this_a_gdas_task(run, task_name): # Specific Tasks begin here def fetch(self): - cycledef = 'gdas_half' if self.run in ['gdas', 'enkfgdas'] else self.run + if self.options['do_enkfonly_atm']: + deps = [] + dep_dict = {'type': 'metatask', 'name': 'enkfgdas_epmn', 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} + deps.append(rocoto.add_dependency(dep_dict)) + dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) - resources = self.get_resource('fetch') - task_name = f'{self.run}_fetch' - task_dict = {'task_name': task_name, - 'resources': resources, - 'envars': self.envars, - 'cycledef': cycledef, - 'command': f'{self.HOMEgfs}/dev/jobs/fetch.sh', - 'job_name': f'{self.pslot}_{task_name}_@H', - 'log': f'{self.rotdir}/logs/@Y@m@d@H/{task_name}.log', - 'maxtries': '&MAXTRIES;' - } + cycledef = self.run + + resources = self.get_resource('fetch') + task_name = f'{self.run}_fetch' + task_dict = {'task_name': task_name, + 'resources': resources, + 'dependency': dependencies, + 'envars': self.envars, + 'cycledef': cycledef, + 'command': f'{self.HOMEgfs}/dev/jobs/fetch.sh', + 'job_name': f'{self.pslot}_{task_name}_@H', + 'log': f'{self.rotdir}/logs/@Y@m@d@H/{task_name}.log', + 'maxtries': '&MAXTRIES;' + } + else: + cycledef = 'gdas_half' if self.run in ['gdas', 'enkfgdas'] else self.run + + resources = self.get_resource('fetch') + task_name = f'{self.run}_fetch' + task_dict = {'task_name': task_name, + 'resources': resources, + 'envars': self.envars, + 'cycledef': cycledef, + 'command': f'{self.HOMEgfs}/dev/jobs/fetch.sh', + 'job_name': f'{self.pslot}_{task_name}_@H', + 'log': f'{self.rotdir}/logs/@Y@m@d@H/{task_name}.log', + 'maxtries': '&MAXTRIES;' + } task = rocoto.create_task(task_dict) @@ -146,6 +167,30 @@ def prep(self): return task + def prepatmopeanlbc(self): + + deps = [] + dep_dict = {'type': 'task', 'name': f'{self.run}_fetch'} + deps.append(rocoto.add_dependency(dep_dict)) + dependencies = rocoto.create_dependency(dep=deps) + + resources = self.get_resource('prepatmopeanlbc') + task_name = f'{self.run}_prepatmopeanlbc' + task_dict = {'task_name': task_name, + 'resources': resources, + 'dependency': dependencies, + 'envars': self.envars, + 'cycledef': self.run.replace('enkf', ''), + 'command': f'{self.HOMEgfs}/dev/jobs/prepatmopeanlbc.sh', + 'job_name': f'{self.pslot}_{task_name}_@H', + 'log': f'{self.rotdir}/logs/@Y@m@d@H/{task_name}.log', + 'maxtries': '&MAXTRIES;' + } + + task = rocoto.create_task(task_dict) + + return task + def waveinit(self): resources = self.get_resource('waveinit') @@ -2550,6 +2595,9 @@ def eobs(self): deps.append(rocoto.add_dependency(dep_dict)) dep_dict = {'type': 'metatask', 'name': 'enkfgdas_epmn', 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} deps.append(rocoto.add_dependency(dep_dict)) + if self.options['do_enkfonly_atm']: + dep_dict = {'type': 'task', 'name': f'{self.run.replace("enkf", "")}_prepatmopeanlbc'} + deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) resources = self.get_resource('eobs') @@ -2621,6 +2669,9 @@ def atmensanlinit(self): deps.append(rocoto.add_dependency(dep_dict)) dep_dict = {'type': 'metatask', 'name': 'enkfgdas_epmn', 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} deps.append(rocoto.add_dependency(dep_dict)) + if self.options['do_enkfonly_atm']: + dep_dict = {'type': 'task', 'name': f'{self.run.replace("enkf", "")}_prepatmopeanlbc'} + deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) cycledef = "gdas" diff --git a/dev/workflow/rocoto/tasks.py b/dev/workflow/rocoto/tasks.py index 79c380ffeb2..e49aebbcef8 100644 --- a/dev/workflow/rocoto/tasks.py +++ b/dev/workflow/rocoto/tasks.py @@ -17,7 +17,7 @@ class Tasks: 'prep_sfc', 'prep', 'anal', 'sfcanl', 'analcalc', 'analdiag', 'arch_vrfy', 'arch_tars', 'cleanup', 'ecen_fv3jedi', 'analcalc_fv3jedi', 'cleanup', 'prepatmiodaobs', 'atmanlinit', 'atmanlvar', 'atmanlfv3inc', 'atmanlfinal', - 'prep_emissions', 'prepoceanobs', + 'prep_emissions', 'prepoceanobs', 'prepatmopeanlbc', 'marineanlinit', 'marineanlletkf', 'marinebmatinit', 'marinebmat', 'marineanlvar', 'marineanlecen', 'marineanlchkpt', 'marineanlfinal', 'ocnanalvrfy', 'eobs', 'epos', 'esfc', 'eupd', diff --git a/sorc/gdas.cd b/sorc/gdas.cd index 30baa196233..299f38f6ac1 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit 30baa196233c43468aaa9ad5c001fe1899e8aa94 +Subproject commit 299f38f6ac1c313dbc8ef07b3cac1ce98b64093e From f32d59cfc29ce58ef2f834f74a89d401340a9391 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Mon, 10 Nov 2025 23:57:59 +0000 Subject: [PATCH 04/22] Pass JEDI and GSI test --- dev/jobs/prep.sh | 11 --- dev/jobs/prepatmopeanlbc.sh | 18 ++++ dev/parm/config/gfs/config.base.j2 | 1 - dev/parm/config/gfs/config.prepatmopeanlbc | 11 +++ jobs/JGDAS_ENKF_SELECT_OBS | 15 ++- jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE | 10 -- jobs/JGLOBAL_ATM_PREP_OPE_ANL_BC | 103 +++++++++++++++++++++ parm/fetch/gfs_ATM_gdas-anl-gsibc.yaml.j2 | 16 ++++ sorc/gdas.cd | 2 +- sorc/link_workflow.sh | 4 + ush/gen_run_satbias_conv_yaml.py | 1 + ush/run_satbias_conv.py | 1 + ush/satbias_converter.yaml | 1 + 13 files changed, 162 insertions(+), 32 deletions(-) create mode 100755 dev/jobs/prepatmopeanlbc.sh create mode 100644 dev/parm/config/gfs/config.prepatmopeanlbc create mode 100755 jobs/JGLOBAL_ATM_PREP_OPE_ANL_BC create mode 100644 parm/fetch/gfs_ATM_gdas-anl-gsibc.yaml.j2 create mode 120000 ush/gen_run_satbias_conv_yaml.py create mode 120000 ush/run_satbias_conv.py create mode 120000 ush/satbias_converter.yaml diff --git a/dev/jobs/prep.sh b/dev/jobs/prep.sh index 599db2043d7..21a8478f6b2 100755 --- a/dev/jobs/prep.sh +++ b/dev/jobs/prep.sh @@ -40,7 +40,6 @@ RUN=${GDUMP} YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ mkdir -p "${COMOUT_OBS}" - ############################################################### # Copy dump files to ROTDIR "${HOMEgfs}/ush/getdump.sh" "${PDY}" "${cyc}" "${RUN_local}" "${COMINobsproc}" "${COMOUT_OBS}" @@ -69,16 +68,6 @@ fi ############################################################### -# Download GSI deterministic bias correction files for EnKF-only model from HPSS -if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then - "${HOMEgfs}/ush/get_gsi_det_bc.sh" "${gPDY}" "${gcyc}" "${RUN_local}" - #"${RUN_local}" "${COMINobsproc}" "${COMOUT_OBS}" - status=$? - if [[ ${status} -ne 0 ]]; then - exit "${status}" - fi -fi - ############################################################### # For running real-time parallels, execute tropcy_qc and # copy files from operational syndata directory to a local directory. diff --git a/dev/jobs/prepatmopeanlbc.sh b/dev/jobs/prepatmopeanlbc.sh new file mode 100755 index 00000000000..2fc9901d8e7 --- /dev/null +++ b/dev/jobs/prepatmopeanlbc.sh @@ -0,0 +1,18 @@ +#! /usr/bin/env bash + +############################################################### +# Source UFSDA workflow modules +source "${HOMEgfs}/dev/ush/load_modules.sh" ufsda +status=$? +if [[ ${status} -ne 0 ]]; then + exit "${status}" +fi + +export job="prepatmopeanlbc" +export jobid="${job}.$$" + +############################################################### +# Execute the JJOB +"${HOMEgfs}/jobs/JGLOBAL_ATM_PREP_OPE_ANL_BC" +status=$? +exit "${status}" diff --git a/dev/parm/config/gfs/config.base.j2 b/dev/parm/config/gfs/config.base.j2 index c2ae27a9f89..bc1f316af75 100644 --- a/dev/parm/config/gfs/config.base.j2 +++ b/dev/parm/config/gfs/config.base.j2 @@ -517,7 +517,6 @@ if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then export DO_FIT2OBS="NO" # Run fit to observations package export DO_TRACKER="NO" # Hurricane track verification export DO_GENESIS="NO" # Cyclone genesis verification - export GSIBIAS="/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/Data/testSatBiasConverter/output" fi # If starting ICs that are not at cycle hour diff --git a/dev/parm/config/gfs/config.prepatmopeanlbc b/dev/parm/config/gfs/config.prepatmopeanlbc new file mode 100644 index 00000000000..db995141b2b --- /dev/null +++ b/dev/parm/config/gfs/config.prepatmopeanlbc @@ -0,0 +1,11 @@ +#! /usr/bin/env bash + +########## config.prepatmiodaobs ########## +# Atm Operational Anl Bias Correction specific + +echo "BEGIN: config.prepatmopeanlbc" + +# Get task specific resources +. "${EXPDIR}/config.resources" prepatmopeanlbc + +echo "END: config.prepatmopeanlbc" diff --git a/jobs/JGDAS_ENKF_SELECT_OBS b/jobs/JGDAS_ENKF_SELECT_OBS index 117ba12d87c..483c3da6c86 100755 --- a/jobs/JGDAS_ENKF_SELECT_OBS +++ b/jobs/JGDAS_ENKF_SELECT_OBS @@ -76,15 +76,12 @@ if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then export DTFANL="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}analysis.dtf.a006.nc" export ATMANL="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}analysis.atm.a006.nc" export ATMINC="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}increment.atm.i006.nc" - # Copy and untar GSI BC files for ensemble - GSIBIAS_SRC=${GSIBIAS}/${GDATE}/gdas.t${gcyc}z.rad_varbc_params.tar - GSIBIAS_DET=${COMIN_ATMOS_ANALYSIS_DET_PREV}/GSIOPE/ - mkdir -p ${GSIBIAS_DET} - tar -xvf ${GSIBIAS_SRC} -C ${GSIBIAS_DET} - export GBIAS=${GSIBIAS_DET}/${GPREFIX}abias.ensmean - export GBIASPC=${GSIBIAS_DET}/${GPREFIX}abias_pc.ensmean - export GBIASAIR=${GSIBIAS_DET}/${GPREFIX}abias_air.ensmean - export GRADSTAT=${GSIBIAS_DET}/${GPREFIX}radstat.ensmean + + # Guess Bias correction coefficients related to ensemble + export GBIAS=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias.ensmean + export GBIASPC=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias_pc.ensmean + export GBIASAIR=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias_air.ensmean + export GRADSTAT=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}radstat.ensmean else # Deterministic analysis and increment files export SFCANL="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}analysis.sfc.a006.nc" diff --git a/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE b/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE index 8c43e43552e..10b4ea88d3b 100755 --- a/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE +++ b/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE @@ -27,16 +27,6 @@ else COMIN_ATMOS_ANALYSIS_PREV:COM_ATMOS_ANALYSIS_TMPL fi - -# Copy GSI BC files -if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then - GSIBIAS_SRC=${GSIBIAS}/${GDATE}/gdas.t${gcyc}z.rad_varbc_params.tar - # Need to Change - GSIBIAS_DET=${ROTDIR}/enkfgdas.${gPDY}/${gcyc}/ensstat/analysis/atmos/gdas.t${gcyc}z.rad_varbc_params.tar - - cp -r ${GSIBIAS_SRC} ${GSIBIAS_DET} -fi - ############################################################### # Run relevant script diff --git a/jobs/JGLOBAL_ATM_PREP_OPE_ANL_BC b/jobs/JGLOBAL_ATM_PREP_OPE_ANL_BC new file mode 100755 index 00000000000..acf4fa71203 --- /dev/null +++ b/jobs/JGLOBAL_ATM_PREP_OPE_ANL_BC @@ -0,0 +1,103 @@ +#! /usr/bin/env bash +source "${HOMEgfs}/ush/jjob_header.sh" -e "prepatmopeanlbc" -c "base prepatmopeanlbc" + +############################################## +# Set variables used in the script +############################################## + +############################################## +# Begin JOB SPECIFIC work +############################################## +export GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") +export gPDY=${GDATE:0:8} +export gcyc=${GDATE:8:2} +export gyy=${GDATE:0:4} +export gmm=${GDATE:4:2} +export gdd=${GDATE:6:2} +export GDUMP="gdas" + +# Generate COM variables from templates +RUN="enkfgdas" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ + COMOUT_ENS_ATMOS_ANALYSIS_PRES:COM_ENS_ATMOS_ANALYSIS_TMPL +COMIN_ATMOS_PREV=${ROTDIR}/${GDUMP}.${gPDY}/${gcyc}/atmos +OPEBIASFILES="${GDUMP}.t${gcyc}z.abias ${GDUMP}.t${gcyc}z.abias_int ${GDUMP}.t${gcyc}z.abias_pc ${GDUMP}.t${gcyc}z.radstat" + +EXSCRIPT_GEN_YAML=${RUNSATBIASCONVPY:-${USHgfs}/gen_run_satbias_conv_yaml.py} +EXSCRIPT=${RUNSATBIASCONVPY:-${USHgfs}/run_satbias_conv.py} +export EXYAML=${RUNSATBIASCONVYAML:-${USHgfs}/satbias_converter.yaml} +export EXX=${RUNSATBIASCONVX:-${EXECgfs}/satbias2ioda.x} +OUTPUT=${DATA}/output + +if [[ ! -d "${COMOUT_ENS_ATMOS_ANALYSIS_PRES}" ]]; then mkdir -p "${COMOUT_ENS_ATMOS_ANALYSIS_PRES}"; fi +if [[ ! -d "${OUTPUT}" ]]; then mkdir -p "${OUTPUT}"; fi + +if [[ ${DO_JEDIATMENS} == "YES" ]]; then + # JEDI run + cd ${DATA} + cpreq ${EXYAML} ./ + +# Generate YAML +${EXSCRIPT_GEN_YAML} -i ${TASK_CONFIG_YAML} -o run_satbias_conv.yaml +err=$? + + if [[ ${err} -eq 0 ]]; then +${EXSCRIPT} -c run_satbias_conv.yaml +err=$? + else + err_exit "Error executing ${EXSCRIPT_GEN_YAML}" + fi + + if [[ ${err} -eq 0 ]]; then + cd output/${GDUMP}.${gPDY}/${gcyc}/atmos + for file in ${OPEBIASFILES}; do + cpreq ${COMIN_ATMOS_PREV}/${file} ./${file}.ensmean + err=$? + if [[ ${err} -ne 0 ]]; then + err_exit "Error copying operational anl bias correction files" + fi + done + tar -cvf ${COMOUT_ENS_ATMOS_ANALYSIS_PRES}/${GDUMP}.t${gcyc}z.rad_varbc_params.tar * + err=$? + else + err_exit "Error executing ${EXSCRIPT}" + fi + +else + # GSI run + for file in ${OPEBIASFILES}; do + cpreq ${COMIN_ATMOS_PREV}/${file} ${OUTPUT}/${file}.ensmean + err=$? + if [[ ${err} -ne 0 ]]; then + err_exit "Error copying operational anl bias correction files" + fi + done + cd ${OUTPUT} + tar -cvf ${COMOUT_ENS_ATMOS_ANALYSIS_PRES}/${GDUMP}.t${gcyc}z.rad_varbc_params.tar * + err=$? +fi + + +if [[ ${err} -ne 0 ]]; then + err_exit "Error executing ${EXSCRIPT}" +fi +set_trace + +############################################## +# End JOB SPECIFIC work +############################################## + +############################################## +# Final processing +############################################## +if [[ -e "${pgmout}" ]]; then + cat "${pgmout}" +fi + +################################### +# Remove temp directories +################################### +if [[ "${KEEPDATA}" != "YES" ]]; then + rm -rf "${DATA}" +fi + +exit 0 diff --git a/parm/fetch/gfs_ATM_gdas-anl-gsibc.yaml.j2 b/parm/fetch/gfs_ATM_gdas-anl-gsibc.yaml.j2 new file mode 100644 index 00000000000..3c0fa88066e --- /dev/null +++ b/parm/fetch/gfs_ATM_gdas-anl-gsibc.yaml.j2 @@ -0,0 +1,16 @@ +{% set cycle_YMDH = previous_cycle | to_YMDH %} +{% set cycle_Y = previous_cycle | strftime("%Y") %} +{% set cycle_YM = previous_cycle | strftime("%Y%m") %} +{% set cycle_YMD = previous_cycle | to_YMD %} +{% set cycle_HH = previous_cycle | strftime("%H") %} +target: + tarball : "/NCEPPROD/hpssprod/runhistory/rh{{ cycle_Y }}/{{ cycle_YM }}/{{ cycle_YMD }}/com_gfs_{{ gdas_version }}_gdas.{{ cycle_YMD }}_{{ cycle_HH }}.gdas_restart.tar" + on_hpss: True + contents: + # Atmospheric analysis + - ./gdas.{{ cycle_YMD }}/{{ cycle_HH }}/atmos/gdas.t{{ cycle_HH }}z.abias + - ./gdas.{{ cycle_YMD }}/{{ cycle_HH }}/atmos/gdas.t{{ cycle_HH }}z.abias_air + - ./gdas.{{ cycle_YMD }}/{{ cycle_HH }}/atmos/gdas.t{{ cycle_HH }}z.abias_int + - ./gdas.{{ cycle_YMD }}/{{ cycle_HH }}/atmos/gdas.t{{ cycle_HH }}z.abias_pc + - ./gdas.{{ cycle_YMD }}/{{ cycle_HH }}/atmos/gdas.t{{ cycle_HH }}z.radstat + destination: "{{ ROTDIR }}" diff --git a/sorc/gdas.cd b/sorc/gdas.cd index 299f38f6ac1..f3131ae4516 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit 299f38f6ac1c313dbc8ef07b3cac1ce98b64093e +Subproject commit f3131ae4516b4e7ab4449db906c7937c97ab7df0 diff --git a/sorc/link_workflow.sh b/sorc/link_workflow.sh index d7d3bdff1ba..a28dc3ae718 100755 --- a/sorc/link_workflow.sh +++ b/sorc/link_workflow.sh @@ -267,6 +267,9 @@ if [[ -d "${HOMEgfs}/sorc/gdas.cd/build" ]]; then ${LINK_OR_COPY} "${HOMEgfs}/sorc/gdas.cd/sorc/da-utils/ush/gsincdiag_to_ioda" . cd "${HOMEgfs}/ush" || exit 1 ${LINK_OR_COPY} "${HOMEgfs}/sorc/gdas.cd/ush/ioda/bufr2ioda/run_bufr2ioda.py" . + ${LINK_OR_COPY} "${HOMEgfs}/sorc/gdas.cd/ush/run_satbias_conv.py" ./ + ${LINK_OR_COPY} "${HOMEgfs}/sorc/gdas.cd/ush/gen_run_satbias_conv_yaml.py" ./ + ${LINK_OR_COPY} "${HOMEgfs}/sorc/gdas.cd/sorc/iodaconv/test/testinput/satbias_converter.yaml" ./ ${LINK_OR_COPY} "${HOMEgfs}/sorc/gdas.cd/ush/snow/bufr_snocvr_snomad.py" . ${LINK_OR_COPY} "${HOMEgfs}/sorc/gdas.cd/build/bin/imsfv3_scf2ioda.py" . declare -a gdasapp_ocn_insitu_profile_platforms=("argo" "bathy" "glider" "marinemammal" "tesac" "xbtctd") @@ -404,6 +407,7 @@ fi if [[ -d "${HOMEgfs}/sorc/gdas.cd/install" ]]; then cp -f "${HOMEgfs}/sorc/gdas.cd/install/bin"/gdas* ./ cp -f "${HOMEgfs}/sorc/gdas.cd/install/bin/bufr2ioda.x" ./gdas_bufr2ioda.x + cp -f "${HOMEgfs}/sorc/gdas.cd/install/bin/satbias2ioda.x" ./satbias2ioda.x cp -f "${HOMEgfs}/sorc/gdas.cd/install/bin/calcfIMS.exe" ./gdas_calcfIMS.x cp -f "${HOMEgfs}/sorc/gdas.cd/install/bin/apply_incr.exe" ./gdas_apply_incr.x fi diff --git a/ush/gen_run_satbias_conv_yaml.py b/ush/gen_run_satbias_conv_yaml.py new file mode 120000 index 00000000000..ee9fc6c6cd5 --- /dev/null +++ b/ush/gen_run_satbias_conv_yaml.py @@ -0,0 +1 @@ +/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/gdas.cd/ush/gen_run_satbias_conv_yaml.py \ No newline at end of file diff --git a/ush/run_satbias_conv.py b/ush/run_satbias_conv.py new file mode 120000 index 00000000000..f9f276539a3 --- /dev/null +++ b/ush/run_satbias_conv.py @@ -0,0 +1 @@ +/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/gdas.cd/ush/run_satbias_conv.py \ No newline at end of file diff --git a/ush/satbias_converter.yaml b/ush/satbias_converter.yaml new file mode 120000 index 00000000000..fc3135ddd8b --- /dev/null +++ b/ush/satbias_converter.yaml @@ -0,0 +1 @@ +/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/gdas.cd/sorc/iodaconv/test/testinput/satbias_converter.yaml \ No newline at end of file From fc6005c6de9ed4c50d3f461c40648f6cbb36ed61 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Wed, 12 Nov 2025 23:25:29 +0000 Subject: [PATCH 05/22] Minor change with failure of gsi jobs (create_gsi_info.sh) and UFS model (global_control.nml.IN) --- dev/workflow/applications/gfs_cycled.py | 3 --- dev/workflow/rocoto/gfs_tasks.py | 2 +- parm/stage/analysis.yaml.j2 | 12 ++++++------ ush/gen_run_satbias_conv_yaml.py | 1 - ush/run_satbias_conv.py | 1 - ush/satbias_converter.yaml | 1 - 6 files changed, 7 insertions(+), 13 deletions(-) delete mode 120000 ush/gen_run_satbias_conv_yaml.py delete mode 120000 ush/run_satbias_conv.py delete mode 120000 ush/satbias_converter.yaml diff --git a/dev/workflow/applications/gfs_cycled.py b/dev/workflow/applications/gfs_cycled.py index 68f129c562e..30ae846d3d7 100644 --- a/dev/workflow/applications/gfs_cycled.py +++ b/dev/workflow/applications/gfs_cycled.py @@ -107,9 +107,6 @@ def _get_app_configs(self, run): configs = ['prep'] - if options['do_enkfonly_atm']: - configs += ['fetch', 'prepatmanlsatbias'] - if options['do_prep_sfc']: configs += ['prep_sfc'] diff --git a/dev/workflow/rocoto/gfs_tasks.py b/dev/workflow/rocoto/gfs_tasks.py index e693bccfa83..5cab12fce96 100644 --- a/dev/workflow/rocoto/gfs_tasks.py +++ b/dev/workflow/rocoto/gfs_tasks.py @@ -3130,7 +3130,7 @@ def earc_vrfy(self): if 'enkfgdas' in self.run: dep_dict = {'type': 'metatask', 'name': f'{self.run}_epmn'} deps.append(rocoto.add_dependency(dep_dict)) - if not self.options['do_enkfonly_atm']: + if not self.options['do_jediatmvar']: dep_dict = {'type': 'task', 'name': f'{self.run}_echgres'} deps.append(rocoto.add_dependency(dep_dict)) else: diff --git a/parm/stage/analysis.yaml.j2 b/parm/stage/analysis.yaml.j2 index cc7f5f2e720..4853cc55d25 100644 --- a/parm/stage/analysis.yaml.j2 +++ b/parm/stage/analysis.yaml.j2 @@ -29,14 +29,13 @@ analysis: {% endfor %} {% endfor %} - ## TODO: make these filenames the same after RE-staging inputs with EE2-compliant filenames - {% set ftypes = [ + # TODO: make these filenames the same after RE-staging inputs with EE2-compliant filenames + {% for source_ftype, dest_ftype in [ ("abias", "abias.txt"), ("abias_air", "abias_air.txt"), ("abias_int", "abias_int.txt"), ("abias_pc", "abias_pc.txt"), ("rad_varbc_params.tar", "rad_varbc_params.tar")] %} - {% for source_ftype, dest_ftype in ftypes %} {% if path_exists(ICSDIR ~ "/" ~ COMOUT_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) ~ "/" ~ RUN ~ ".t" ~ current_cycle_HH ~ "z." ~ source_ftype) %} - ["{{ ICSDIR }}/{{ COMOUT_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ RUN }}.t{{ current_cycle_HH }}z.{{ source_ftype }}", "{{ COMOUT_ATMOS_ANALYSIS_MEM }}/{{ RUN }}.t{{ current_cycle_HH }}z.{{ dest_ftype }}"] @@ -46,7 +45,8 @@ analysis: {% else %} # TODO: make these filenames the same after RE-staging inputs with EE2-compliant filenames - {% set ftypes = [ + {% for source_ftype, dest_ftype in + [ ("atminc.nc", "increment.atm.i006.nc"), ("atmi009.nc", "increment.atm.i009.nc"), ("atmi003.nc", "increment.atm.i003.nc"), @@ -58,8 +58,8 @@ analysis: ("abias_air", "abias_air.txt"), ("abias_int", "abias_int.txt"), ("abias_pc", "abias_pc.txt"), - ("rad_varbc_params.tar", "rad_varbc_params.tar") ] %} - {% for source_ftype, dest_ftype in ftypes %} + ("rad_varbc_params.tar", "rad_varbc_params.tar") + ] %} {% if path_exists(ICSDIR ~ "/" ~ COMOUT_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) ~ "/" ~ RUN ~ ".t" ~ current_cycle_HH ~ "z." ~ source_ftype) %} - ["{{ ICSDIR }}/{{ COMOUT_ATMOS_ANALYSIS_MEM | relpath(ROTDIR) }}/{{ RUN }}.t{{ current_cycle_HH }}z.{{ source_ftype }}", "{{ COMOUT_ATMOS_ANALYSIS_MEM }}/{{ RUN }}.t{{ current_cycle_HH }}z.{{ dest_ftype }}"] diff --git a/ush/gen_run_satbias_conv_yaml.py b/ush/gen_run_satbias_conv_yaml.py deleted file mode 120000 index ee9fc6c6cd5..00000000000 --- a/ush/gen_run_satbias_conv_yaml.py +++ /dev/null @@ -1 +0,0 @@ -/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/gdas.cd/ush/gen_run_satbias_conv_yaml.py \ No newline at end of file diff --git a/ush/run_satbias_conv.py b/ush/run_satbias_conv.py deleted file mode 120000 index f9f276539a3..00000000000 --- a/ush/run_satbias_conv.py +++ /dev/null @@ -1 +0,0 @@ -/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/gdas.cd/ush/run_satbias_conv.py \ No newline at end of file diff --git a/ush/satbias_converter.yaml b/ush/satbias_converter.yaml deleted file mode 120000 index fc3135ddd8b..00000000000 --- a/ush/satbias_converter.yaml +++ /dev/null @@ -1 +0,0 @@ -/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/gdas.cd/sorc/iodaconv/test/testinput/satbias_converter.yaml \ No newline at end of file From 22c0c539205a75bd89a79c63b80e2ea862a23ce3 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Thu, 13 Nov 2025 00:02:38 +0000 Subject: [PATCH 06/22] Update submodules --- sorc/gdas.cd | 2 +- sorc/gsi_enkf.fd | 2 +- sorc/ufs_model.fd | 2 +- sorc/ufs_utils.fd | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sorc/gdas.cd b/sorc/gdas.cd index dc3b9304f39..8cb610ea4ff 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit dc3b9304f396384f474a5fd910affafb0ad3f54a +Subproject commit 8cb610ea4ff5dd9cd4a27463554695ee4642dab9 diff --git a/sorc/gsi_enkf.fd b/sorc/gsi_enkf.fd index b806a99515d..7da30e79df0 160000 --- a/sorc/gsi_enkf.fd +++ b/sorc/gsi_enkf.fd @@ -1 +1 @@ -Subproject commit b806a99515d02de3fbfa80bb6336a454eabf8d8b +Subproject commit 7da30e79df0c986712c92b30de8136d7caa00adc diff --git a/sorc/ufs_model.fd b/sorc/ufs_model.fd index 4760a41a2ba..4ec82c99bda 160000 --- a/sorc/ufs_model.fd +++ b/sorc/ufs_model.fd @@ -1 +1 @@ -Subproject commit 4760a41a2ba012b236361d99a0248b718a06921b +Subproject commit 4ec82c99bda10bc886e66ff9fc2d20f41b11bd63 diff --git a/sorc/ufs_utils.fd b/sorc/ufs_utils.fd index 6c05801564a..154a3676735 160000 --- a/sorc/ufs_utils.fd +++ b/sorc/ufs_utils.fd @@ -1 +1 @@ -Subproject commit 6c05801564ae222d9232278e9a038c2add8c668d +Subproject commit 154a367673555910b57aeb5b064f2c45c2f61e05 From 9b2eaa6b48c40e28b31eff9ca48ad3cb546fbdb2 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Thu, 13 Nov 2025 18:33:01 +0000 Subject: [PATCH 07/22] Fix model and gsi oeobs failure and rename satbias to bias --- ...prepatmanlsatbias.sh => prepatmanlbias.sh} | 4 +-- dev/parm/config/gfs/config.fetch | 2 +- ...repatmanlsatbias => config.prepatmanlbias} | 6 ++--- dev/parm/config/gfs/config.resources | 4 +-- dev/workflow/applications/gfs_cycled.py | 3 +++ dev/workflow/rocoto/gfs_tasks.py | 16 +++++------ dev/workflow/rocoto/tasks.py | 2 +- jobs/JGDAS_ENKF_SELECT_OBS | 8 +++--- ..._ANL_SATBIAS => JGLOBAL_ATM_PREP_ANL_BIAS} | 27 ++++++++----------- ....yaml.j2 => gfs_ATM_gdas-anl-bias.yaml.j2} | 0 10 files changed, 35 insertions(+), 37 deletions(-) rename dev/jobs/{prepatmanlsatbias.sh => prepatmanlbias.sh} (82%) rename dev/parm/config/gfs/{config.prepatmanlsatbias => config.prepatmanlbias} (53%) rename jobs/{JGLOBAL_ATM_PREP_ANL_SATBIAS => JGLOBAL_ATM_PREP_ANL_BIAS} (77%) rename parm/fetch/{gfs_ATM_gdas-anl-satbias.yaml.j2 => gfs_ATM_gdas-anl-bias.yaml.j2} (100%) diff --git a/dev/jobs/prepatmanlsatbias.sh b/dev/jobs/prepatmanlbias.sh similarity index 82% rename from dev/jobs/prepatmanlsatbias.sh rename to dev/jobs/prepatmanlbias.sh index 30525a25273..f6e20661c8f 100755 --- a/dev/jobs/prepatmanlsatbias.sh +++ b/dev/jobs/prepatmanlbias.sh @@ -8,11 +8,11 @@ if [[ ${status} -ne 0 ]]; then exit "${status}" fi -export job="prepatmanlsatbias" +export job="prepatmanlbias" export jobid="${job}.$$" ############################################################### # Execute the JJOB -"${HOMEgfs}/jobs/JGLOBAL_ATM_PREP_ANL_SATBIAS" +"${HOMEgfs}/jobs/JGLOBAL_ATM_PREP_ANL_BIAS" status=$? exit "${status}" diff --git a/dev/parm/config/gfs/config.fetch b/dev/parm/config/gfs/config.fetch index b1c233d22ad..882db90d290 100644 --- a/dev/parm/config/gfs/config.fetch +++ b/dev/parm/config/gfs/config.fetch @@ -19,7 +19,7 @@ if [[ "${PDY}${cyc}" -gt "${SDATE}" ]]; then gdas_version="prod" fi export gdas_version - export FETCH_YAML_TMPL="${PARMgfs}/fetch/${NET}_${APP}_gdas-anl-satbias.yaml.j2" + export FETCH_YAML_TMPL="${PARMgfs}/fetch/${NET}_${APP}_gdas-anl-bias.yaml.j2" export KEEPDATA="YES" fi else diff --git a/dev/parm/config/gfs/config.prepatmanlsatbias b/dev/parm/config/gfs/config.prepatmanlbias similarity index 53% rename from dev/parm/config/gfs/config.prepatmanlsatbias rename to dev/parm/config/gfs/config.prepatmanlbias index 84e068c6505..89bfd1a247a 100644 --- a/dev/parm/config/gfs/config.prepatmanlsatbias +++ b/dev/parm/config/gfs/config.prepatmanlbias @@ -3,9 +3,9 @@ ########## config.prepatmiodaobs ########## # Atm Operational Anl Bias Correction specific -echo "BEGIN: config.prepatmanlsatbias" +echo "BEGIN: config.prepatmanlbias" # Get task specific resources -. "${EXPDIR}/config.resources" prepatmanlsatbias +. "${EXPDIR}/config.resources" prepatmanlbias -echo "END: config.prepatmanlsatbias" +echo "END: config.prepatmanlbias" diff --git a/dev/parm/config/gfs/config.resources b/dev/parm/config/gfs/config.resources index 79dc7fc87b6..84fb9d4c63b 100644 --- a/dev/parm/config/gfs/config.resources +++ b/dev/parm/config/gfs/config.resources @@ -12,7 +12,7 @@ if (( $# != 1 )); then echo "Must specify an input task argument to set resource variables!" echo "argument can be any one of the following:" echo "stage_ic aerosol_init fetch" - echo "prep prep_sfc prepatmiodaobs prepatmanlsatbias" + echo "prep prep_sfc prepatmiodaobs prepatmanlbias" echo "atmanlinit atmanlvar atmanlfv3inc atmanlfinal" echo "atmensanlinit atmensanlobs atmensanlsol atmensanlletkf atmensanlfv3inc atmensanlfinal ecen_fv3jedi analcalc_fv3jedi" echo "snowanl esnowanl" @@ -123,7 +123,7 @@ case ${step} in tasks_per_node=$(( max_tasks_per_node / threads_per_task )) ;; - "prepatmanlsatbias") + "prepatmanlbias") walltime="00:30:00" ntasks=1 threads_per_task=1 diff --git a/dev/workflow/applications/gfs_cycled.py b/dev/workflow/applications/gfs_cycled.py index 30ae846d3d7..4a085e2ec67 100644 --- a/dev/workflow/applications/gfs_cycled.py +++ b/dev/workflow/applications/gfs_cycled.py @@ -107,6 +107,9 @@ def _get_app_configs(self, run): configs = ['prep'] + if options['do_enkfonly_atm']: + configs += ['fetch', 'prepatmanlbias'] + if options['do_prep_sfc']: configs += ['prep_sfc'] diff --git a/dev/workflow/rocoto/gfs_tasks.py b/dev/workflow/rocoto/gfs_tasks.py index 5cab12fce96..93b7fc46484 100644 --- a/dev/workflow/rocoto/gfs_tasks.py +++ b/dev/workflow/rocoto/gfs_tasks.py @@ -27,7 +27,7 @@ def fetch(self): cycledef = self.run resources = self.get_resource('fetch') - task_name = f'{self.run}_fetchatmanlsatbias' + task_name = f'{self.run}_fetchatmanlbias' task_dict = {'task_name': task_name, 'resources': resources, 'dependency': dependencies, @@ -167,21 +167,21 @@ def prep(self): return task - def prepatmanlsatbias(self): + def prepatmanlbias(self): deps = [] - dep_dict = {'type': 'task', 'name': f'{self.run}_fetchatmanlsatbias'} + dep_dict = {'type': 'task', 'name': f'{self.run}_fetchatmanlbias'} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep=deps) - resources = self.get_resource('prepatmanlsatbias') - task_name = f'{self.run}_prepatmanlsatbias' + resources = self.get_resource('prepatmanlbias') + task_name = f'{self.run}_prepatmanlbias' task_dict = {'task_name': task_name, 'resources': resources, 'dependency': dependencies, 'envars': self.envars, 'cycledef': self.run.replace('enkf', ''), - 'command': f'{self.HOMEgfs}/dev/jobs/prepatmanlsatbias.sh', + 'command': f'{self.HOMEgfs}/dev/jobs/prepatmanlbias.sh', 'job_name': f'{self.pslot}_{task_name}_@H', 'log': f'{self.rotdir}/logs/@Y@m@d@H/{task_name}.log', 'maxtries': '&MAXTRIES;' @@ -2596,7 +2596,7 @@ def eobs(self): dep_dict = {'type': 'metatask', 'name': 'enkfgdas_epmn', 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} deps.append(rocoto.add_dependency(dep_dict)) if self.options['do_enkfonly_atm']: - dep_dict = {'type': 'task', 'name': f'{self.run.replace("enkf", "")}_prepatmanlsatbias'} + dep_dict = {'type': 'task', 'name': f'{self.run.replace("enkf", "")}_prepatmanlbias'} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) @@ -2670,7 +2670,7 @@ def atmensanlinit(self): dep_dict = {'type': 'metatask', 'name': 'enkfgdas_epmn', 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} deps.append(rocoto.add_dependency(dep_dict)) if self.options['do_enkfonly_atm']: - dep_dict = {'type': 'task', 'name': f'{self.run.replace("enkf", "")}_prepatmanlsatbias'} + dep_dict = {'type': 'task', 'name': f'{self.run.replace("enkf", "")}_prepatmanlbias'} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) diff --git a/dev/workflow/rocoto/tasks.py b/dev/workflow/rocoto/tasks.py index c947511e1a0..e1a0a3da8b9 100644 --- a/dev/workflow/rocoto/tasks.py +++ b/dev/workflow/rocoto/tasks.py @@ -17,7 +17,7 @@ class Tasks: 'prep_sfc', 'prep', 'anal', 'sfcanl', 'analcalc', 'analdiag', 'arch_vrfy', 'arch_tars', 'cleanup', 'ecen_fv3jedi', 'analcalc_fv3jedi', 'cleanup', 'prepatmiodaobs', 'atmanlinit', 'atmanlvar', 'atmanlfv3inc', 'atmanlfinal', - 'prep_emissions', 'prepoceanobs', 'prepatmanlsatbias', + 'prep_emissions', 'prepoceanobs', 'prepatmanlbias', 'marineanlinit', 'marineanlletkf', 'marinebmatinit', 'marinebmat', 'marineanlvar', 'marineanlecen', 'marineanlchkpt', 'marineanlfinal', 'ocnanalvrfy', 'eobs', 'epos', 'esfc', 'eupd', diff --git a/jobs/JGDAS_ENKF_SELECT_OBS b/jobs/JGDAS_ENKF_SELECT_OBS index ea1825d1a11..a51dd4b11e0 100755 --- a/jobs/JGDAS_ENKF_SELECT_OBS +++ b/jobs/JGDAS_ENKF_SELECT_OBS @@ -73,10 +73,10 @@ if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then export ATMINC="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}increment.atm.i006.nc" # Guess Bias correction coefficients related to ensemble - export GBIAS=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias.ensmean - export GBIASPC=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias_pc.ensmean - export GBIASAIR=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias_air.ensmean - export GRADSTAT=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}radstat.ensmean + export GBIAS=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias.txt + export GBIASPC=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias_pc.txt + export GBIASAIR=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias_air.txt + export GRADSTAT=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}radstat.txt else # Deterministic analysis and increment files export SFCANL="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}analysis.sfc.a006.nc" diff --git a/jobs/JGLOBAL_ATM_PREP_ANL_SATBIAS b/jobs/JGLOBAL_ATM_PREP_ANL_BIAS similarity index 77% rename from jobs/JGLOBAL_ATM_PREP_ANL_SATBIAS rename to jobs/JGLOBAL_ATM_PREP_ANL_BIAS index 0423c8d3caf..54a911b9b70 100755 --- a/jobs/JGLOBAL_ATM_PREP_ANL_SATBIAS +++ b/jobs/JGLOBAL_ATM_PREP_ANL_BIAS @@ -1,7 +1,7 @@ #! /usr/bin/env bash export WIPE_DATA="NO" export DATA=${DATA:-${DATAROOT}/${RUN}fetch_${cyc}} -source "${HOMEgfs}/ush/jjob_header.sh" -e "prepatmanlsatbias" -c "base prepatmanlsatbias" +source "${HOMEgfs}/ush/jjob_header.sh" -e "prepatmanlbias" -c "base prepatmanlbias" ############################################## # Set variables used in the script @@ -22,9 +22,9 @@ export GDUMP="gdas" MEMDIR="ensstat" RUN="enkf${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ COMOUT_ATMOS_ANALYSIS_PREV:COM_ATMOS_ANALYSIS_TMPL \ -# Process bias corrections files grabbed from HPSS in task gdas_fetchatmanlsatbias -SATBIASDIR=${DATA}/${GDUMP}.${gPDY}/${gcyc}/atmos -SATBIASFILES="${GDUMP}.t${gcyc}z.abias ${GDUMP}.t${gcyc}z.abias_int ${GDUMP}.t${gcyc}z.abias_pc ${GDUMP}.t${gcyc}z.radstat" +# Process bias corrections files grabbed from HPSS in task gdas_fetchatmanlbias +BIASDIR=${DATA}/${GDUMP}.${gPDY}/${gcyc}/atmos +BIASFILES="${GDUMP}.t${gcyc}z.abias ${GDUMP}.t${gcyc}z.abias_air ${GDUMP}.t${gcyc}z.abias_int ${GDUMP}.t${gcyc}z.abias_pc ${GDUMP}.t${gcyc}z.radstat" EXSCRIPT_GEN_YAML=${RUNSATBIASCONVPY:-${USHgfs}/gen_run_satbias_conv_yaml.py} EXSCRIPT=${RUNSATBIASCONVPY:-${USHgfs}/run_satbias_conv.py} @@ -49,38 +49,33 @@ err=$? if [[ ${err} -eq 0 ]]; then ${EXSCRIPT} -c run_satbias_conv.yaml err=$? - else - err_exit "Error executing ${EXSCRIPT_GEN_YAML}" fi if [[ ${err} -eq 0 ]]; then cd ${OUTPUT}/${GDUMP}.${gPDY}/${gcyc}/atmos - for file in ${SATBIASFILES}; do - cpreq ${SATBIASDIR}/${file} ./${file}.ensmean + for file in ${BIASFILES}; do + cpreq ${BIASDIR}/${file} ./enkf${file}.txt err=$? if [[ ${err} -ne 0 ]]; then err_exit "Error copying operational anl bias correction files" fi done + # TODO: Temporary solution and need to process abias_air for JEDI when ready + tar -cvf ${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.air_varbc_params.tar enkf${GDUMP}.t${gcyc}z.abias_air.txt + rm -rf enkf${GDUMP}.t${gcyc}z.abias_air.txt tar -cvf ${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.rad_varbc_params.tar * err=$? - else - err_exit "Error executing ${EXSCRIPT}" fi else # GSI run - if [[ ! -d "${OUTPUT}" ]]; then mkdir -p "${OUTPUT}"; fi - for file in ${SATBIASFILES}; do - cpreq ${SATBIASDIR}/${file} ${OUTPUT}/${file}.ensmean + for file in ${BIASFILES}; do + cpreq ${BIASDIR}/${file} ${COMOUT_ATMOS_ANALYSIS_PREV}/enkf${file}.txt err=$? if [[ ${err} -ne 0 ]]; then err_exit "Error copying operational anl bias correction files" fi done - cd ${OUTPUT} - tar -cvf ${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.rad_varbc_params.tar * - err=$? fi diff --git a/parm/fetch/gfs_ATM_gdas-anl-satbias.yaml.j2 b/parm/fetch/gfs_ATM_gdas-anl-bias.yaml.j2 similarity index 100% rename from parm/fetch/gfs_ATM_gdas-anl-satbias.yaml.j2 rename to parm/fetch/gfs_ATM_gdas-anl-bias.yaml.j2 From 85ed17bc2dd6f53595c1a34b5d4cd377b2185fb7 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Thu, 13 Nov 2025 20:14:11 +0000 Subject: [PATCH 08/22] Fix python coding norm error --- dev/workflow/applications/gfs_cycled.py | 6 +++--- dev/workflow/rocoto/gfs_tasks.py | 4 ++-- scripts/exglobal_stage_ic.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/workflow/applications/gfs_cycled.py b/dev/workflow/applications/gfs_cycled.py index 4a085e2ec67..92dda83979c 100644 --- a/dev/workflow/applications/gfs_cycled.py +++ b/dev/workflow/applications/gfs_cycled.py @@ -383,9 +383,9 @@ def get_task_names(self): # Reset tasks to run enkf-only for atm if do_enkfonly_atm=true if options['do_enkfonly_atm']: - if run == 'gdas': - task_names[run] = [] - task_names[run] += ['prep', 'fetch', 'prepatmanlsatbias'] + if run == 'gdas': + task_names[run] = [] + task_names[run] += ['prep', 'fetch', 'prepatmanlsatbias'] if options['do_jediatmvar']: task_names[run] += ['prepatmiodaobs'] diff --git a/dev/workflow/rocoto/gfs_tasks.py b/dev/workflow/rocoto/gfs_tasks.py index 93b7fc46484..7bce2f1fa6d 100644 --- a/dev/workflow/rocoto/gfs_tasks.py +++ b/dev/workflow/rocoto/gfs_tasks.py @@ -30,7 +30,7 @@ def fetch(self): task_name = f'{self.run}_fetchatmanlbias' task_dict = {'task_name': task_name, 'resources': resources, - 'dependency': dependencies, + 'dependency': dependencies, 'envars': self.envars, 'cycledef': cycledef, 'command': f'{self.HOMEgfs}/dev/jobs/fetch.sh', @@ -50,7 +50,7 @@ def fetch(self): 'command': f'{self.HOMEgfs}/dev/jobs/fetch.sh', 'job_name': f'{self.pslot}_{task_name}_@H', 'log': f'{self.rotdir}/logs/@Y@m@d@H/{task_name}.log', - 'maxtries': '&MAXTRIES;' + 'maxtries': '&MAXTRIES;' } task = rocoto.create_task(task_dict) diff --git a/scripts/exglobal_stage_ic.py b/scripts/exglobal_stage_ic.py index cbce5d50dcd..e95dc42efd8 100755 --- a/scripts/exglobal_stage_ic.py +++ b/scripts/exglobal_stage_ic.py @@ -24,7 +24,7 @@ def main(): 'OCNRES', 'waveGRD', 'ntiles', 'DOIAU', 'DO_JEDIOCNVAR', 'DO_STARTMEM_FROM_JEDIICE', 'DO_WAVE', 'DO_OCN', 'DO_ICE', 'DO_NEST', 'DO_CA', 'DO_AERO_ANL', - 'USE_ATM_ENS_PERTURB_FILES', 'USE_OCN_ENS_PERTURB_FILES', 'DO_GSISOILDA', 'DO_LAND_IAU', + 'USE_ATM_ENS_PERTURB_FILES', 'USE_OCN_ENS_PERTURB_FILES', 'DO_GSISOILDA', 'DO_LAND_IAU', 'DOENKFONLY_ATM'] stage_dict = AttrDict() From e8806e4d7b2848f162ce08bda4b4fd2fd4fdc612 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Thu, 13 Nov 2025 23:26:38 +0000 Subject: [PATCH 09/22] 1st clean/ready version that pass JEDI and GSI test --- dev/workflow/applications/gfs_cycled.py | 2 +- sorc/gdas.cd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/workflow/applications/gfs_cycled.py b/dev/workflow/applications/gfs_cycled.py index 92dda83979c..90a94920bc4 100644 --- a/dev/workflow/applications/gfs_cycled.py +++ b/dev/workflow/applications/gfs_cycled.py @@ -385,7 +385,7 @@ def get_task_names(self): if options['do_enkfonly_atm']: if run == 'gdas': task_names[run] = [] - task_names[run] += ['prep', 'fetch', 'prepatmanlsatbias'] + task_names[run] += ['prep', 'fetch', 'prepatmanlbias'] if options['do_jediatmvar']: task_names[run] += ['prepatmiodaobs'] diff --git a/sorc/gdas.cd b/sorc/gdas.cd index 8cb610ea4ff..c0651a38fba 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit 8cb610ea4ff5dd9cd4a27463554695ee4642dab9 +Subproject commit c0651a38fba46cf9a91eecab5310dd656f8c5715 From 4f5806d0af50c5f25bd3a8df831d19f0cd1ca003 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Fri, 14 Nov 2025 17:26:55 +0000 Subject: [PATCH 10/22] Git shellcheck change to 1st clean version --- dev/jobs/prep.sh | 14 +++++++------- jobs/JGDAS_ENKF_SELECT_OBS | 16 ++++++++-------- jobs/JGLOBAL_ATM_PREP_ANL_BIAS | 16 ++++++++-------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/dev/jobs/prep.sh b/dev/jobs/prep.sh index 805e19388a1..61f201a2614 100755 --- a/dev/jobs/prep.sh +++ b/dev/jobs/prep.sh @@ -119,13 +119,13 @@ if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then MEMDIR="ensstat" RUN="enkf${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx COMIN_ATMOS_HISTORY_ENS_STAT_PREV:COM_ATMOS_HISTORY_TMPL MEMDIR="mem001" RUN="enkf${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx COMIN_ATMOS_HISTORY_ENS_MEM001_PREV:COM_ATMOS_HISTORY_TMPL RUN="gdas" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx COMOUT_ATMOS_HISTORY_DET_PREV:COM_ATMOS_HISTORY_TMPL - mkdir -p $COMOUT_ATMOS_HISTORY_DET_PREV - ln -sf $COMIN_ATMOS_HISTORY_ENS_MEM001_PREV/enkfgdas.t${gcyc}z.log.f003.txt $COMOUT_ATMOS_HISTORY_DET_PREV/gdas.t${gcyc}z.log.f003.txt - ln -sf $COMIN_ATMOS_HISTORY_ENS_MEM001_PREV/enkfgdas.t${gcyc}z.log.f006.txt $COMOUT_ATMOS_HISTORY_DET_PREV/gdas.t${gcyc}z.log.f006.txt - ln -sf $COMIN_ATMOS_HISTORY_ENS_MEM001_PREV/enkfgdas.t${gcyc}z.log.f009.txt $COMOUT_ATMOS_HISTORY_DET_PREV/gdas.t${gcyc}z.log.f009.txt - ln -sf $COMIN_ATMOS_HISTORY_ENS_STAT_PREV/enkfgdas.t${gcyc}z.ensmean.atm.f003.nc $COMOUT_ATMOS_HISTORY_DET_PREV/gdas.t${gcyc}z.atm.f003.nc - ln -sf $COMIN_ATMOS_HISTORY_ENS_STAT_PREV/enkfgdas.t${gcyc}z.ensmean.atm.f006.nc $COMOUT_ATMOS_HISTORY_DET_PREV/gdas.t${gcyc}z.atm.f006.nc - ln -sf $COMIN_ATMOS_HISTORY_ENS_STAT_PREV/enkfgdas.t${gcyc}z.ensmean.atm.f009.nc $COMOUT_ATMOS_HISTORY_DET_PREV/gdas.t${gcyc}z.atm.f009.nc + mkdir -p ${COMOUT_ATMOS_HISTORY_DET_PREV} + ln -sf "${COMIN_ATMOS_HISTORY_ENS_MEM001_PREV}/enkfgdas.t${gcyc}z.log.f003.txt" "${COMOUT_ATMOS_HISTORY_DET_PREV}/gdas.t${gcyc}z.log.f003.txt" + ln -sf "${COMIN_ATMOS_HISTORY_ENS_MEM001_PREV}/enkfgdas.t${gcyc}z.log.f006.txt" "${COMOUT_ATMOS_HISTORY_DET_PREV}/gdas.t${gcyc}z.log.f006.txt" + ln -sf "${COMIN_ATMOS_HISTORY_ENS_MEM001_PREV}/enkfgdas.t${gcyc}z.log.f009.txt" "${COMOUT_ATMOS_HISTORY_DET_PREV}/gdas.t${gcyc}z.log.f009.txt" + ln -sf "${COMIN_ATMOS_HISTORY_ENS_STAT_PREV}/enkfgdas.t${gcyc}z.ensmean.atm.f003.nc" "${COMOUT_ATMOS_HISTORY_DET_PREV}/gdas.t${gcyc}z.atm.f003.nc" + ln -sf "${COMIN_ATMOS_HISTORY_ENS_STAT_PREV}/enkfgdas.t${gcyc}z.ensmean.atm.f006.nc" "${COMOUT_ATMOS_HISTORY_DET_PREV}/gdas.t${gcyc}z.atm.f006.nc" + ln -sf "${COMIN_ATMOS_HISTORY_ENS_STAT_PREV}/enkfgdas.t${gcyc}z.ensmean.atm.f009.nc" "${COMOUT_ATMOS_HISTORY_DET_PREV}/gdas.t${gcyc}z.atm.f009.nc" fi # Create or Copy prepbufr, prepbufr.acft_profiles, nsstbufr files diff --git a/jobs/JGDAS_ENKF_SELECT_OBS b/jobs/JGDAS_ENKF_SELECT_OBS index a51dd4b11e0..0616aec1b48 100755 --- a/jobs/JGDAS_ENKF_SELECT_OBS +++ b/jobs/JGDAS_ENKF_SELECT_OBS @@ -73,10 +73,10 @@ if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then export ATMINC="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}increment.atm.i006.nc" # Guess Bias correction coefficients related to ensemble - export GBIAS=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias.txt - export GBIASPC=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias_pc.txt - export GBIASAIR=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias_air.txt - export GRADSTAT=${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}radstat.txt + export GBIAS="${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias.txt" + export GBIASPC="${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias_pc.txt" + export GBIASAIR="${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}abias_air.txt" + export GRADSTAT="${COMIN_ATMOS_ANALYSIS_PREV}/${GPREFIX}radstat.txt" else # Deterministic analysis and increment files export SFCANL="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}analysis.sfc.a006.nc" @@ -85,10 +85,10 @@ else export ATMINC="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}increment.atm.i006.nc" # Guess Bias correction coefficients related to control - export GBIAS=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias.txt - export GBIASPC=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias_pc.txt - export GBIASAIR=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias_air.txt - export GRADSTAT=${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}radstat.tar + export GBIAS="${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias.txt" + export GBIASPC="${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias_pc.txt" + export GBIASAIR="${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}abias_air.txt" + export GRADSTAT="${COMIN_ATMOS_ANALYSIS_DET_PREV}/${GPREFIX_DET}radstat.tar" fi # Bias correction coefficients related to ensemble mean diff --git a/jobs/JGLOBAL_ATM_PREP_ANL_BIAS b/jobs/JGLOBAL_ATM_PREP_ANL_BIAS index 54a911b9b70..0146936292e 100755 --- a/jobs/JGLOBAL_ATM_PREP_ANL_BIAS +++ b/jobs/JGLOBAL_ATM_PREP_ANL_BIAS @@ -39,8 +39,8 @@ if [[ -d "${PYRUNTMP}" ]]; then rm -rf "${PYRUNTMP}"; fi if [[ ${DO_JEDIATMENS} == "YES" ]]; then # JEDI run - cd ${DATA} - cpreq ${EXYAML} ./ + cd "${DATA}" || exit + cpreq "${EXYAML}" "./" # Generate YAML ${EXSCRIPT_GEN_YAML} -o run_satbias_conv.yaml @@ -52,25 +52,25 @@ err=$? fi if [[ ${err} -eq 0 ]]; then - cd ${OUTPUT}/${GDUMP}.${gPDY}/${gcyc}/atmos + cd "${OUTPUT}/${GDUMP}.${gPDY}/${gcyc}/atmos" || exit for file in ${BIASFILES}; do - cpreq ${BIASDIR}/${file} ./enkf${file}.txt + cpreq "${BIASDIR}/${file}" "./enkf${file}.txt" err=$? if [[ ${err} -ne 0 ]]; then err_exit "Error copying operational anl bias correction files" fi done # TODO: Temporary solution and need to process abias_air for JEDI when ready - tar -cvf ${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.air_varbc_params.tar enkf${GDUMP}.t${gcyc}z.abias_air.txt - rm -rf enkf${GDUMP}.t${gcyc}z.abias_air.txt - tar -cvf ${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.rad_varbc_params.tar * + tar -cvf "${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.air_varbc_params.tar" "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" + rm -rf "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" + tar -cvf "${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.rad_varbc_params.tar" "./*.txt ./*.nc" err=$? fi else # GSI run for file in ${BIASFILES}; do - cpreq ${BIASDIR}/${file} ${COMOUT_ATMOS_ANALYSIS_PREV}/enkf${file}.txt + cpreq "${BIASDIR}/${file}" "${COMOUT_ATMOS_ANALYSIS_PREV}/enkf${file}.txt" err=$? if [[ ${err} -ne 0 ]]; then err_exit "Error copying operational anl bias correction files" From be8c47910b8a26c3cb22d84ed41f71f9b26784b9 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Fri, 14 Nov 2025 17:29:41 +0000 Subject: [PATCH 11/22] Git shellcheck change 2 to 1st clean version --- dev/jobs/prep.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/jobs/prep.sh b/dev/jobs/prep.sh index 61f201a2614..c880497e20c 100755 --- a/dev/jobs/prep.sh +++ b/dev/jobs/prep.sh @@ -119,7 +119,7 @@ if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then MEMDIR="ensstat" RUN="enkf${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx COMIN_ATMOS_HISTORY_ENS_STAT_PREV:COM_ATMOS_HISTORY_TMPL MEMDIR="mem001" RUN="enkf${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx COMIN_ATMOS_HISTORY_ENS_MEM001_PREV:COM_ATMOS_HISTORY_TMPL RUN="gdas" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx COMOUT_ATMOS_HISTORY_DET_PREV:COM_ATMOS_HISTORY_TMPL - mkdir -p ${COMOUT_ATMOS_HISTORY_DET_PREV} + mkdir -p "${COMOUT_ATMOS_HISTORY_DET_PREV}" ln -sf "${COMIN_ATMOS_HISTORY_ENS_MEM001_PREV}/enkfgdas.t${gcyc}z.log.f003.txt" "${COMOUT_ATMOS_HISTORY_DET_PREV}/gdas.t${gcyc}z.log.f003.txt" ln -sf "${COMIN_ATMOS_HISTORY_ENS_MEM001_PREV}/enkfgdas.t${gcyc}z.log.f006.txt" "${COMOUT_ATMOS_HISTORY_DET_PREV}/gdas.t${gcyc}z.log.f006.txt" ln -sf "${COMIN_ATMOS_HISTORY_ENS_MEM001_PREV}/enkfgdas.t${gcyc}z.log.f009.txt" "${COMOUT_ATMOS_HISTORY_DET_PREV}/gdas.t${gcyc}z.log.f009.txt" From fa9ff54969ba966877fee4d39a6ae7f9f14d268a Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Mon, 1 Dec 2025 23:27:48 +0000 Subject: [PATCH 12/22] Address David's comments and need to update to recent NOAA EMC develop --- jobs/JGLOBAL_ATM_PREP_ANL_BIAS | 2 +- sorc/gdas.cd | 2 +- ush/python/pygfs/task/atmens_analysis.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jobs/JGLOBAL_ATM_PREP_ANL_BIAS b/jobs/JGLOBAL_ATM_PREP_ANL_BIAS index 0146936292e..2dc5971abfb 100755 --- a/jobs/JGLOBAL_ATM_PREP_ANL_BIAS +++ b/jobs/JGLOBAL_ATM_PREP_ANL_BIAS @@ -63,7 +63,7 @@ err=$? # TODO: Temporary solution and need to process abias_air for JEDI when ready tar -cvf "${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.air_varbc_params.tar" "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" rm -rf "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" - tar -cvf "${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.rad_varbc_params.tar" "./*.txt ./*.nc" + tar -cvf "${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.rad_varbc_params.tar" * err=$? fi diff --git a/sorc/gdas.cd b/sorc/gdas.cd index c0651a38fba..3cc019d5a1c 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit c0651a38fba46cf9a91eecab5310dd656f8c5715 +Subproject commit 3cc019d5a1c24225a09ae73184dfa2c9c60f5562 diff --git a/ush/python/pygfs/task/atmens_analysis.py b/ush/python/pygfs/task/atmens_analysis.py index 646dda268f3..130c438d491 100644 --- a/ush/python/pygfs/task/atmens_analysis.py +++ b/ush/python/pygfs/task/atmens_analysis.py @@ -35,8 +35,6 @@ def __init__(self, config: Dict[str, Any]): _res = int(self.task_config.CASE_ENS[1:]) - self.task_config.letkf_app = "true" - # Create a local dictionary that is repeatedly used across this class self.task_config.update(AttrDict( { @@ -45,6 +43,8 @@ def __init__(self, config: Dict[str, Any]): 'npz_ges': self.task_config.LEVS - 1, 'npz': self.task_config.LEVS - 1, 'BKG_TSTEP': "PT1H", # Placeholder for 4D applications + 'letkf_app': "true", + 'atm_enkfonly': self.task_config.DOENKFONLY_ATM, }) ) From 8fd40d6b6380b183f807091eaf4fee2f9b86b88d Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Thu, 11 Dec 2025 22:24:16 +0000 Subject: [PATCH 13/22] remove temporary files --- jobs/@! | 132 ------------------------------- sorc/gdas.cd | 2 +- ush/gen_run_satbias_conv_yaml.py | 1 - ush/run_bufr2ioda.py | 1 - ush/run_satbias_conv.py | 1 - ush/satbias_converter.yaml | 1 - 6 files changed, 1 insertion(+), 137 deletions(-) delete mode 100644 jobs/@! delete mode 120000 ush/gen_run_satbias_conv_yaml.py delete mode 120000 ush/run_bufr2ioda.py delete mode 120000 ush/run_satbias_conv.py delete mode 120000 ush/satbias_converter.yaml diff --git a/jobs/@! b/jobs/@! deleted file mode 100644 index f56e3895b05..00000000000 --- a/jobs/@! +++ /dev/null @@ -1,132 +0,0 @@ -#! /usr/bin/env bash -export WIPE_DATA="NO" -export DATA=${DATA:-${DATAROOT}/${RUN}fetch_${cyc}} -source "${HOMEgfs}/ush/jjob_header.sh" -e "prepatmanlbias" -c "base prepatmanlbias" - -############################################## -# Set variables used in the script -############################################## - -############################################## -# Begin JOB SPECIFIC work -############################################## -export GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") -export gPDY=${GDATE:0:8} -export gcyc=${GDATE:8:2} -export gyy=${GDATE:0:4} -export gmm=${GDATE:4:2} -export gdd=${GDATE:6:2} -export GDUMP="gdas" - -# Generate COM variables from templates -MEMDIR="ensstat" RUN="enkf${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ - COMOUT_ATMOS_ANALYSIS_PREV:COM_ATMOS_ANALYSIS_TMPL \ - -# Process bias corrections files grabbed from HPSS in task gdas_fetchatmanlbias -BIASDIR=${DATA}/${GDUMP}.${gPDY}/${gcyc}/atmos -BIASFILES="${GDUMP}.t${gcyc}z.abias ${GDUMP}.t${gcyc}z.abias_air ${GDUMP}.t${gcyc}z.abias_int ${GDUMP}.t${gcyc}z.abias_pc ${GDUMP}.t${gcyc}z.radstat" - -ABIAS_RAD=${BIASDIR}/${GDUMP}.t${gcyc}z.abias -ABIASPC_RAD=${BIASDIR}/${GDUMP}.t${gcyc}z.abias_pc -ABIAS_RAD_JEDI=${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.rad_varbc_params.tar -ABIAS_AIR_JEDI=${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.air_varbc_params.tar - -#EXSCRIPT_GEN_YAML=${RUNSATBIASCONVPY:-${USHgfs}/gen_run_satbias_conv_yaml.py} -#EXSCRIPT=${RUNSATBIASCONVPY:-${USHgfs}/run_satbias_conv.py} -#EXYAML=${RUNSATBIASCONVYAML:-${USHgfs}/satbias_converter.yaml} -#export EXX=${RUNSATBIASCONVX:-${EXECgfs}/satbias2ioda.x} -SATBIAS2IODAX=${SATBIAS2IODAX:-${EXECgfs}/satbias2ioda.x} -SATBIAS2IODAY=${SATBIAS2IODAX:-${USHgfs}/satbias_converter.yaml.tmpl} -OUTPUT=${DATA}/output -PYRUNTMP=${DATA}/tmp - -if [[ ! -d "${COMOUT_ATMOS_ANALYSIS_PREV}" ]]; then mkdir -p "${COMOUT_ATMOS_ANALYSIS_PREV}"; fi -if [[ -d "${OUTPUT}" ]]; then rm -rf "${OUTPUT}"; fi -if [[ -d "${PYRUNTMP}" ]]; then rm -rf "${PYRUNTMP}"; fi - -if [[ ${DO_JEDIATMENS} == "YES" ]]; then - # JEDI run - cd "${DATA}" || exit - /bin/ln -sf ${ABIAS_RAD} ./satbias_in - /bin/ln -sf ${ABIASPC_RAD} ./satbias_pc - grep -i 'NaN' satbias_in && echo 'Stop. There are NaN in ${ABIAS}.' && exit 1 - - # Get instruments from satbias_in - obsclass=`grep '_' satbias_in | awk '{print $2}' | uniq` - - # Loop over instruments. Covert GSI abias to JEDI format - for instrument in $(echo $obsclass); do - echo ${instrument} - /bin/cp -f ${SATBIAS2IODA_Y} satbias_converter.yaml - sed -i -e "s/INSTRUMENT/${instrument}/g" satbias_converter.yaml - - ${SATBIAS2IODA_x} satbias_converter.yaml - - export err=$? - if [[ ${err} -ne 0 ]]; then - err_exit "satbias2iodas.x failed for ${instrument}, ABORT!" - fi - - /bin/rm -f testrun/varbc/*nc - /bin/rm -f testrun/varbc/*txt - - cd ./testrun/varbc/ - grep ${instrument} ../../satbias_in | awk '{print $2" "$3" "$4}' > \ - ${OUTPUT}/gdas.t${gcyc}z.${instrument}.tlapse.txt - /bin/cp -p satbias_${instrument}.nc4 ${OUTPUT}/gdas.t${gcyc}z.${instrument}.satbias.nc - /bin/mv satbias_${instrument}.nc4 ${OUTPUT}/gdas.t${gcyc}z.${instrument}.satbias_cov.nc - - done - - if [[ ${err} -eq 0 ]]; then - cd "${OUTPUT}/${GDUMP}.${gPDY}/${gcyc}/atmos" || exit - for file in ${BIASFILES}; do - cpreq "${BIASDIR}/${file}" "./enkf${file}.txt" - err=$? - if [[ ${err} -ne 0 ]]; then - err_exit "Error copying operational anl bias correction files" - fi - done - # TODO: Temporary solution and need to process abias_air for JEDI when ready - tar -cvf ${ABIAS_AIR_JEDI} "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" - rm -rf "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" - tar -cvf ${ABIAS_RAD_JEDI} * - err=$? - fi - -else - # GSI run - for file in ${BIASFILES}; do - cpreq "${BIASDIR}/${file}" "${COMOUT_ATMOS_ANALYSIS_PREV}/enkf${file}.txt" - err=$? - if [[ ${err} -ne 0 ]]; then - err_exit "Error copying operational anl bias correction files" - fi - done -fi - - -if [[ ${err} -ne 0 ]]; then - err_exit "Error executing ${EXSCRIPT}" -fi -set_trace - -############################################## -# End JOB SPECIFIC work -############################################## - -############################################## -# Final processing -############################################## -if [[ -e "${pgmout}" ]]; then - cat "${pgmout}" -fi - -################################### -# Remove temp directories -################################### -if [[ "${KEEPDATA}" != "YES" ]]; then - rm -rf "${DATA}" -fi - -exit 0 diff --git a/sorc/gdas.cd b/sorc/gdas.cd index c3b2bab1645..2e104c7b4fa 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit c3b2bab1645a0bde18e5dc8944b457a27d672bd0 +Subproject commit 2e104c7b4fa537f4261124513027909f3cff6ca8 diff --git a/ush/gen_run_satbias_conv_yaml.py b/ush/gen_run_satbias_conv_yaml.py deleted file mode 120000 index ee9fc6c6cd5..00000000000 --- a/ush/gen_run_satbias_conv_yaml.py +++ /dev/null @@ -1 +0,0 @@ -/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/gdas.cd/ush/gen_run_satbias_conv_yaml.py \ No newline at end of file diff --git a/ush/run_bufr2ioda.py b/ush/run_bufr2ioda.py deleted file mode 120000 index d2b835cd57e..00000000000 --- a/ush/run_bufr2ioda.py +++ /dev/null @@ -1 +0,0 @@ -/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/gdas.cd/ush/ioda/bufr2ioda/run_bufr2ioda.py \ No newline at end of file diff --git a/ush/run_satbias_conv.py b/ush/run_satbias_conv.py deleted file mode 120000 index f9f276539a3..00000000000 --- a/ush/run_satbias_conv.py +++ /dev/null @@ -1 +0,0 @@ -/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/gdas.cd/ush/run_satbias_conv.py \ No newline at end of file diff --git a/ush/satbias_converter.yaml b/ush/satbias_converter.yaml deleted file mode 120000 index fc3135ddd8b..00000000000 --- a/ush/satbias_converter.yaml +++ /dev/null @@ -1 +0,0 @@ -/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/gdas.cd/sorc/iodaconv/test/testinput/satbias_converter.yaml \ No newline at end of file From 84731f360746a3755274f67e97d167e187640f13 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Tue, 16 Dec 2025 18:32:50 +0000 Subject: [PATCH 14/22] Issue #4339: Enable EnKF-only for atmosphere (2nd try): remove temporary file --- ush/forecast_postdet.sh-myMod1 | 1163 -------------------------------- 1 file changed, 1163 deletions(-) delete mode 100755 ush/forecast_postdet.sh-myMod1 diff --git a/ush/forecast_postdet.sh-myMod1 b/ush/forecast_postdet.sh-myMod1 deleted file mode 100755 index 3d169b54f38..00000000000 --- a/ush/forecast_postdet.sh-myMod1 +++ /dev/null @@ -1,1163 +0,0 @@ -#! /usr/bin/env bash - -# Disable variable not used warnings -# shellcheck disable=SC2034 -# shellcheck disable=SC2178 -FV3_postdet() { - echo "SUB ${FUNCNAME[0]}: Entering for RUN = ${RUN}" - - echo "warm_start = ${warm_start}" - echo "RERUN = ${RERUN}" - - #============================================================================ - # First copy initial conditions - # cold start case - if [[ "${warm_start}" == ".false." ]]; then - - # Get list of FV3 cold start files - local file_list - file_list=$(FV3_coldstarts) - echo "Copying FV3 cold start files for 'RUN=${RUN}' at '${current_cycle}' from '${COMIN_ATMOS_INPUT}'" - local fv3_file - for fv3_file in ${file_list}; do - cpreq "${COMIN_ATMOS_INPUT}/${fv3_file}" "${DATA}/INPUT/${fv3_file}" - done - - # warm start case - elif [[ "${warm_start}" == ".true." ]]; then - - # Determine restart date and directory containing restarts - local restart_date restart_dir - if [[ "${RERUN}" == "YES" ]]; then - restart_date="${RERUN_DATE}" - restart_dir="${DATArestart}/FV3_RESTART" - else # "${RERUN}" == "NO" - restart_date="${model_start_date_current_cycle}" - restart_dir="${COMIN_ATMOS_RESTART_PREV}" - fi - - # Get list of FV3 restart files - local file_list - file_list=$(FV3_restarts) - echo "Copying FV3 restarts for 'RUN=${RUN}' at '${restart_date}' from '${restart_dir}'" - local fv3_file restart_file - for fv3_file in ${file_list}; do - restart_file="${restart_date:0:8}.${restart_date:8:2}0000.${fv3_file}" - cpreq "${restart_dir}/${restart_file}" "${DATA}/INPUT/${fv3_file}" - done - - if [[ "${RERUN}" == "YES" ]]; then - if [[ "${DO_SPPT:-}" == "YES" || "${DO_SKEB:-}" == "YES" || - "${DO_SHUM:-}" == "YES" || "${DO_LAND_PERT:-}" == "YES" ]]; then - stochini=".true." - file_list=$(stoch_restarts) - echo "Copying stochastic restarts for 'RUN=${RUN}' at '${restart_date}' from '${restart_dir}'" - for stoch_file in $(stoch_restarts); do - restart_file="${restart_date:0:8}.${restart_date:8:2}0000.${stoch_file}" - cpreq "${restart_dir}/${restart_file}" "${DATA}/INPUT/${stoch_file}" - done - fi - else - # Replace sfc_data with sfcanl_data restart files from current cycle (if found) - local nn - for ((nn = 1; nn <= ntiles; nn++)); do - if [[ -f "${COMIN_ATMOS_RESTART}/${restart_date:0:8}.${restart_date:8:2}0000.sfcanl_data.tile${nn}.nc" ]]; then - rm -f "${DATA}/INPUT/sfc_data.tile${nn}.nc" - cpreq "${COMIN_ATMOS_RESTART}/${restart_date:0:8}.${restart_date:8:2}0000.sfcanl_data.tile${nn}.nc" \ - "${DATA}/INPUT/sfc_data.tile${nn}.nc" - # GCAFS does not run the sfcanl, only GCDAS - elif [[ ${DO_AERO_FCST} == "YES" && -f "${COMIN_TRACER_RESTART}/${restart_date:0:8}.${restart_date:8:2}0000.sfcanl_data.tile${nn}.nc" ]]; then - rm -f "${DATA}/INPUT/sfc_data.tile${nn}.nc" - cpreq "${COMIN_TRACER_RESTART}/${restart_date:0:8}.${restart_date:8:2}0000.sfcanl_data.tile${nn}.nc" \ - "${DATA}/INPUT/sfc_data.tile${nn}.nc" - else - echo "'sfcanl_data.tile1.nc' not found in '${COMIN_ATMOS_RESTART}', using 'sfc_data.tile1.nc'" - break - fi - done - - # If aerosol analysis is to be done, replace fv_tracer with aeroanl_fv_tracer - # restart files from current cycle (if found) - if [[ "${DO_AERO_FCST}" == "YES" ]]; then - local nn - local use_anl_aero="YES" - for ((nn = 1; nn <= ntiles; nn++)); do - test_tracer_file="${COMIN_TRACER_RESTART}/${restart_date:0:8}.${restart_date:8:2}0000.aeroanl_fv_tracer.res.tile${nn}.nc" - if [[ ! -f "${test_tracer_file}" ]]; then - use_anl_aero="NO" - echo "WARNING: File ${test_tracer_file} does not exist, will not replace any files from the aerosol analysis" - break - fi - done - if [[ "${use_anl_aero}" == "YES" ]]; then - for ((nn = 1; nn <= ntiles; nn++)); do - rm -f "${DATA}/INPUT/fv_tracer.res.tile${nn}.nc" - cpreq "${COMIN_TRACER_RESTART}/${restart_date:0:8}.${restart_date:8:2}0000.aeroanl_fv_tracer.res.tile${nn}.nc" \ - "${DATA}/INPUT/fv_tracer.res.tile${nn}.nc" - done - fi # if [[ ${use_anl_aero} == "YES" ]]; then - - fi # [[ ${DO_AERO_FCST} == "YES" ]]; then - - fi # if [[ "${RERUN}" == "YES" ]]; then - - fi # if [[ "${warm_start}" == ".true." ]]; then - - # Regardless of warm_start or not, the sfc_data and orography files should be consistent - # Check for consistency - # TODO: the checker has a --fatal option, which is not used here. This needs to be decided how to handle. - if [[ "${CHECK_LAND_RESTART_OROG:-NO}" == "YES" ]]; then - "${USHgfs}/check_land_input_orography.py" \ - --input_dir "${DATA}/INPUT" --orog_dir "${DATA}/INPUT" - err=$? - if [[ ${err} -ne 0 ]]; then - echo "FATAL ERROR: check_land_input_orography.py returned error code ${err}, ABORT!" - exit "${err}" - fi - fi - - #============================================================================ - # Determine increment files when doing cold start - if [[ "${warm_start}" == ".false." ]]; then - - if [[ "${USE_ATM_ENS_PERTURB_FILES:-NO}" == "YES" ]]; then - if ((MEMBER == 0)); then - inc_files=() - else - inc_files=("increment.atm.i006.nc") - read_increment=".true." - res_latlon_dynamics="increment.atm.i006.nc" - fi - increment_file_on_native_grid=".false." - local increment_file - for inc_file in "${inc_files[@]}"; do - increment_file="${COMIN_ATMOS_ANALYSIS}/${RUN}.t${cyc}z.${inc_file}" - cpreq "${increment_file}" "${DATA}/INPUT/${inc_file}" - done - fi - - # Determine IAU and increment files when doing warm start - elif [[ "${warm_start}" == ".true." ]]; then - - #-------------------------------------------------------------------------- - if [[ "${RERUN}" == "YES" ]]; then - - local restart_fhr - restart_fhr=$(nhour "${RERUN_DATE}" "${current_cycle}") - IAU_FHROT=$((IAU_OFFSET + restart_fhr)) - if [[ "${DOIAU}" == "YES" ]]; then - IAUFHRS=-1 - IAU_DELTHRS=0 - IAU_INC_FILES="''" - fi - DO_LAND_IAU=".false." - #-------------------------------------------------------------------------- - else # "${RERUN}" == "NO" - - # Need a coupler.res that is consistent with the model start time - if [[ "${DOIAU:-NO}" == "YES" ]]; then - local model_start_time="${previous_cycle}" - else - local model_start_time="${current_cycle}" - fi - local model_current_time="${model_start_date_current_cycle}" - rm -f "${DATA}/INPUT/coupler.res" - cat >> "${DATA}/INPUT/coupler.res" << EOF - 3 (Calendar: no_calendar=0, thirty_day_months=1, julian=2, gregorian=3, noleap=4) - ${model_start_time:0:4} ${model_start_time:4:2} ${model_start_time:6:2} ${model_start_time:8:2} 0 0 Model start time: year, month, day, hour, minute, second - ${model_current_time:0:4} ${model_current_time:4:2} ${model_current_time:6:2} ${model_current_time:8:2} 0 0 Current model time: year, month, day, hour, minute, second -EOF - - # Create a array of increment files - local inc_files inc_file iaufhrs iaufhr - if [[ "${DOIAU}" == "YES" ]]; then - # create an array of inc_files for each IAU hour - IFS=',' read -ra iaufhrs <<< "${IAUFHRS}" - inc_files=() - delimiter="" - IAU_INC_FILES="" - for iaufhr in "${iaufhrs[@]}"; do - if [[ "${DO_JEDIATMVAR:-NO}" == "YES" ]]; then - for tile in {1..6}; do - inc_file="jedi_increment.atm.i$(printf %03i "${iaufhr}").tile${tile}.nc" - inc_files+=("${inc_file}") - IAU_INC_FILES="${IAU_INC_FILES}${delimiter}'${inc_file}'" - done - else - inc_file="increment.atm.i$(printf %03i "${iaufhr}").nc" - inc_files+=("${inc_file}") - IAU_INC_FILES="${IAU_INC_FILES}${delimiter}'${inc_file}'" - fi - - delimiter="," - done - else # "${DOIAU}" == "NO" - read_increment=".true." - - if [[ "${DO_JEDIATMVAR:-NO}" == "YES" ]]; then - inc_files=("jedi_increment.atm.i006.tile1.nc" "jedi_increment.atm.i006.tile2.nc" "jedi_increment.atm.i006.tile3.nc" "jedi_increment.atm.i006.tile4.nc" "jedi_increment.atm.i006.tile5.nc" "jedi_increment.atm.i006.tile6.nc") - increment_file_on_native_grid=".true." - res_latlon_dynamics="jedi_increment.atm.i006" - if [[ "${DO_JEDIATMENS:-NO}" == "NO" ]]; then - inc_files=("increment.atm.i006.nc") - res_latlon_dynamics="increment.atm.i006.nc" - increment_file_on_native_grid=".false." - fi - else - inc_files=("increment.atm.i006.nc") - res_latlon_dynamics="increment.atm.i006.nc" - increment_file_on_native_grid=".false." - fi - if [[ "${USE_ATM_ENS_PERTURB_FILES:-NO}" == "YES" ]]; then - # Control member has no perturbation - if ((MEMBER == 0)); then - inc_files=() - read_increment=".false." - res_latlon_dynamics='""' - fi - fi - fi - - if [[ "${RUN}" == "enkfgfs" ]] || [[ "${RUN}" == "enkfgdas" ]]; then - prefix_atminc="recentered_" - else - prefix_atminc="" - fi - - local increment_file - for inc_file in "${inc_files[@]}"; do - if [[ "${DO_JEDIATMVAR:-NO}" == "YES" ]]; then - increment_file="${COMIN_ATMOS_ANALYSIS}/${RUN}.t${cyc}z.${prefix_atminc}${inc_file}" - if [[ "${DO_JEDIATMENS:-NO}" == "NO" ]]; then - increment_file="${COMIN_ATMOS_ANALYSIS}/${RUN}.t${cyc}z.${prefix_atminc}${inc_file}" - fi - else - if [[ "${RUN}" == "gcafs" ]]; then - increment_file="${COMIN_ATMOS_ANALYSIS}/gcdas.t${cyc}z.${prefix_atminc}${inc_file}" - else - increment_file="${COMIN_ATMOS_ANALYSIS}/${RUN}.t${cyc}z.${prefix_atminc}${inc_file}" - fi - fi - cpreq "${increment_file}" "${DATA}/INPUT/${inc_file}" - done - - # Land IAU increments: sfc_inc in FV3 grid, all timesteps in one file per tile - if [[ ${DO_LAND_IAU} == ".true." ]]; then - local TN sfc_increment_file - for TN in $(seq 1 "${ntiles}"); do - sfc_increment_file="${COMIN_ATMOS_ANALYSIS}/increment.sfc.tile${TN}.nc" - if [[ ! -f "${sfc_increment_file}" ]]; then - export err=1 - err_exit "FATAL ERROR: DO_LAND_IAU=${DO_LAND_IAU}, but missing increment file ${sfc_increment_file}, ABORT!" - else - cpreq "${sfc_increment_file}" "${DATA}/INPUT/sfc_inc.tile${TN}.nc" - fi - done - fi - fi # if [[ "${RERUN}" == "YES" ]]; then - #-------------------------------------------------------------------------- - fi # if [[ "${warm_start}" == ".true." ]]; then - #============================================================================ - -<<<<<<< HEAD - if [[ "${DO_JEDIATMVAR:-NO}" == "YES" ]]; then - inc_files=("csg_jedi_increment.atm.i006.tile1.nc" "csg_jedi_increment.atm.i006.tile2.nc" "csg_jedi_increment.atm.i006.tile3.nc" "csg_jedi_increment.atm.i006.tile4.nc" "csg_jedi_increment.atm.i006.tile5.nc" "csg_jedi_increment.atm.i006.tile6.nc") - increment_file_on_native_grid=".true." - if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]]; then - res_latlon_dynamics="csg_jedi_increment.atm.i006" - else - res_latlon_dynamics="jedi_increment.atm.i006" - fi - if [[ "${DO_JEDIATMENS:-NO}" == "NO" ]]; then - inc_files=("increment.atm.i006.nc") - res_latlon_dynamics="increment.atm.i006.nc" - increment_file_on_native_grid=".false." - fi - else - inc_files=("increment.atm.i006.nc") - res_latlon_dynamics="increment.atm.i006.nc" - increment_file_on_native_grid=".false." - fi - if [[ "${USE_ATM_ENS_PERTURB_FILES:-NO}" == "YES" ]]; then - # Control member has no perturbation - if (( MEMBER == 0 )); then - inc_files=() - read_increment=".false." - res_latlon_dynamics='""' - fi - fi - fi - - if [[ "${RUN}" = "enkfgfs" ]] || [[ "${RUN}" = "enkfgdas" ]]; then - if [[ "${DOENKFONLY_ATM}" = "YES" ]]; then - prefix_atminc="" - else - prefix_atminc="recentered_" - fi - else - prefix_atminc="" - fi - - local increment_file - for inc_file in "${inc_files[@]}"; do - if [[ "${DO_JEDIATMVAR:-NO}" == "YES" ]]; then - increment_file="${COMIN_ATMOS_ANALYSIS}/${RUN}.t${cyc}z.${prefix_atminc}${inc_file}" - if [[ "${DO_JEDIATMENS:-NO}" == "NO" ]]; then - increment_file="${COMIN_ATMOS_ANALYSIS}/${RUN}.t${cyc}z.${prefix_atminc}${inc_file}" - fi - else - if [[ "${RUN}" == "gcafs" ]]; then - increment_file="${COMIN_ATMOS_ANALYSIS}/gcdas.t${cyc}z.${prefix_atminc}${inc_file}" - else - increment_file="${COMIN_ATMOS_ANALYSIS}/${RUN}.t${cyc}z.${prefix_atminc}${inc_file}" - fi - fi - cpreq "${increment_file}" "${DATA}/INPUT/${inc_file}" - done - - # Land IAU increments: sfc_inc in FV3 grid, all timesteps in one file per tile - if [[ ${DO_LAND_IAU} = ".true." ]]; then - local TN sfc_increment_file - for TN in $(seq 1 "${ntiles}"); do - sfc_increment_file="${COMIN_ATMOS_ANALYSIS}/increment.sfc.tile${TN}.nc" - if [[ ! -f "${sfc_increment_file}" ]]; then - echo "FATAL ERROR: DO_LAND_IAU=${DO_LAND_IAU}, but missing increment file ${sfc_increment_file}, ABORT!" - exit 1 - else - cpreq "${sfc_increment_file}" "${DATA}/INPUT/sfc_inc.tile${TN}.nc" - fi - done - - fi - - fi # if [[ "${RERUN}" == "YES" ]]; then - #-------------------------------------------------------------------------- - - fi # if [[ "${warm_start}" == ".true." ]]; then - #============================================================================ - - #============================================================================ - # If doing IAU, change forecast hours - if [[ "${DOIAU:-NO}" == "YES" ]]; then - FHMAX=$((FHMAX + 6)) - if (( FHMAX_HF > 0 )); then - FHMAX_HF=$((FHMAX_HF + 6)) - fi - fi - #============================================================================ - - #============================================================================ - # If warm starting from restart files, set the following flags - if [[ "${warm_start}" == ".true." ]]; then - - # start from restart file - nggps_ic=".false." - ncep_ic=".false." - external_ic=".false." - mountain=".true." - - # restarts contain non-hydrostatic state - if [[ "${TYPE}" == "nh" ]]; then - make_nh=".false." - fi - - # do not pre-condition the solution - na_init=0 - - fi # warm_start == .true. - #============================================================================ - - #============================================================================ - if [[ "${QUILTING}" = ".true." ]] && [[ "${OUTPUT_GRID}" = "gaussian_grid" ]]; then - local FH2 FH3 - for fhr in ${FV3_OUTPUT_FH}; do - FH3=$(printf %03i "${fhr}") - FH2=$(printf %02i "${fhr}") - ${NLN} "${COMOUT_ATMOS_HISTORY}/${RUN}.t${cyc}z.atm.f${FH3}.nc" "${DATAoutput}/FV3ATM_OUTPUT/atmf${FH3}.nc" - ${NLN} "${COMOUT_ATMOS_HISTORY}/${RUN}.t${cyc}z.sfc.f${FH3}.nc" "${DATAoutput}/FV3ATM_OUTPUT/sfcf${FH3}.nc" - ${NLN} "${COMOUT_ATMOS_HISTORY}/${RUN}.t${cyc}z.log.f${FH3}.txt" "${DATAoutput}/FV3ATM_OUTPUT/log.atm.f${FH3}" - if [[ "${DO_JEDIATMVAR:-}" == "YES" || "${DO_HISTORY_FILE_ON_NATIVE_GRID:-"NO"}" == "YES" ]]; then - ${NLN} "${COMOUT_ATMOS_HISTORY}/${RUN}.t${cyc}z.csg_atm.f${FH3}.nc" "${DATAoutput}/FV3ATM_OUTPUT/cubed_sphere_grid_atmf${FH3}.nc" - ${NLN} "${COMOUT_ATMOS_HISTORY}/${RUN}.t${cyc}z.csg_sfc.f${FH3}.nc" "${DATAoutput}/FV3ATM_OUTPUT/cubed_sphere_grid_sfcf${FH3}.nc" - fi - if [[ "${WRITE_DOPOST}" == ".true." ]]; then - ${NLN} "${COMOUT_ATMOS_MASTER}/${RUN}.t${cyc}z.master.f${FH3}.grib2" "${DATAoutput}/FV3ATM_OUTPUT/GFSPRS.GrbF${FH2}" - ${NLN} "${COMOUT_ATMOS_MASTER}/${RUN}.t${cyc}z.sflux.f${FH3}.grib2" "${DATAoutput}/FV3ATM_OUTPUT/GFSFLX.GrbF${FH2}" - if [[ "${DO_NEST:-NO}" == "YES" ]]; then - ${NLN} "${COMOUT_ATMOS_MASTER}/${RUN}.t${cyc}z.master.nest.f${FH3}.grib2" "${DATAoutput}/FV3ATM_OUTPUT/GFSPRS.GrbF${FH2}.nest02" - ${NLN} "${COMOUT_ATMOS_MASTER}/${RUN}.t${cyc}z.sflux.nest.f${FH3}.grib2" "${DATAoutput}/FV3ATM_OUTPUT/GFSFLX.GrbF${FH2}.nest02" - fi - fi - done - fi - #============================================================================ - restart_interval=${restart_interval:-${FHMAX}} - # restart_interval = 0 implies write restart at the END of the forecast i.e. at FHMAX - # Convert restart interval into an explicit list for CMEPS/CICE/MOM6/WW3 - # Note, this must be computed after determination IAU in forecast_det and fhrot. - if (( restart_interval == 0 )); then -======= - #============================================================================ - # If doing IAU, change forecast hours ->>>>>>> develop - if [[ "${DOIAU:-NO}" == "YES" ]]; then - FHMAX=$((FHMAX + 6)) - if [[ ${FHMAX_HF} -gt 0 ]]; then - FHMAX_HF=$((FHMAX_HF + 6)) - fi - fi - #============================================================================ - - #============================================================================ - # If warm starting from restart files, set the following flags - if [[ "${warm_start}" == ".true." ]]; then - - # start from restart file - nggps_ic=".false." - ncep_ic=".false." - external_ic=".false." - mountain=".true." - - # restarts contain non-hydrostatic state - if [[ "${TYPE}" == "nh" ]]; then - make_nh=".false." - fi - - # do not pre-condition the solution - na_init=0 - - fi # warm_start == .true. - #============================================================================ - - #============================================================================ - if [[ "${QUILTING}" == ".true." ]] && [[ "${OUTPUT_GRID}" == "gaussian_grid" ]]; then - local FH2 FH3 - for fhr in ${FV3_OUTPUT_FH}; do - FH3=$(printf %03i "${fhr}") - FH2=$(printf %02i "${fhr}") - ${NLN} "${COMOUT_ATMOS_HISTORY}/${RUN}.t${cyc}z.atm.f${FH3}.nc" "${DATAoutput}/FV3ATM_OUTPUT/atmf${FH3}.nc" - ${NLN} "${COMOUT_ATMOS_HISTORY}/${RUN}.t${cyc}z.sfc.f${FH3}.nc" "${DATAoutput}/FV3ATM_OUTPUT/sfcf${FH3}.nc" - ${NLN} "${COMOUT_ATMOS_HISTORY}/${RUN}.t${cyc}z.log.f${FH3}.txt" "${DATAoutput}/FV3ATM_OUTPUT/log.atm.f${FH3}" - if [[ "${DO_JEDIATMVAR:-}" == "YES" || "${DO_HISTORY_FILE_ON_NATIVE_GRID:-"NO"}" == "YES" ]]; then - ${NLN} "${COMOUT_ATMOS_HISTORY}/${RUN}.t${cyc}z.csg_atm.f${FH3}.nc" "${DATAoutput}/FV3ATM_OUTPUT/cubed_sphere_grid_atmf${FH3}.nc" - ${NLN} "${COMOUT_ATMOS_HISTORY}/${RUN}.t${cyc}z.csg_sfc.f${FH3}.nc" "${DATAoutput}/FV3ATM_OUTPUT/cubed_sphere_grid_sfcf${FH3}.nc" - fi - if [[ "${WRITE_DOPOST}" == ".true." ]]; then - ${NLN} "${COMOUT_ATMOS_MASTER}/${RUN}.t${cyc}z.master.f${FH3}.grib2" "${DATAoutput}/FV3ATM_OUTPUT/GFSPRS.GrbF${FH2}" - ${NLN} "${COMOUT_ATMOS_MASTER}/${RUN}.t${cyc}z.sflux.f${FH3}.grib2" "${DATAoutput}/FV3ATM_OUTPUT/GFSFLX.GrbF${FH2}" - if [[ "${DO_NEST:-NO}" == "YES" ]]; then - ${NLN} "${COMOUT_ATMOS_MASTER}/${RUN}.t${cyc}z.master.nest.f${FH3}.grib2" "${DATAoutput}/FV3ATM_OUTPUT/GFSPRS.GrbF${FH2}.nest02" - ${NLN} "${COMOUT_ATMOS_MASTER}/${RUN}.t${cyc}z.sflux.nest.f${FH3}.grib2" "${DATAoutput}/FV3ATM_OUTPUT/GFSFLX.GrbF${FH2}.nest02" - fi - fi - done - fi - #============================================================================ - restart_interval=${restart_interval:-${FHMAX}} - # restart_interval = 0 implies write restart at the END of the forecast i.e. at FHMAX - # Convert restart interval into an explicit list for CMEPS/CICE/MOM6/WW3 - # Note, this must be computed after determination IAU in forecast_det and fhrot. - if [[ ${restart_interval} -eq 0 ]]; then - if [[ "${DOIAU:-NO}" == "YES" ]]; then - FV3_RESTART_FH=$((FHMAX + assim_freq)) - else - FV3_RESTART_FH=("${FHMAX}") - fi - else - if [[ "${DOIAU:-NO}" == "YES" ]]; then - if [[ "${MODE}" = "cycled" && "${SDATE}" = "${PDY}${cyc}" && ${EXP_WARM_START} = ".false." ]]; then - local restart_interval_start=${restart_interval} - local restart_interval_end=${FHMAX} - else - local restart_interval_start=$((restart_interval + assim_freq)) - local restart_interval_end=$((FHMAX + assim_freq)) - fi - else - local restart_interval_start=${restart_interval} - local restart_interval_end=${FHMAX} - fi - FV3_RESTART_FH="$(seq -s ' ' "${restart_interval_start}" "${restart_interval}" "${restart_interval_end}")" - fi - export FV3_RESTART_FH - #============================================================================ -} - -FV3_nml() { - # namelist output for a certain component - echo "SUB ${FUNCNAME[0]}: Creating name lists and model configure file for FV3" - - source "${USHgfs}/parsing_namelists_FV3.sh" - source "${USHgfs}/parsing_model_configure_FV3.sh" - - # Call the appropriate namelist functions - if [[ "${DO_NEST:-NO}" == "YES" ]]; then - source "${USHgfs}/parsing_namelists_FV3_nest.sh" - FV3_namelists_nest global - FV3_namelists_nest nest - else - FV3_namelists - fi - FV3_model_configure - - echo "SUB ${FUNCNAME[0]}: FV3 name lists and model configure file created" -} - -FV3_out() { - echo "SUB ${FUNCNAME[0]}: copying output data for FV3" - - # Copy configuration files - cpfs "${DATA}/input.nml" "${COMOUT_CONF}/ufs.input.nml" - cpfs "${DATA}/model_configure" "${COMOUT_CONF}/ufs.model_configure" - cpfs "${DATA}/ufs.configure" "${COMOUT_CONF}/ufs.ufs.configure" - cpfs "${DATA}/diag_table" "${COMOUT_CONF}/ufs.diag_table" - - # Determine the dates for restart files to be copied to COM - local restart_date restart_dates - restart_dates=() - - case ${RUN} in - gdas | enkfgdas | enkfgfs | enkfgcafs | gcdas) # Copy restarts in the assimilation window for RUN=gdas|enkfgdas|enkfgfs - restart_date="${model_start_date_next_cycle}" - while ((restart_date <= forecast_end_cycle)); do - restart_dates+=("${restart_date:0:8}.${restart_date:8:2}0000") - restart_date=$(date --utc -d "${restart_date:0:8} ${restart_date:8:2} + ${restart_interval} hours" +%Y%m%d%H) - done - ;; - gfs | gefs | sfs | gcafs) # Copy restarts at the end of the forecast segment for RUN=gfs|gefs|sfs|gcafs - if [[ "${COPY_FINAL_RESTARTS}" == "YES" ]]; then - restart_dates+=("${forecast_end_cycle:0:8}.${forecast_end_cycle:8:2}0000") - fi - ;; - *) - echo "FATAL ERROR: Not sure how to copy restart files for RUN ${RUN}" - exit 25 - ;; - esac - - ### Check that there are restart files to copy - if [[ ${#restart_dates[@]} -gt 0 ]]; then - # Get list of FV3 restart files - local file_list fv3_file - file_list=$(FV3_restarts) - - # Copy restarts for the dates collected above to COM - for restart_date in "${restart_dates[@]}"; do - echo "Copying FV3 restarts for 'RUN=${RUN}' at ${restart_date}" - for fv3_file in ${file_list}; do - cpfs "${DATArestart}/FV3_RESTART/${restart_date}.${fv3_file}" \ - "${COMOUT_ATMOS_RESTART}/${restart_date}.${fv3_file}" - done - done - - echo "SUB ${FUNCNAME[0]}: Output data for FV3 copied" - fi -} - -# Disable variable not used warnings -# shellcheck disable=SC2034 -WW3_postdet() { - echo "SUB ${FUNCNAME[0]}: Linking input data for WW3" - # Copy initial condition files: - local restart_date restart_dir - if [[ "${RERUN}" == "YES" ]]; then - restart_date="${RERUN_DATE}" - restart_dir="${DATArestart}/WW3_RESTART" - else - restart_date="${model_start_date_current_cycle}" - restart_dir="${COMIN_WAVE_RESTART_PREV}" - fi - - echo "Copying WW3 restarts for 'RUN=${RUN}' at '${restart_date}' from '${restart_dir}'" - - local ww3_restart_file ww3_restart_dest_file seconds - seconds=$(to_seconds "${restart_date:8:2}0000") # convert HHMMSS to seconds - ww3_restart_file="${restart_dir}/${restart_date:0:8}.${restart_date:8:2}0000.restart.ww3" - ww3_restart_dest_file="ufs.cpld.ww3.r.${restart_date:0:4}-${restart_date:4:2}-${restart_date:6:2}-${seconds}" - if [[ -s "${ww3_restart_file}.nc" ]]; then # First check to see if netcdf restart exists: - export WW3_restart_from_binary=false - cpreq "${ww3_restart_file}.nc" "${DATA}/${ww3_restart_dest_file}.nc" - elif [[ -s "${ww3_restart_file}" ]]; then # If not, check to see if binary restart exists: - export WW3_restart_from_binary=true - cpreq "${ww3_restart_file}" "${DATA}/${ww3_restart_dest_file}" - else - if [[ "${RERUN}" == "YES" ]] || [[ -f "${DATA}/ufs.cpld.cpl.r.nc" ]]; then # The || part requires CMEPS_postdet to be called before WW3_postdet - # In the case of a RERUN, the WW3 restart file is required - # In the case of runtype=continue, if no wave restart when using PIO, the model will fail - echo "FATAL ERROR: WW3 binary | netcdf restart file '${ww3_restart_file}' | '${ww3_restart_file}.nc' not found for RERUN='${RERUN}' or runtype=continue, ABORT!" - exit 1 - else - export WW3_restart_from_binary=false - echo "WARNING: WW3 binary | netcdf restart file '${ww3_restart_file}' | '${ww3_restart_file}.nc' not found for warm_start='${warm_start}', will start from rest!" - fi - fi - - local first_ww3_restart_out - first_ww3_restart_out=$(date --utc -d "${restart_date:0:8} ${restart_date:8:2} + ${restart_interval} hours" +%Y%m%d%H) - if [[ "${DOIAU:-NO}" == "YES" ]]; then - first_ww3_restart_out=$(date --utc -d "${first_ww3_restart_out:0:8} ${first_ww3_restart_out:8:2} + ${half_window} hours" +%Y%m%d%H) - fi - - # Link restart files to their expected names in DATArestart/WW3_RESTART - # TODO: Have the UFSWM write out the WW3 restart files in the expected format of 'YYYYMMDD.HHmmSS.restart.ww3.nc' - local cwd vdate ww3_ufs_restart_file ww3_netcdf_restart_file - cwd="${PWD}" - cd "${DATArestart}/WW3_RESTART" || exit 1 - for ((vdate = first_ww3_restart_out; vdate <= forecast_end_cycle; \ - vdate = $(date --utc -d "${vdate:0:8} ${vdate:8:2} + ${restart_interval} hours" +%Y%m%d%H))); do - seconds=$(to_seconds "${vdate:8:2}0000") # convert HHMMSS to seconds - ww3_ufs_restart_file="ufs.cpld.ww3.r.${vdate:0:4}-${vdate:4:2}-${vdate:6:2}-${seconds}.nc" # UFS restart file name - ww3_netcdf_restart_file="${vdate:0:8}.${vdate:8:2}0000.restart.ww3.nc" # WW3 restart file name in COM - ${NLN} "${ww3_netcdf_restart_file}" "${ww3_ufs_restart_file}" - done - - # TODO: link GEFS restart for next cycle IC - #if [[ "${RUN}" == "gefs" ]]; then - # vdate=${model_start_date_next_cycle} - # seconds=$(to_seconds "${vdate:8:2}0000") # convert HHMMSS to seconds - # ww3_ufs_restart_file="ufs.cpld.ww3.r.${vdate:0:4}-${vdate:4:2}-${vdate:6:2}-${seconds}.nc" - # ww3_netcdf_restart_file="${vdate:0:8}.${vdate:8:2}0000.restart.ww3.nc" - # ${NLN} "${ww3_netcdf_restart_file}" "${ww3_ufs_restart_file}" - #fi - cd "${cwd}" || exit 1 - - # Link output files - ${NLN} "${COMOUT_WAVE_HISTORY}/${RUN}.t${cyc}z.${waveGRD}.${PDY}${cyc}.log" "log.ww3" - - # Loop for gridded output (uses FHINC) - local fhr fhr3 FHINC - # shellcheck disable=SC2153 - fhr="${FHMIN_WAV}" - if [[ ${FHMAX_HF_WAV} -gt 0 && ${FHOUT_HF_WAV} -gt 0 && ${fhr} -lt ${FHMAX_HF_WAV} ]]; then - fhinc=${FHOUT_HF_WAV} - else - fhinc=${FHOUT_WAV} - fi - while [[ ${fhr} -le ${FHMAX_WAV} ]]; do - fhr3=$(printf '%03d' "${fhr}") - vdate=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${fhr} hours" +%Y%m%d.%H0000) - ${NLN} "${COMOUT_WAVE_HISTORY}/${RUN}.t${cyc}z.${waveGRD}.f${fhr3}.bin" "${DATAoutput}/WW3_OUTPUT/${vdate}.out_grd.ww3" - ${NLN} "${COMOUT_WAVE_HISTORY}/${RUN}.t${cyc}z.${waveGRD}.f${fhr3}.log" "${DATAoutput}/WW3_OUTPUT/log.${vdate}.out_grd.ww3.txt" - - if [[ ${fhr} -ge ${FHMAX_HF_WAV} ]]; then - fhinc=${FHOUT_WAV} - fi - fhr=$((fhr + fhinc)) - done - - # Loop for point output (uses DTPNT) - fhr=${FHMIN_WAV} - fhinc=${FHINCP_WAV} - while [[ ${fhr} -le ${FHMAX_WAV} ]]; do - fhr3=$(printf '%03d' "${fhr}") - vdate=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${fhr} hours" +%Y%m%d.%H0000) - ${NLN} "${COMOUT_WAVE_HISTORY}/${RUN}.t${cyc}z.points.f${fhr3}.nc" "${DATAoutput}/WW3_OUTPUT/${vdate}.out_pnt.ww3.nc" - ${NLN} "${COMOUT_WAVE_HISTORY}/${RUN}.t${cyc}z.points.f${fhr3}.log" "${DATAoutput}/WW3_OUTPUT/log.${vdate}.out_pnt.ww3.txt" - - fhr=$((fhr + fhinc)) - done -} - -WW3_nml() { - echo "SUB ${FUNCNAME[0]}: Copying input files for WW3" - source "${USHgfs}/parsing_namelists_WW3.sh" - WW3_namelists -} - -WW3_out() { - echo "SUB ${FUNCNAME[0]}: Copying output data for WW3" - - # Copy wave namelist from DATA to COMOUT_CONF after the forecast is run (and successfull) - cpfs "${DATA}/ww3_shel.nml" "${COMOUT_CONF}/ufs.ww3_shel.nml" - - # Copy WW3 restarts at the end of the forecast segment to COM for RUN=gfs|gefs - if [[ "${COPY_FINAL_RESTARTS}" == "YES" ]]; then - local restart_file - if [[ "${RUN}" == "gfs" || "${RUN}" == "gefs" || "${RUN}" == "gcafs" ]]; then - echo "Copying WW3 restarts for 'RUN=${RUN}' at ${forecast_end_cycle}" - restart_file="${forecast_end_cycle:0:8}.${forecast_end_cycle:8:2}0000.restart.ww3.nc" - cpfs "${DATArestart}/WW3_RESTART/${restart_file}" \ - "${COMOUT_WAVE_RESTART}/${restart_file}" - fi - fi - - # Copy restarts for next cycle for RUN=gdas|gefs - # TODO: GEFS needs to be added here - if [[ "${RUN}" == "gdas" ]]; then - local restart_date restart_file - restart_date="${model_start_date_next_cycle}" - echo "Copying WW3 restarts for 'RUN=${RUN}' at ${restart_date}" - restart_file="${restart_date:0:8}.${restart_date:8:2}0000.restart.ww3.nc" - cpfs "${DATArestart}/WW3_RESTART/${restart_file}" \ - "${COMOUT_WAVE_RESTART}/${restart_file}" - fi - - # Copy restarts for downstream usage in HAFS - if [[ "${RUN}" == "gdas" ]]; then - local restart_date restart_file - restart_date="${next_cycle}" - echo "Copying WW3 restarts for 'RUN=${RUN}' at ${restart_date}" - restart_file="${restart_date:0:8}.${restart_date:8:2}0000.restart.ww3.nc" - cpfs "${DATArestart}/WW3_RESTART/${restart_file}" \ - "${COMOUT_WAVE_RESTART}/${restart_file}" - fi - -} - -CPL_out() { - echo "SUB ${FUNCNAME[0]}: Copying output data for general cpl fields" - if [[ "${esmf_profile:-.false.}" == ".true." ]]; then - cpfs "${DATA}/ESMF_Profile.summary" "${COMOUT_ATMOS_HISTORY}/ESMF_Profile.summary" - fi -} - -MOM6_postdet() { - echo "SUB ${FUNCNAME[0]}: MOM6 after run type determination" - - local restart_dir restart_date - if [[ "${RERUN}" == "YES" ]]; then - restart_dir="${DATArestart}/MOM6_RESTART" - restart_date="${RERUN_DATE}" - else # "${RERUN}" == "NO" - restart_dir="${COMIN_OCEAN_RESTART_PREV}" - restart_date="${model_start_date_current_cycle}" - fi - - # Copy MOM6 ICs - cpreq "${restart_dir}/${restart_date:0:8}.${restart_date:8:2}0000.MOM.res.nc" "${DATA}/INPUT/MOM.res.nc" - case ${OCNRES} in - "025") - local nn - for ((nn = 1; nn <= 4; nn++)); do - if [[ -f "${restart_dir}/${restart_date:0:8}.${restart_date:8:2}0000.MOM.res_${nn}.nc" ]]; then - cpreq "${restart_dir}/${restart_date:0:8}.${restart_date:8:2}0000.MOM.res_${nn}.nc" "${DATA}/INPUT/MOM.res_${nn}.nc" - fi - done - ;; - *) ;; - esac - - # Copy increment (only when RERUN=NO) - if [[ "${RERUN}" == "NO" ]]; then - if [[ "${DO_JEDIOCNVAR:-NO}" == "YES" ]] || [[ ${MEMBER} -gt 0 && "${ODA_INCUPD:-False}" == "True" ]]; then - cpreq "${COMIN_OCEAN_ANALYSIS}/${RUN}.t${cyc}z.mom6_increment.i006.nc" "${DATA}/INPUT/mom6_increment.nc" - fi - fi # if [[ "${RERUN}" == "NO" ]]; then - - # Link output files - case ${RUN} in - gfs | enkfgfs | gefs | sfs | gcafs) # Link output files for RUN=gfs|enkfgfs|gefs|sfs - # Looping over MOM6 output hours - local fhr fhr3 last_fhr interval midpoint vdate vdate_mid source_file dest_file - for fhr in ${MOM6_OUTPUT_FH}; do - fhr3=$(printf %03i "${fhr}") - - if [[ -z ${last_fhr:-} ]]; then - last_fhr=${fhr} - continue - fi - - ((interval = fhr - last_fhr)) - ((midpoint = last_fhr + interval / 2)) - - vdate=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${fhr} hours" +%Y%m%d%H) - #If OFFSET_START_HOUR is greater than 0, OFFSET_START_HOUR should be added to the midpoint for first lead time - if ((OFFSET_START_HOUR > 0)) && ((fhr == FHOUT_OCN)); then - vdate_mid=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + $((midpoint + OFFSET_START_HOUR)) hours" +%Y%m%d%H) - else - vdate_mid=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${midpoint} hours" +%Y%m%d%H) - fi - - # Native model output uses window midpoint in the filename, but we are mapping that to the end of the period for COM - if ((OFFSET_START_HOUR > 0)) && ((fhr == FHOUT_OCN)); then - source_file="ocn_lead1_${vdate_mid:0:4}_${vdate_mid:4:2}_${vdate_mid:6:2}_${vdate_mid:8:2}.nc" - else - source_file="ocn_${vdate_mid:0:4}_${vdate_mid:4:2}_${vdate_mid:6:2}_${vdate_mid:8:2}.nc" - fi - dest_file="${RUN}.t${cyc}z.${interval}hr_avg.f${fhr3}.nc" - ${NLN} "${COMOUT_OCEAN_HISTORY}/${dest_file}" "${DATAoutput}/MOM6_OUTPUT/${source_file}" - - last_fhr=${fhr} - - done - ;; - - gdas | enkfgdas) # Link output files for RUN=gdas|enkfgdas - # Save (instantaneous) MOM6 backgrounds - local fhr3 vdatestr - for fhr in ${MOM6_OUTPUT_FH}; do - fhr3=$(printf %03i "${fhr}") - vdatestr=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${fhr} hours" +%Y_%m_%d_%H) - ${NLN} "${COMOUT_OCEAN_HISTORY}/${RUN}.t${cyc}z.inst.f${fhr3}.nc" "${DATAoutput}/MOM6_OUTPUT/ocn_da_${vdatestr}.nc" - done - ;; - *) - echo "FATAL ERROR: Don't know how to copy MOM output files for RUN ${RUN}" - exit 25 - ;; - esac - - echo "SUB ${FUNCNAME[0]}: MOM6 input data linked/copied" - -} - -MOM6_nml() { - echo "SUB ${FUNCNAME[0]}: Creating name list for MOM6" - source "${USHgfs}/parsing_namelists_MOM6.sh" - MOM6_namelists -} - -MOM6_out() { - echo "SUB ${FUNCNAME[0]}: Copying output data for MOM6" - - # Copy MOM_input from DATA to COMOUT_CONF after the forecast is run (and successfull) - cpfs "${DATA}/INPUT/MOM_input" "${COMOUT_CONF}/ufs.MOM_input" - # Copy runtime configuration of MOM: MOM_parameter_doc.all that was used in the forecast - if [[ -f "${DATA}/MOM6_OUTPUT/MOM_parameter_doc.all" ]]; then - cpfs "${DATA}/MOM6_OUTPUT/MOM_parameter_doc.all" "${COMOUT_CONF}/MOM_parameter_doc.all" - fi - - # Create a list of MOM6 restart files - # Coarser than 1/2 degree has a single MOM restart - local mom6_restart_files mom6_restart_file restart_file - mom6_restart_files=(MOM.res.nc) - # 1/4 degree resolution has 3 additional restarts - case "${OCNRES}" in - "025") - local nn - for ((nn = 1; nn <= 3; nn++)); do - mom6_restart_files+=("MOM.res_${nn}.nc") - done - ;; - *) ;; - esac - - case ${RUN} in - gdas | enkfgdas | enkfgfs) # Copy restarts for the next cycle for RUN=gdas|enkfgdas|enkfgfs - local restart_date - restart_date="${model_start_date_next_cycle}" - echo "Copying MOM6 restarts for 'RUN=${RUN}' at ${restart_date}" - for mom6_restart_file in "${mom6_restart_files[@]}"; do - restart_file="${restart_date:0:8}.${restart_date:8:2}0000.${mom6_restart_file}" - cpfs "${DATArestart}/MOM6_RESTART/${restart_file}" \ - "${COMOUT_OCEAN_RESTART}/${restart_file}" - done - ;; - gfs | gefs | sfs | gcafs) # Copy MOM6 restarts at the end of the forecast segment to COM for RUN=gfs|gefs|sfs - if [[ "${COPY_FINAL_RESTARTS}" == "YES" ]]; then - local restart_file - echo "Copying MOM6 restarts for 'RUN=${RUN}' at ${forecast_end_cycle}" - for mom6_restart_file in "${mom6_restart_files[@]}"; do - restart_file="${forecast_end_cycle:0:8}.${forecast_end_cycle:8:2}0000.${mom6_restart_file}" - cpfs "${DATArestart}/MOM6_RESTART/${restart_file}" \ - "${COMOUT_OCEAN_RESTART}/${restart_file}" - done - fi - ;; - *) - echo "FATAL ERROR: Not sure how to copy restart files for RUN ${RUN}" - exit 25 - ;; - esac -} - -CICE_postdet() { - echo "SUB ${FUNCNAME[0]}: CICE after run type determination" - - local restart_date cice_restart_file - if [[ "${RERUN}" == "YES" ]]; then - restart_date="${RERUN_DATE}" - local seconds - seconds=$(to_seconds "${restart_date:8:2}0000") # convert HHMMSS to seconds - cice_restart_file="${DATArestart}/CICE_RESTART/cice_model.res.${restart_date:0:4}-${restart_date:4:2}-${restart_date:6:2}-${seconds}.nc" - else # "${RERUN}" == "NO" - restart_date="${model_start_date_current_cycle}" - cice_restart_file="${COMIN_ICE_RESTART_PREV}/${restart_date:0:8}.${restart_date:8:2}0000.cice_model.res.nc" - if [[ "${DO_JEDIOCNVAR:-NO}" == "YES" ]]; then - if [[ "${MEMBER}" -eq 0 ]]; then - # Start the deterministic from the JEDI/SOCA analysis if the Marine DA in ON - cice_restart_file="${COMIN_ICE_ANALYSIS}/${restart_date:0:8}.${restart_date:8:2}0000.analysis.cice_model.res.nc" - elif [[ "${MEMBER}" -gt 0 ]] && [[ "${DO_STARTMEM_FROM_JEDIICE:-NO}" == "YES" ]]; then - # Ignore the JEDI/SOCA ensemble analysis for the ensemble members if DO_START_FROM_JEDIICE is OFF - cice_restart_file="${COMIN_ICE_ANALYSIS}/${restart_date:0:8}.${restart_date:8:2}0000.analysis.cice_model.res.nc" - fi - fi - fi - - # Copy CICE ICs - cpreq "${cice_restart_file}" "${DATA}/cice_model.res.nc" - - # Link iceh_ic file to COM. This is the initial condition file from CICE (f000) - # TODO: Is this file needed in COM? Is this going to be used for generating any products? - local vdate seconds vdatestr fhr fhr3 interval last_fhr - seconds=$(to_seconds "${model_start_date_current_cycle:8:2}0000") # convert HHMMSS to seconds - vdatestr="${model_start_date_current_cycle:0:4}-${model_start_date_current_cycle:4:2}-${model_start_date_current_cycle:6:2}-${seconds}" - ${NLN} "${COMOUT_ICE_HISTORY}/${RUN}.t${cyc}z.ic.nc" "${DATAoutput}/CICE_OUTPUT/iceh_ic.${vdatestr}.nc" - - # Link CICE forecast output files from DATAoutput/CICE_OUTPUT to COM - local source_file dest_file - for fhr in "${CICE_OUTPUT_FH[@]}"; do - - if [[ -z ${last_fhr:-} ]]; then - last_fhr=${fhr} - continue - fi - - fhr3=$(printf %03i "${fhr}") - ((interval = fhr - last_fhr)) - - vdate=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${fhr} hours" +%Y%m%d%H) - seconds=$(to_seconds "${vdate:8:2}0000") # convert HHMMSS to seconds - vdatestr="${vdate:0:4}-${vdate:4:2}-${vdate:6:2}-${seconds}" - - case "${RUN}" in - gdas | enkfgdas) - source_file="iceh_inst.${vdatestr}.nc" - dest_file="${RUN}.t${cyc}z.inst.f${fhr3}.nc" - ;; - gfs | enkfgfs | sfs | gcafs) - source_file="iceh_$(printf "%0.2d" "${FHOUT_ICE}")h.${vdatestr}.nc" - dest_file="${RUN}.t${cyc}z.${interval}hr_avg.f${fhr3}.nc" - ;; - gefs) - source_file="iceh.${vdatestr}.nc" - dest_file="${RUN}.t${cyc}z.${interval}hr_avg.f${fhr3}.nc" - ;; - *) - echo "FATAL ERROR: Unsupported RUN ${RUN} in CICE postdet" - exit 10 - ;; - esac - - ${NLN} "${COMOUT_ICE_HISTORY}/${dest_file}" "${DATAoutput}/CICE_OUTPUT/${source_file}" - - last_fhr=${fhr} - done - -} - -CICE_nml() { - echo "SUB ${FUNCNAME[0]}: Creating name list for CICE" - source "${USHgfs}/parsing_namelists_CICE.sh" - CICE_namelists -} - -CICE_out() { - echo "SUB ${FUNCNAME[0]}: Copying output data for CICE" - - # Copy ice_in namelist from DATA to COMOUT_CONF after the forecast is run (and successfull) - cpfs "${DATA}/ice_in" "${COMOUT_CONF}/ufs.ice_in" - - case ${RUN} in - gdas | enkfgdas | enkfgfs) # Copy restarts for next cycle for RUN=gdas|enkfgdas|enkfgfs - local restart_date - restart_date="${model_start_date_next_cycle}" - echo "Copying CICE restarts for 'RUN=${RUN}' at ${restart_date}" - seconds=$(to_seconds "${restart_date:8:2}0000") # convert HHMMSS to seconds - source_file="cice_model.res.${restart_date:0:4}-${restart_date:4:2}-${restart_date:6:2}-${seconds}.nc" - target_file="${restart_date:0:8}.${restart_date:8:2}0000.cice_model.res.nc" - cpfs "${DATArestart}/CICE_RESTART/${source_file}" \ - "${COMOUT_ICE_RESTART}/${target_file}" - ;; - gfs | gefs | sfs | gcafs) # Copy CICE restarts at the end of the forecast segment to COM for RUN=gfs|gefs|sfs|gcafs - if [[ "${COPY_FINAL_RESTARTS}" == "YES" ]]; then - local seconds source_file target_file - echo "Copying CICE restarts for 'RUN=${RUN}' at ${forecast_end_cycle}" - seconds=$(to_seconds "${forecast_end_cycle:8:2}0000") # convert HHMMSS to seconds - source_file="cice_model.res.${forecast_end_cycle:0:4}-${forecast_end_cycle:4:2}-${forecast_end_cycle:6:2}-${seconds}.nc" - target_file="${forecast_end_cycle:0:8}.${forecast_end_cycle:8:2}0000.cice_model.res.nc" - cpfs "${DATArestart}/CICE_RESTART/${source_file}" \ - "${COMOUT_ICE_RESTART}/${target_file}" - fi - ;; - *) - echo "FATAL ERROR: Not sure how to copy restart files for RUN ${RUN}" - exit 25 - ;; - esac -} - -GOCART_rc() { - echo "SUB ${FUNCNAME[0]}: Linking input data and copying config files for GOCART" - # set input directory containing GOCART input data and configuration files - # this variable is platform-dependent and should be set via a YAML file - - # link directory containing GOCART input dataset, if provided - if [[ -n "${AERO_INPUTS_DIR}" ]]; then - ${NLN} "${AERO_INPUTS_DIR}" "${DATA}/ExtData" - status=$? - if [[ ${status} -ne 0 ]]; then - exit "${status}" - fi - fi - - source "${USHgfs}/parsing_namelists_GOCART.sh" - GOCART_namelists -} - -GOCART_postdet() { - echo "SUB ${FUNCNAME[0]}: Linking output data for GOCART" - - local vdate - for fhr in $(GOCART_output_fh); do - vdate=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${fhr} hours" +%Y%m%d%H) - - # Temporarily delete existing files due to noclobber in GOCART - local file_types=("inst_aod" "inst_du_ss" "inst_ca" "inst_ni" "inst_su" - "inst_du_bin" "inst_ss_bin" "inst_ca_bin" "inst_ni_bin" "inst_su_bin" - "inst_2d" "inst_3d" "tavg_du_ss" "tavg_du_bin" "tavg_2d_rad" "tavg_3d_rad") - for file_type in "${file_types[@]}"; do - if [[ -e "${COMOUT_CHEM_HISTORY}/gocart.${file_type}.${vdate:0:8}_${vdate:8:2}00z.nc4" ]]; then - rm -f "${COMOUT_CHEM_HISTORY}/gocart.${file_type}.${vdate:0:8}_${vdate:8:2}00z.nc4" - fi - done - - #TODO: Temporarily removing this as this will crash gocart, adding copy statement at the end - #${NLN} "${COMOUT_CHEM_HISTORY}/gocart.inst_aod.${vdate:0:8}_${vdate:8:2}00z.nc4" \ - # "${DATA}/gocart.inst_aod.${vdate:0:8}_${vdate:8:2}00z.nc4" - done -} - -GOCART_output_fh() { - # This has to be called during postdet after FHROT has been set - local aero_min - local gocart_output_fh - # GOCART produces no AOD files at the initial forecast time, so start the time - # after the forecast start (accounting for FHROT) - aero_min=$((${IAU_FHROT:-0} > FHMIN ? IAU_FHROT + FHOUT_AERO : FHMIN + FHOUT_AERO)) - gocart_output_fh=$(seq -s ' ' "$((aero_min))" "${FHOUT_AERO}" "${GOCART_MAX}") - - echo "${gocart_output_fh}" -} - -GOCART_out() { - echo "SUB ${FUNCNAME[0]}: Copying output data for GOCART" - - # Copy gocart.inst_aod after the forecast is run (and successfull) - # TODO: this should be linked but there are issues where gocart crashing if it is linked - local fhr - local vdate - - local file_types=("inst_aod" "inst_du_ss" "inst_ca" "inst_ni" "inst_su" - "inst_du_bin" "inst_ss_bin" "inst_ca_bin" "inst_ni_bin" "inst_su_bin" - "inst_2d" "inst_3d" "tavg_du_ss" "tavg_du_bin" "tavg_2d_rad" "tavg_3d_rad") - - for fhr in $(GOCART_output_fh); do - vdate=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${fhr} hours" +%Y%m%d%H) - for file_type in "${file_types[@]}"; do - if [[ -e "${DATA}/gocart.${file_type}.${vdate:0:8}_${vdate:8:2}00z.nc4" ]]; then - cpfs "${DATA}/gocart.${file_type}.${vdate:0:8}_${vdate:8:2}00z.nc4" \ - "${COMOUT_CHEM_HISTORY}/gocart.${file_type}.${vdate:0:8}_${vdate:8:2}00z.nc4" - fi - done - done -} - -# shellcheck disable=SC2178 -CMEPS_postdet() { - echo "SUB ${FUNCNAME[0]}: Linking output data for CMEPS mediator" - - if [[ "${warm_start}" == ".true." ]]; then - - # Determine the appropriate restart file - local restart_date cmeps_restart_file - if [[ "${RERUN}" == "YES" ]]; then - restart_date="${RERUN_DATE}" - local seconds - seconds=$(to_seconds "${restart_date:8:2}0000") # convert HHMMSS to seconds - cmeps_restart_file="${DATArestart}/CMEPS_RESTART/ufs.cpld.cpl.r.${restart_date:0:4}-${restart_date:4:2}-${restart_date:6:2}-${seconds}.nc" - else # "${RERUN}" == "NO" - restart_date="${model_start_date_current_cycle}" - cmeps_restart_file="${COMIN_MED_RESTART_PREV}/${restart_date:0:8}.${restart_date:8:2}0000.ufs.cpld.cpl.r.nc" - fi - - # Copy CMEPS restarts - if [[ -f "${cmeps_restart_file}" ]]; then - cpreq "${cmeps_restart_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 - # 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 CMEPS restart file - echo "WARNING: CMEPS restart file '${cmeps_restart_file}' not found for warm_start='${warm_start}', will initialize!" - if [[ "${RERUN}" == "YES" ]]; then - # In the case of a RERUN, the CMEPS restart file is required - echo "FATAL ERROR: CMEPS restart file '${cmeps_restart_file}' not found for RERUN='${RERUN}', ABORT!" - exit 1 - fi - fi - - fi # [[ "${warm_start}" == ".true." ]]; - - # For CMEPS, CICE, MOM6 and WW3 determine restart writes - # Note FV3 has its own restart intervals - cmeps_restart_interval=${restart_interval:-${FHMAX}} - # restart_interval = 0 implies write restart at the END of the forecast i.e. at FHMAX - # Convert restart interval into an explicit list for CMEPS/CICE/MOM6/WW3 - # Note, this must be computed after determination IAU in forecast_det and fhrot. - if ((cmeps_restart_interval == 0)); then - if [[ "${DOIAU:-NO}" == "YES" ]]; then - CMEPS_RESTART_FH=$((FHMAX + half_window)) - else - CMEPS_RESTART_FH=("${FHMAX}") - fi - else - if [[ "${DOIAU:-NO}" == "YES" ]]; then - if [[ "${MODE}" = "cycled" && "${SDATE}" = "${PDY}${cyc}" && ${EXP_WARM_START} = ".false." ]]; then - local restart_interval_start=${cmeps_restart_interval} - local restart_interval_end=${FHMAX} - else - local restart_interval_start=$((cmeps_restart_interval + half_window)) - local restart_interval_end=$((FHMAX + half_window)) - fi - else - local restart_interval_start=${cmeps_restart_interval} - local restart_interval_end=${FHMAX} - fi - CMEPS_RESTART_FH="$(seq -s ' ' "${restart_interval_start}" "${cmeps_restart_interval}" "${restart_interval_end}")" - fi - export CMEPS_RESTART_FH - # TODO: For GEFS, once cycling waves "self-cycles" and therefore needs to have a restart at 6 hour - -} - -CMEPS_out() { - echo "SUB ${FUNCNAME[0]}: Copying output data for CMEPS mediator" - - case ${RUN} in - gdas | enkfgdas | enkfgfs) # Copy restarts for the next cycle to COM - local restart_date - restart_date="${model_start_date_next_cycle}" - echo "Copying mediator restarts for 'RUN=${RUN}' at ${restart_date}" - seconds=$(to_seconds "${restart_date:8:2}"0000) - source_file="ufs.cpld.cpl.r.${restart_date:0:4}-${restart_date:4:2}-${restart_date:6:2}-${seconds}.nc" - target_file="${restart_date:0:8}.${restart_date:8:2}0000.ufs.cpld.cpl.r.nc" - if [[ -f "${DATArestart}/CMEPS_RESTART/${source_file}" ]]; then - cpfs "${DATArestart}/CMEPS_RESTART/${source_file}" \ - "${COMOUT_MED_RESTART}/${target_file}" - else - echo "Mediator restart '${DATArestart}/CMEPS_RESTART/${source_file}' not found." - fi - ;; - gfs | gefs | sfs | gcafs) # Copy mediator restarts at the end of the forecast segment - if [[ "${COPY_FINAL_RESTARTS}" == "YES" ]]; then - echo "Copying mediator restarts for 'RUN=${RUN}' at ${forecast_end_cycle}" - local seconds source_file target_file - seconds=$(to_seconds "${forecast_end_cycle:8:2}"0000) - source_file="ufs.cpld.cpl.r.${forecast_end_cycle:0:4}-${forecast_end_cycle:4:2}-${forecast_end_cycle:6:2}-${seconds}.nc" - target_file="${forecast_end_cycle:0:8}.${forecast_end_cycle:8:2}0000.ufs.cpld.cpl.r.nc" - if [[ -f "${DATArestart}/CMEPS_RESTART/${source_file}" ]]; then - cpfs "${DATArestart}/CMEPS_RESTART/${source_file}" \ - "${COMOUT_MED_RESTART}/${target_file}" - else - echo "Mediator restart '${DATArestart}/CMEPS_RESTART/${source_file}' not found." - fi - fi - ;; - *) - echo "FATAL ERROR: Not sure how to copy restart files for RUN ${RUN}" - exit 25 - ;; - esac -} From 6a70bc2b422adad555b9c0da3862b1b0e69ebfdb Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Tue, 16 Dec 2025 18:36:10 +0000 Subject: [PATCH 15/22] Issue #4339: Enable EnKF-only for atmosphere (3rd try): remove temporary file --- parm/post/gcafs | 1 - parm/ufs/post_itag_gcafs | 1 - 2 files changed, 2 deletions(-) delete mode 120000 parm/post/gcafs delete mode 120000 parm/ufs/post_itag_gcafs diff --git a/parm/post/gcafs b/parm/post/gcafs deleted file mode 120000 index 89005e7ea58..00000000000 --- a/parm/post/gcafs +++ /dev/null @@ -1 +0,0 @@ -/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/upp.fd/parm/gcafs \ No newline at end of file diff --git a/parm/ufs/post_itag_gcafs b/parm/ufs/post_itag_gcafs deleted file mode 120000 index b600e0b4125..00000000000 --- a/parm/ufs/post_itag_gcafs +++ /dev/null @@ -1 +0,0 @@ -/scratch4/BMC/gsienkf/Bo.Huang/expCodes/Workflow/EnKFOnly-20251031/global-workflow/sorc/ufs_model.fd/tests/parm/post_itag_gcafs \ No newline at end of file From e52d0391e134ecc1b183caee61e8dbd7c45ef4b4 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Wed, 14 Jan 2026 00:26:42 +0000 Subject: [PATCH 16/22] Fix shfmt failure (try 1) --- dev/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE | 2 +- dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS | 54 ++++++++++----------- dev/jobs/JGLOBAL_ENKF_SELECT_OBS | 2 +- sorc/link_workflow.sh | 2 +- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/dev/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE b/dev/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE index f46232b45c9..42fce2ee9f4 100755 --- a/dev/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE +++ b/dev/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE @@ -19,7 +19,7 @@ GDUMP="gdas" RUN=${GDUMP} YMD=${PDY} HH=${cyc} declare_from_tmpl -rx \ COMIN_OBS:COM_OBS_TMPL -if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then +if [[ ${DOENKFONLY_ATM:-"NO"} == "YES" ]]; then MEMDIR='ensstat' RUN="enkf${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ COMIN_ATMOS_ANALYSIS_PREV:COM_ATMOS_ANALYSIS_TMPL else diff --git a/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS index 4aacc9ffc52..f1a307c411e 100755 --- a/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS +++ b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS @@ -20,7 +20,7 @@ export GDUMP="gdas" # Generate COM variables from templates MEMDIR="ensstat" RUN="enkf${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ - COMOUT_ATMOS_ANALYSIS_PREV:COM_ATMOS_ANALYSIS_TMPL \ + COMOUT_ATMOS_ANALYSIS_PREV:COM_ATMOS_ANALYSIS_TMPL # Process bias corrections files grabbed from HPSS in task gdas_fetchatmanlbias BIASDIR=${DATA}/${GDUMP}.${gPDY}/${gcyc}/atmos @@ -42,36 +42,36 @@ if [[ ${DO_JEDIATMENS} == "YES" ]]; then # JEDI run cd "${DATA}" || exit if [[ ! -d "testrun/varbc" ]]; then mkdir -p "testrun/varbc"; fi - /bin/ln -sf "${ABIAS_SAT}" "./satbias_in" + /bin/ln -sf "${ABIAS_SAT}" "./satbias_in" /bin/ln -sf "${ABIASPC_SAT}" "./satbias_pc" - grep -i "NaN" satbias_in && echo "Stop. There are NaN in ${ABIAS}." && exit 1 + grep -i "NaN" satbias_in && echo "Stop. There are NaN in ${ABIAS}." && exit 1 # Get instruments from satbias_in - obsclass=$(grep "_" satbias_in | awk '{print $2}' | uniq) + obsclass=$(grep "_" satbias_in | awk '{print $2}' | uniq) # Loop over instruments. Covert GSI abias to JEDI format - for instrument in $(echo ${obsclass}); do - echo ${instrument} - /bin/cp -f ${SATBIAS2IODAY} satbias_converter.yaml - sed -i -e "s/INSTRUMENT/${instrument}/g" satbias_converter.yaml + for instrument in ${obsclass}; do + echo "${instrument}" + /bin/cp -f "${SATBIAS2IODAY}" satbias_converter.yaml + sed -i -e "s/INSTRUMENT/${instrument}/g" satbias_converter.yaml - ${SATBIAS2IODAX} satbias_converter.yaml + ${SATBIAS2IODAX} satbias_converter.yaml - export err=$? - if [[ ${err} -ne 0 ]]; then + export err=$? + if [[ ${err} -ne 0 ]]; then err_exit "satbias2iodas.x failed for ${instrument}, ABORT!" - fi - - /bin/rm -f testrun/varbc/*nc - /bin/rm -f testrun/varbc/*txt - - cd ./testrun/varbc/ - grep ${instrument} ../../satbias_in | awk '{print $2" "$3" "$4}' > \ - ${OUTPUT}/gdas.t${gcyc}z.${instrument}.tlapse.txt - /bin/cp -p satbias_${instrument}.nc4 ${OUTPUT}/gdas.t${gcyc}z.${instrument}.satbias.nc - /bin/mv satbias_${instrument}.nc4 ${OUTPUT}/gdas.t${gcyc}z.${instrument}.satbias_cov.nc - cd ${DATA} - /bin/rm -rf satbias_converter.yaml + fi + + /bin/rm -f testrun/varbc/*nc + /bin/rm -f testrun/varbc/*txt + + cd ./testrun/varbc/ + grep "${instrument}" ../../satbias_in | awk '{print $2" "$3" "$4}' > \ + "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".tlapse.txt + /bin/cp -p satbias_"${instrument}".nc4 "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".satbias.nc + /bin/mv satbias_"${instrument}".nc4 "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".satbias_cov.nc + cd "${DATA}" + /bin/rm -rf satbias_converter.yaml done if [[ ${err} -eq 0 ]]; then @@ -82,11 +82,11 @@ if [[ ${DO_JEDIATMENS} == "YES" ]]; then if [[ ${err} -ne 0 ]]; then err_exit "Error copying operational anl bias correction files" fi - done + done # TODO: Temporary solution and need to process abias_air for JEDI when ready - tar -cvf ${ABIAS_AIR_JEDI_TAR} "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" - rm -rf "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" - tar -cvf ${ABIAS_SAT_JEDI_TAR} ./*.nc ./*.txt + tar -cvf "${ABIAS_AIR_JEDI_TAR}" "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" + rm -rf "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" + tar -cvf "${ABIAS_SAT_JEDI_TAR}" ./*.nc ./*.txt err=$? fi diff --git a/dev/jobs/JGLOBAL_ENKF_SELECT_OBS b/dev/jobs/JGLOBAL_ENKF_SELECT_OBS index 6eb0f6be714..db4b842cf98 100755 --- a/dev/jobs/JGLOBAL_ENKF_SELECT_OBS +++ b/dev/jobs/JGLOBAL_ENKF_SELECT_OBS @@ -65,7 +65,7 @@ if [[ ${DONST} == "YES" ]]; then fi export PREPQCPF="${COMIN_OBS}/${OPREFIX}prepbufr.acft_profiles" -if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]] ; then +if [[ ${DOENKFONLY_ATM:-"NO"} == "YES" ]]; then # Ensemble analysis and increment files export SFCANL="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}analysis.sfc.a006.nc" export DTFANL="${COMOUT_ATMOS_ANALYSIS}/${APREFIX}increment.dtf.i006.nc" diff --git a/sorc/link_workflow.sh b/sorc/link_workflow.sh index e0c61f301c4..6b54f835685 100755 --- a/sorc/link_workflow.sh +++ b/sorc/link_workflow.sh @@ -438,7 +438,7 @@ fi # GDASApp executables if [[ -d "${HOMEgfs}/sorc/gdas.cd/install" ]]; then - cp -f "${HOMEgfs}/sorc/gdas.cd/install/bin"/gdas* ./ + cp -f "${HOMEgfs}/sorc/gdas.cd/install/bin"/gdas* ./ cp -f "${HOMEgfs}/sorc/gdas.cd/install/bin/satbias2ioda.x" ./satbias2ioda.x cp -f "${HOMEgfs}/sorc/gdas.cd/install/bin/apply_incr.exe" ./gdas_apply_incr.x fi From d2f7005aaed3f5447f8d2b453241bab6d3db9e95 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Wed, 14 Jan 2026 00:36:00 +0000 Subject: [PATCH 17/22] Fix shfmt failure (try 2) --- dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS index f1a307c411e..7e1a415ea2a 100755 --- a/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS +++ b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS @@ -67,9 +67,9 @@ if [[ ${DO_JEDIATMENS} == "YES" ]]; then cd ./testrun/varbc/ grep "${instrument}" ../../satbias_in | awk '{print $2" "$3" "$4}' > \ - "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".tlapse.txt - /bin/cp -p satbias_"${instrument}".nc4 "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".satbias.nc - /bin/mv satbias_"${instrument}".nc4 "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".satbias_cov.nc + "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".tlapse.txt + /bin/cp -p satbias_"${instrument}".nc4 "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".satbias.nc + /bin/mv satbias_"${instrument}".nc4 "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".satbias_cov.nc cd "${DATA}" /bin/rm -rf satbias_converter.yaml done @@ -83,7 +83,7 @@ if [[ ${DO_JEDIATMENS} == "YES" ]]; then err_exit "Error copying operational anl bias correction files" fi done - # TODO: Temporary solution and need to process abias_air for JEDI when ready + # TODO: Temporary solution and need to process abias_air for JEDI when ready tar -cvf "${ABIAS_AIR_JEDI_TAR}" "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" rm -rf "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" tar -cvf "${ABIAS_SAT_JEDI_TAR}" ./*.nc ./*.txt From 6d092193c9e117948f1e388c05d03005c456fddc Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Wed, 14 Jan 2026 00:39:34 +0000 Subject: [PATCH 18/22] Fix shfmt failure (try 3) --- dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS index 7e1a415ea2a..aed103e4201 100755 --- a/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS +++ b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS @@ -69,7 +69,7 @@ if [[ ${DO_JEDIATMENS} == "YES" ]]; then grep "${instrument}" ../../satbias_in | awk '{print $2" "$3" "$4}' > \ "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".tlapse.txt /bin/cp -p satbias_"${instrument}".nc4 "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".satbias.nc - /bin/mv satbias_"${instrument}".nc4 "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".satbias_cov.nc + /bin/mv satbias_"${instrument}".nc4 "${OUTPUT}"/gdas.t"${gcyc}"z."${instrument}".satbias_cov.nc cd "${DATA}" /bin/rm -rf satbias_converter.yaml done From 59755de6cc2fa4cc7766bea10fedaa536013399c Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Thu, 15 Jan 2026 17:22:37 +0000 Subject: [PATCH 19/22] Fix shfmt failure (try 4) --- dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS index aed103e4201..c2ce8d397ae 100755 --- a/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS +++ b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS @@ -10,7 +10,7 @@ source "${HOMEgfs}/ush/jjob_header.sh" -e "prepatmanlbias" -c "base prepatmanlbi ############################################## # Begin JOB SPECIFIC work ############################################## -export GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") +GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") export gPDY=${GDATE:0:8} export gcyc=${GDATE:8:2} export gyy=${GDATE:0:4} @@ -101,7 +101,6 @@ else done fi - if [[ ${err} -ne 0 ]]; then err_exit "Error executing ${EXSCRIPT}" fi From aa45fe9fb7141cf8cfdeb0ed32928cbff680c82f Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Thu, 15 Jan 2026 18:55:18 +0000 Subject: [PATCH 20/22] Fix shellcheck failure (try 1) --- dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS index c2ce8d397ae..118cd134190 100755 --- a/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS +++ b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS @@ -10,6 +10,8 @@ source "${HOMEgfs}/ush/jjob_header.sh" -e "prepatmanlbias" -c "base prepatmanlbi ############################################## # Begin JOB SPECIFIC work ############################################## +# Ignore possible spelling error (nothing is misspelled) +# shellcheck disable=SC2153 GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") export gPDY=${GDATE:0:8} export gcyc=${GDATE:8:2} From 95ae053be8273fb69965486b3d626014cd1d3265 Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Fri, 16 Jan 2026 18:38:30 +0000 Subject: [PATCH 21/22] Update sorc/gdas.cd --- sorc/gdas.cd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sorc/gdas.cd b/sorc/gdas.cd index 882c00fd53c..78ab7016461 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit 882c00fd53ccc6493b78f946b0ca9ace593518f2 +Subproject commit 78ab701646169b18bfb2787496e8bb334e3a6fda From 26a993d6bce089fce84f5162aac66f9dc00c47fc Mon Sep 17 00:00:00 2001 From: Bo Huang Date: Fri, 16 Jan 2026 18:45:33 +0000 Subject: [PATCH 22/22] use parm/jcb-gdas develop in sorc/gdas.cd --- sorc/gdas.cd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sorc/gdas.cd b/sorc/gdas.cd index 78ab7016461..bfb20db68d9 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit 78ab701646169b18bfb2787496e8bb334e3a6fda +Subproject commit bfb20db68d99aa649cdad51ac6a65697a782c781