diff --git a/dev/ci/cases/pr/C48_gsienkf_atmDA.yaml b/dev/ci/cases/pr/C48_gsienkf_atmDA.yaml new file mode 100644 index 00000000000..3e173cee86c --- /dev/null +++ b/dev/ci/cases/pr/C48_gsienkf_atmDA.yaml @@ -0,0 +1,30 @@ +experiment: + net: gfs + mode: cycled + pslot: {{ 'pslot' | getenv }} + app: ATM + resdetatmos: 96 + resensatmos: 48 + comroot: {{ 'RUNTESTS' | getenv }}/COMROOT + expdir: {{ 'RUNTESTS' | getenv }}/EXPDIR + icsdir: {{ 'ICSDIR_ROOT' | getenv }}/C96C48/20250808 + idate: 2024022318 + edate: 2024022406 + nens: 2 + interval: 0 + start: warm + yaml: {{ HOMEgfs }}/dev/ci/cases/yamls/gsienkf_atmDA_defaults.ci.yaml + +skip_ci_on_hosts: + - gaeac5 + - orion + - hercules + - awsepicglobalworkflow + +workflow: + engine: rocoto + rocoto: + maxtries: 2 + cyclethrottle: 3 + taskthrottle: 25 + verbosity: 2 diff --git a/dev/ci/cases/pr/C48_ufsenkf_atmDA.yaml b/dev/ci/cases/pr/C48_ufsenkf_atmDA.yaml new file mode 100644 index 00000000000..b55f1de57b2 --- /dev/null +++ b/dev/ci/cases/pr/C48_ufsenkf_atmDA.yaml @@ -0,0 +1,30 @@ +experiment: + net: gfs + mode: cycled + pslot: {{ 'pslot' | getenv }} + app: ATM + resdetatmos: 96 + resensatmos: 48 + comroot: {{ 'RUNTESTS' | getenv }}/COMROOT + expdir: {{ 'RUNTESTS' | getenv }}/EXPDIR + icsdir: {{ 'ICSDIR_ROOT' | getenv }}/C96C48/20250808 + idate: 2024022318 + edate: 2024022406 + nens: 2 + interval: 0 + start: warm + yaml: {{ HOMEgfs }}/dev/ci/cases/yamls/ufsenkf_atmDA_defaults.ci.yaml + +skip_ci_on_hosts: + - gaeac5 + - orion + - hercules + - awsepicglobalworkflow + +workflow: + engine: rocoto + rocoto: + maxtries: 2 + cyclethrottle: 3 + taskthrottle: 25 + verbosity: 2 diff --git a/dev/ci/cases/yamls/gsienkf_atmDA_defaults.ci.yaml b/dev/ci/cases/yamls/gsienkf_atmDA_defaults.ci.yaml new file mode 100644 index 00000000000..6f27588162b --- /dev/null +++ b/dev/ci/cases/yamls/gsienkf_atmDA_defaults.ci.yaml @@ -0,0 +1,13 @@ +defaults: + !INC {{ HOMEgfs }}/dev/parm/config/gfs/yaml/defaults.yaml +base: + DOIAU: "NO" + DO_JEDIATMVAR: "NO" + DO_JEDIATMENS: "NO" + DOENKFONLY_ATM: "YES" + DO_TEST_MODE: "NO" + CASE_ANL: "C48" + CASE_HIST: "C96" + DONST: "NO" + DO_ARCHCOM: "YES" + USE_IODADIR: "NO" diff --git a/dev/ci/cases/yamls/ufsenkf_atmDA_defaults.ci.yaml b/dev/ci/cases/yamls/ufsenkf_atmDA_defaults.ci.yaml new file mode 100644 index 00000000000..0a76c23e6ec --- /dev/null +++ b/dev/ci/cases/yamls/ufsenkf_atmDA_defaults.ci.yaml @@ -0,0 +1,13 @@ +defaults: + !INC {{ HOMEgfs }}/dev/parm/config/gfs/yaml/defaults.yaml +base: + DOIAU: "NO" + DO_JEDIATMVAR: "NO" + DO_JEDIATMENS: "YES" + DOENKFONLY_ATM: "YES" + DO_TEST_MODE: "NO" + CASE_ANL: "C48" + CASE_HIST: "C96" + DONST: "NO" + DO_ARCHCOM: "YES" + USE_IODADIR: "YES" diff --git a/dev/ci/gitlab-ci-hosts.yml b/dev/ci/gitlab-ci-hosts.yml index 34a67cd5948..b4f34a1e707 100644 --- a/dev/ci/gitlab-ci-hosts.yml +++ b/dev/ci/gitlab-ci-hosts.yml @@ -22,10 +22,10 @@ # Template matrices for case lists .hera_cases_matrix: &hera_cases - - caseName: ["C48_ATM", "C48_S2SW", "C48_S2SWA_gefs", "C48mx500_3DVarAOWCDA", "C48mx500_hybAOWCDA", "C96C48_hybatmDA", "C96C48_hybatmsnowDA", "C96C48_hybatmsoilDA", "C96C48_ufsgsi_hybatmDA", "C96C48_ufs_hybatmDA", "C96C48mx500_S2SW_cyc_gfs", "C96_atm3DVar", "C96_gcafs_cycled", "C96_gcafs_cycled_noDA", "C96mx100_S2S"] + - caseName: ["C48_ATM", "C48_S2SW", "C48_S2SWA_gefs", "C48mx500_3DVarAOWCDA", "C48mx500_hybAOWCDA", "C96C48_hybatmDA", "C96C48_hybatmsnowDA", "C96C48_hybatmsoilDA", "C96C48_ufsgsi_hybatmDA", "C96C48_ufs_hybatmDA", "C96C48mx500_S2SW_cyc_gfs", "C96_atm3DVar", "C96_gcafs_cycled", "C96_gcafs_cycled_noDA", "C96mx100_S2S", "C48_gsienkf_atmDA", "C48_ufsenkf_atmDA"] .gaeac6_cases_matrix: &gaeac6_cases - - caseName: ["C48_ATM", "C48_S2SW", "C48_S2SWA_gefs", "C48mx500_3DVarAOWCDA", "C48mx500_hybAOWCDA", "C96C48_hybatmDA", "C96C48_hybatmsnowDA", "C96C48_hybatmsoilDA", "C96C48mx500_S2SW_cyc_gfs", "C96_atm3DVar", "C96_gcafs_cycled", "C96_gcafs_cycled_noDA", "C96mx100_S2S"] + - caseName: ["C48_ATM", "C48_S2SW", "C48_S2SWA_gefs", "C48mx500_3DVarAOWCDA", "C48mx500_hybAOWCDA", "C96C48_hybatmDA", "C96C48_hybatmsnowDA", "C96C48_hybatmsoilDA", "C96C48mx500_S2SW_cyc_gfs", "C96_atm3DVar", "C96_gcafs_cycled", "C96_gcafs_cycled_noDA", "C96mx100_S2S", "C48_gsienkf_atmDA", "C48_ufsenkf_atmDA"] .orion_cases_matrix: &orion_cases - caseName: ["C48_ATM", "C48_S2SW", "C48_S2SWA_gefs", "C96C48_hybatmDA", "C96C48mx500_S2SW_cyc_gfs", "C96_atm3DVar", "C96mx100_S2S", "C96_gcafs_cycled"] @@ -34,7 +34,7 @@ - caseName: ["C48_ATM", "C48_S2SW", "C48_S2SWA_gefs", "C48mx500_3DVarAOWCDA", "C48mx500_hybAOWCDA", "C96C48_hybatmDA", "C96C48mx500_S2SW_cyc_gfs", "C96_atm3DVar", "C96mx100_S2S", "C96_gcafs_cycled"] .ursa_cases_matrix: &ursa_cases - - caseName: ["C48_ATM", "C48_S2SW", "C48_S2SWA_gefs", "C48mx500_3DVarAOWCDA", "C48mx500_hybAOWCDA", "C96C48_hybatmDA", "C96C48_hybatmsnowDA", "C96C48_hybatmsoilDA", "C96C48_ufsgsi_hybatmDA", "C96C48_ufs_hybatmDA", "C96C48mx500_S2SW_cyc_gfs", "C96_atm3DVar", "C96mx100_S2S", "C96_gcafs_cycled", "C96_gcafs_cycled_noDA"] + - caseName: ["C48_ATM", "C48_S2SW", "C48_S2SWA_gefs", "C48mx500_3DVarAOWCDA", "C48mx500_hybAOWCDA", "C96C48_hybatmDA", "C96C48_hybatmsnowDA", "C96C48_hybatmsoilDA", "C96C48_ufsgsi_hybatmDA", "C96C48_ufs_hybatmDA", "C96C48mx500_S2SW_cyc_gfs", "C96_atm3DVar", "C96mx100_S2S", "C96_gcafs_cycled", "C96_gcafs_cycled_noDA", "C48_gsienkf_atmDA", "C48_ufsenkf_atmDA"] # Host: Hera - Standard Cases setup_experiments-hera: diff --git a/dev/job_cards/rocoto/prep.sh b/dev/job_cards/rocoto/prep.sh index 578b5bbf0f6..3c4efa7977a 100755 --- a/dev/job_cards/rocoto/prep.sh +++ b/dev/job_cards/rocoto/prep.sh @@ -150,6 +150,19 @@ export COMINgfs=${COMIN_ATMOS_HISTORY_GFS} export COMSP=${COMSP:-"${COMIN_OBS}/${RUN_local}.t${cyc}z."} +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" +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/job_cards/rocoto/prepatmanlbias.sh b/dev/job_cards/rocoto/prepatmanlbias.sh new file mode 100755 index 00000000000..2d576aa68ba --- /dev/null +++ b/dev/job_cards/rocoto/prepatmanlbias.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="prepatmanlbias" +export jobid="${job}.$$" + +############################################################### +# Execute the JJOB +"${HOMEgfs}/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS" +status=$? +exit "${status}" diff --git a/dev/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE b/dev/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE index 9037fcc77df..55072fe514d 100755 --- a/dev/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE +++ b/dev/jobs/JGLOBAL_ATMENS_ANALYSIS_INITIALIZE @@ -23,8 +23,13 @@ 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 + MEMDIR='ensstat' RUN="enkf${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ + COMIN_ATMOS_ANALYSIS_PREV:COM_ATMOS_ANALYSIS_TMPL +else + RUN=${GDUMP} YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ + COMIN_ATMOS_ANALYSIS_PREV:COM_ATMOS_ANALYSIS_TMPL +fi ############################################################### # Run relevant script diff --git a/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS new file mode 100755 index 00000000000..386ff87421f --- /dev/null +++ b/dev/jobs/JGLOBAL_ATM_PREP_ANL_BIAS @@ -0,0 +1,137 @@ +#! /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 +############################################## +# 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} +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_SAT=${BIASDIR}/${GDUMP}.t${gcyc}z.abias +ABIASPC_SAT=${BIASDIR}/${GDUMP}.t${gcyc}z.abias_pc +ABIAS_SAT_JEDI_TAR=${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.rad_varbc_params.tar +ABIAS_AIR_JEDI_TAR=${COMOUT_ATMOS_ANALYSIS_PREV}/${GDUMP}.t${gcyc}z.air_varbc_params.tar + +SATBIAS2IODAX=${SATBIAS2IODAX:-${EXECgfs}/satbias2ioda.x} +SATBIAS2IODAY=${HOMEgfs}/sorc/gdas.cd/ush/satbias_converter.yaml.tmpl +OUTPUT=${DATA}/output + +mkdir -p "${COMOUT_ATMOS_ANALYSIS_PREV}" +mkdir -p "${OUTPUT}" + +if [[ ${DO_JEDIATMENS} == "YES" ]]; then + # JEDI run + cd "${DATA}" || exit 1 + mkdir -p "testrun/varbc" + ln -sf "${ABIAS_SAT}" "./satbias_in" + ln -sf "${ABIASPC_SAT}" "./satbias_pc" + if grep -i "NaN" satbias_in > /dev/null 2>&1; then + ##export err=1 + ##err_chk "FATAL ERROR There are NaN in satbias_in." + echo "WARNING: There are NaN in satbias_in. Replace NaN with 0.000000" + cp satbias_in satbias_in_original + sed -i -e 's/ NaN/ 0.000000/g' \ + -e 's/ nan/ 0.000000/g' \ + -e 's/ NAN/ 0.000000/g' satbias_in + fi + + # 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 ${obsclass}; do + echo "${instrument}" + cp -f "${SATBIAS2IODAY}" satbias_converter.yaml + sed -i -e "s/INSTRUMENT/${instrument}/g" satbias_converter.yaml + + ${SATBIAS2IODAX} satbias_converter.yaml + + export err=$? + if [[ ${err} -ne 0 ]]; then + err_exit "FATAL ERROR satbias2iodas.x failed for ${instrument}, ABORT!" + fi + + rm -f testrun/varbc/*nc + rm -f testrun/varbc/*txt + + cd ./testrun/varbc/ + grep "${instrument}" ../../satbias_in | awk '{print $2" "$3" "$4}' > \ + "${OUTPUT}/gdas.t${gcyc}z.radiance_${instrument}.tlapse.txt" + cpreq -p "satbias_${instrument}.nc4" "${OUTPUT}/gdas.t${gcyc}z.radiance_${instrument}.satbias.nc" + mv "satbias_${instrument}.nc4" "${OUTPUT}/gdas.t${gcyc}z.radiance_${instrument}.satbias_cov.nc" + cd "${DATA}" + rm -f satbias_converter.yaml + done + + if [[ ${err} -eq 0 ]]; then + cd "${OUTPUT}" || exit + for file in ${BIASFILES}; do + cpreq "${BIASDIR}/${file}" "./enkf${file}.txt" + export 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_TAR}" "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" + rm -f "./enkf${GDUMP}.t${gcyc}z.abias_air.txt" + tar -cvf "${ABIAS_SAT_JEDI_TAR}" ./*.nc ./*.txt + export err=$? + fi + +else + # GSI run + for file in ${BIASFILES}; do + cpreq "${BIASDIR}/${file}" "${COMOUT_ATMOS_ANALYSIS_PREV}/enkf${file}.txt" + export err=$? + if [[ ${err} -ne 0 ]]; then + err_exit "FATAL ERROR copying operational anl bias correction files" + fi + done +fi + +if [[ ${err} -ne 0 ]]; then + err_exit "FATAL 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/dev/jobs/JGLOBAL_ENKF_SELECT_OBS b/dev/jobs/JGLOBAL_ENKF_SELECT_OBS index 35f10c50167..4a618f4dab9 100755 --- a/dev/jobs/JGLOBAL_ENKF_SELECT_OBS +++ b/dev/jobs/JGLOBAL_ENKF_SELECT_OBS @@ -75,17 +75,31 @@ 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 DTFINC="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}increment.dtf.i006.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 + # Deterministic analysis and increment files + export SFCANL="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}analysis.sfc.a006.nc" + export DTFINC="${COMOUT_ATMOS_ANALYSIS_DET}/${APREFIX_DET}increment.dtf.i006.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 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.tar" +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}increment.dtf.i006.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/dev/jobs/JGLOBAL_FETCH b/dev/jobs/JGLOBAL_FETCH index 88fa1febbe7..047e47bb959 100755 --- a/dev/jobs/JGLOBAL_FETCH +++ b/dev/jobs/JGLOBAL_FETCH @@ -1,5 +1,5 @@ #! /usr/bin/env bash - +export DATA=${DATA:-${DATAROOT}/${RUN}fetch_${cyc}} source "${HOMEgfs}/ush/jjob_header.sh" -e "fetch" -c "base fetch" # Setup Python path for pygfs diff --git a/dev/parm/config/gfs/config.base.j2 b/dev/parm/config/gfs/config.base.j2 index 31231939575..a03c1ac62ae 100644 --- a/dev/parm/config/gfs/config.base.j2 +++ b/dev/parm/config/gfs/config.base.j2 @@ -396,6 +396,10 @@ export BUILD_GSINFO_DIR="${PARMgfs}/gsinfo" 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 }}" +if [[ "${DOENKFONLY_ATM}" = "YES" && "${DO_JEDIATMENS}" = "YES" ]]; then + export DO_HISTORY_FILE_ON_NATIVE_GRID="YES" +fi # EnKF output frequency if [[ "${DOHYBVAR}" = "YES" ]]; then @@ -519,6 +523,17 @@ 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 +fi + # If starting ICs that are not at cycle hour export OFFSET_START_HOUR=0 diff --git a/dev/parm/config/gfs/config.esfc b/dev/parm/config/gfs/config.esfc index 0c35240dc31..0d12aace2af 100644 --- a/dev/parm/config/gfs/config.esfc +++ b/dev/parm/config/gfs/config.esfc @@ -26,6 +26,11 @@ if [[ "${DO_JEDIATMENS}" == "YES" || "${DO_JEDIATMVAR}" == "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.fetch b/dev/parm/config/gfs/config.fetch index 86ab5e3e2f8..882db90d290 100644 --- a/dev/parm/config/gfs/config.fetch +++ b/dev/parm/config/gfs/config.fetch @@ -7,13 +7,31 @@ 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-bias.yaml.j2" + export KEEPDATA="YES" + 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.prep.j2 b/dev/parm/config/gfs/config.prep.j2 index a8b8f0c619a..450aed1a4df 100644 --- a/dev/parm/config/gfs/config.prep.j2 +++ b/dev/parm/config/gfs/config.prep.j2 @@ -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/config.prepatmanlbias b/dev/parm/config/gfs/config.prepatmanlbias new file mode 100644 index 00000000000..89bfd1a247a --- /dev/null +++ b/dev/parm/config/gfs/config.prepatmanlbias @@ -0,0 +1,11 @@ +#! /usr/bin/env bash + +########## config.prepatmiodaobs ########## +# Atm Operational Anl Bias Correction specific + +echo "BEGIN: config.prepatmanlbias" + +# Get task specific resources +. "${EXPDIR}/config.resources" prepatmanlbias + +echo "END: config.prepatmanlbias" diff --git a/dev/parm/config/gfs/config.resources b/dev/parm/config/gfs/config.resources index 5afb46b7c34..c3e87b0fd8f 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" + echo "prep prep_sfc prepatmanlbias" echo "atmanlinit atmanlvar atmanlfv3inc atmanlfinal" echo "atmensanlinit atmensanlobs atmensanlsol atmensanlletkf atmensanlfv3inc atmensanlfinal ecen_fv3jedi analcalc_fv3jedi" echo "snowanl esnowanl" @@ -111,6 +111,13 @@ case ${step} in memory="${mem_node_max}" ;; + "prepatmanlbias") + 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/parm/config/gfs/yaml/defaults.yaml b/dev/parm/config/gfs/yaml/defaults.yaml index 684d45133d0..261ce3d28c7 100644 --- a/dev/parm/config/gfs/yaml/defaults.yaml +++ b/dev/parm/config/gfs/yaml/defaults.yaml @@ -1,5 +1,6 @@ base: DOIAU: "YES" + DOENKFONLY_ATM: "NO" DO_JEDIATMVAR: "NO" DO_JEDIATMENS: "NO" DO_JEDIATMENS_SPLIT_OBSSOL: "YES" diff --git a/dev/workflow/applications/gfs_cycled.py b/dev/workflow/applications/gfs_cycled.py index dadf0619f83..8143b42933a 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) run_options[run]['do_fit2obs'] = base.get('DO_FIT2OBS', True) @@ -104,6 +105,11 @@ def _get_app_configs(self, run): configs = ['prep'] + if options['do_enkfonly_atm']: + configs += ['fetch', 'prepatmanlbias'] + if options['do_archcom']: + configs += ['earc_tars', 'earc_groups'] + if options['do_prep_sfc']: configs += ['prep_sfc'] @@ -376,6 +382,12 @@ def get_task_names(self): task_names[run] += ['cleanup'] + # 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', 'fetchatmanlbias', 'prepatmanlbias'] + # Ensemble tasks elif 'enkf' in run: @@ -414,4 +426,17 @@ def get_task_names(self): task_names[run] += ['cleanup'] + # Reset tasks to run enkf-only for atm if do_enkfonly_atm=true + if options['do_enkfonly_atm']: + task_names[run] = [] + task_names[run] += ['stage_ic'] + if options['do_jediatmens']: + task_names[run] += ['atmensanlinit', 'atmensanlfv3inc', 'atmensanlfinal'] + if options['do_jediatmens_split_obssol']: + task_names[run] += ['atmensanlobs', 'atmensanlsol'] + else: + task_names[run] += ['atmensanlletkf'] + else: + task_names[run] += ['eobs', 'eupd', 'ecen', 'ediag'] + task_names[run] += ['efcs', 'epos', 'esfc', 'earc_tars', 'cleanup'] return task_names diff --git a/dev/workflow/rocoto/gfs_tasks.py b/dev/workflow/rocoto/gfs_tasks.py index d8c89e84058..660c5601e5c 100644 --- a/dev/workflow/rocoto/gfs_tasks.py +++ b/dev/workflow/rocoto/gfs_tasks.py @@ -36,6 +36,31 @@ def fetch(self): return task + def fetchatmanlbias(self): + 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=deps) + + cycledef = self.run + + resources = self.get_resource('fetch') + task_name = f'{self.run}_fetchatmanlbias' + task_dict = {'task_name': task_name, + 'resources': resources, + 'dependency': dependencies, + 'envars': self.envars, + 'cycledef': cycledef, + 'command': f'{self.HOMEgfs}/dev/job_cards/rocoto/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) + + return task + def stage_ic(self): dependencies = None @@ -109,11 +134,15 @@ 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 self.options['do_enkfonly_atm']: + dep_dict = {'type': 'metatask', 'name': 'enkfgdas_epmn', 'offset': f"-{timedelta_to_HMS(self._base['interval_gdas'])}"} + deps.append(rocoto.add_dependency(dep_dict)) + else: + 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)) data = f'{dump_path}/{self.run}.t@Hz.updated.status.tm00.bufr_d' dep_dict = {'type': 'data', 'data': data} if self.options['do_jediatmvar']: @@ -130,8 +159,6 @@ def prep(self): dep_dict = {'type': 'data', 'data': data} deps.append(rocoto.add_dependency(dep_dict)) deps.append(rocoto.add_dependency(dep_dict)) - 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'} deps.append(rocoto.add_dependency(dep_dict)) @@ -158,6 +185,30 @@ def prep(self): return task + def prepatmanlbias(self): + + deps = [] + 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('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/job_cards/rocoto/prepatmanlbias.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') @@ -2443,9 +2494,9 @@ def cleanup(self): # All of the dependencies (half, full, and common) deps_all = [] if 'enkf' in self.run: - - dep_dict = {'type': 'task', 'name': f'{self.run}_earc_vrfy'} - deps_full.append(rocoto.add_dependency(dep_dict)) + if not self.options['do_enkfonly_atm']: + dep_dict = {'type': 'task', 'name': f'{self.run}_earc_vrfy'} + deps_full.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'} @@ -2468,8 +2519,9 @@ def cleanup(self): dep_dict = {'type': 'metatask', 'name': f'{self.run}_epmn'} deps_half.append(rocoto.add_dependency(dep_dict)) if not self.options['do_jediatmvar']: - dep_dict = {'type': 'task', 'name': f'{self.run}_echgres'} - deps_half.append(rocoto.add_dependency(dep_dict)) + if not self.options['do_enkfonly_atm']: + dep_dict = {'type': 'task', 'name': f'{self.run}_echgres'} + deps_half.append(rocoto.add_dependency(dep_dict)) else: if self.app_config.mode in ['cycled']: @@ -2644,6 +2696,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", "")}_prepatmanlbias'} + deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) resources = self.get_resource('eobs') @@ -2715,6 +2770,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", "")}_prepatmanlbias'} + deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) cycledef = "gdas" @@ -2892,8 +2950,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) @@ -2993,8 +3052,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']: @@ -3023,8 +3083,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)) @@ -3206,8 +3267,9 @@ def earc_tars(self): dep_dict = {'type': 'metatask', 'name': f'{self.run}_epmn'} deps.append(rocoto.add_dependency(dep_dict)) if not self.options['do_jediatmens']: - dep_dict = {'type': 'task', 'name': f'{self.run}_echgres'} - deps.append(rocoto.add_dependency(dep_dict)) + if not self.options['do_enkfonly_atm']: + 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/dev/workflow/rocoto/tasks.py b/dev/workflow/rocoto/tasks.py index b5d48e994bb..78207483c16 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', 'atmanlinit', 'atmanlvar', 'atmanlfv3inc', 'atmanlfinal', - 'prep_emissions', 'prepoceanobs', + 'prep_emissions', 'prepoceanobs', 'prepatmanlbias', 'marineanlinit', 'marineanlletkf', 'marinebmatinit', 'marinebmat', 'marineanlvar', 'marineanlecen', 'marineanlchkpt', 'marineanlfinal', 'ocnanalvrfy', 'eobs', 'epos', 'esfc', 'eupd', diff --git a/parm/archive/enkf.yaml.j2 b/parm/archive/enkf.yaml.j2 index f2fc488344a..05f930cecdb 100644 --- a/parm/archive/enkf.yaml.j2 +++ b/parm/archive/enkf.yaml.j2 @@ -10,9 +10,11 @@ enkf: {% for grp in range(0, enkf_epos_ngrps) %} - "logs/{{ cycle_YMDH }}/{{ RUN }}_epos{{ '%03d' % grp }}.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,9 +25,17 @@ enkf: {% if DO_JEDIATMENS %} {% if DO_JEDIATMENS_SPLIT_OBSSOL %} - {% 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 = ["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 %} {% endif %} {% else %} {% set steps = ["eobs", "ediag", "eupd"] %} @@ -41,7 +51,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 }}/{{ head |replace('enkf','')}}ensres.atm.f{{ '%03d' % fhr }}.nc" @@ -72,17 +82,29 @@ enkf: {% else %} {% if DO_JEDIATMENS_SPLIT_OBSSOL %} {% 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_conf_files = ["atmensanlobs.yaml", + "atmensanlsol.yaml", + "atmensanlfv3inc.yaml"] %} + {% else %} + {% set da_conf_files = ["atmensanlobs.yaml", + "atmensanlsol.yaml", + "atmensanlfv3inc.yaml", + "correction_increment.yaml", + "ensemble_recenter.yaml"] %} + {% endif %} {% else %} - {% set da_stat_files = ["atmos_analysis.ioda_hofx.ens_mean.tar.gz"]%} - {% set da_conf_files = ["atmensanlletkf.yaml", - "atmensanlfv3inc.yaml", - "correction_increment.yaml", - "ensemble_recenter.yaml"] %} + {% if DOENKFONLY_ATM %} + {% set da_stat_files = ["atmos_analysis.ioda_hofx.ens_mean.tar.gz"]%} + {% set da_conf_files = ["atmensanlletkf.yaml", + "atmensanlfv3inc.yaml"] %} + {% else %} + {% set da_stat_files = ["atmos_analysis.ioda_hofx.ens_mean.tar.gz"]%} + {% set da_conf_files = ["atmensanlletkf.yaml", + "atmensanlfv3inc.yaml", + "correction_increment.yaml", + "ensemble_recenter.yaml"] %} + {% endif %} {% endif %} {% endif %} {% for file in da_stat_files %} diff --git a/parm/archive/enkf_grp.yaml.j2 b/parm/archive/enkf_grp.yaml.j2 index b1a88d509b5..acf431c5ff9 100644 --- a/parm/archive/enkf_grp.yaml.j2 +++ b/parm/archive/enkf_grp.yaml.j2 @@ -14,17 +14,23 @@ enkf_grp: {% if DO_JEDIATMENS %} {% for iaufhr in iaufhrs_str %} {% for itile in range(6) %} + {% if DOENKFONLY_ATM %} + - "{{ COMIN_ATMOS_ANALYSIS_MEM }}/{{ head }}jedi_increment.atm.i{{ iaufhr }}.tile{{ itile+1 }}.nc" + {% else %} - "{{ COMIN_ATMOS_ANALYSIS_MEM }}/{{ head }}recentered_jedi_increment.atm.i{{ iaufhr }}.tile{{ itile+1 }}.nc" + {% endif %} {% endfor %} {% endfor %} {% else %} {% if do_calc_increment %} - "{{ COMIN_ATMOS_ANALYSIS_MEM }}/{{ head }}analysis.atm.a006.nc" {% else %} - {% for iaufhr in iaufhrs_str %} - {% set iaufhr = iaufhr %} + {% if not DOENKFONLY_ATM %} + {% for iaufhr in iaufhrs_str %} + {% set iaufhr = iaufhr %} - "{{ COMIN_ATMOS_ANALYSIS_MEM }}/{{ head }}recentered_increment.atm.i{{ iaufhr }}.nc" - {% endfor %} # iaufhr in iaufhrs_str + {% endfor %} # iaufhr in iaufhrs_str + {% endif %} {% endif %} {% endif %} diff --git a/parm/archive/enkf_restarta_grp.yaml.j2 b/parm/archive/enkf_restarta_grp.yaml.j2 index db7f2cf997d..7d00c38867f 100644 --- a/parm/archive/enkf_restarta_grp.yaml.j2 +++ b/parm/archive/enkf_restarta_grp.yaml.j2 @@ -11,7 +11,11 @@ enkf_restarta_grp: {% if DO_JEDIATMENS %} {% for iaufhr in iaufhrs_str %} {% for itile in range(6) %} + {% if DOENKFONLY_ATM %} + - "{{ COMIN_ATMOS_ANALYSIS_MEM }}/{{ head }}jedi_increment.atm.i{{ iaufhr }}.tile{{ itile+1 }}.nc" + {% else %} - "{{ COMIN_ATMOS_ANALYSIS_MEM }}/{{ head }}recentered_jedi_increment.atm.i{{ iaufhr }}.tile{{ itile+1 }}.nc" + {% endif %} {% endfor %} {% endfor %} {% else %} @@ -19,7 +23,9 @@ enkf_restarta_grp: {% if do_calc_increment %} - "{{ COMIN_ATMOS_ANALYSIS_MEM }}/{{ head }}analysis.atm.a{{ iaufhr }}.nc" {% else %} + {% if not DOENKFONLY_ATM %} - "{{ COMIN_ATMOS_ANALYSIS_MEM }}/{{ head }}recentered_increment.atm.i{{ iaufhr }}.nc" + {% endif %} {% endif %} {% endfor %} # iaufhr in iaufhrs_str {% endif %} diff --git a/parm/fetch/gfs_ATM_gdas-anl-bias.yaml.j2 b/parm/fetch/gfs_ATM_gdas-anl-bias.yaml.j2 new file mode 100644 index 00000000000..f2ddd8a09f6 --- /dev/null +++ b/parm/fetch/gfs_ATM_gdas-anl-bias.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: "{{ DATA }}" diff --git a/parm/stage/analysis.yaml.j2 b/parm/stage/analysis.yaml.j2 index ddb10b5ad72..92c63e47e86 100644 --- a/parm/stage/analysis.yaml.j2 +++ b/parm/stage/analysis.yaml.j2 @@ -61,6 +61,39 @@ analysis: - ["{{ ICSDIR }}/{{ COMOUT_ATMOS_ANALYSIS | relpath(ROTDIR) }}/{{ RUN }}.t{{ current_cycle_HH }}z.{{ ftype }}", "{{ COMOUT_ATMOS_ANALYSIS }}"] {% endif %} {% endfor %} + + {# -------------------------------------------------------------------- #} + {# JEDI Atmospheric Ensemble Data Assimilation #} + {# -------------------------------------------------------------------- #} + {% elif DO_JEDIATMENS %} + + {# Cubed Sphere Grid Configuration #} + + {% for itile in range(ntiles) %} + + {# Ensemble Members (member != -1) #} + {% if not DOENKFONLY_ATM %} + {% if DOIAU_ENKF %} + {% set ftypes = ["recentered_jedi_increment.atm.i003", "recentered_jedi_increment.atm.i006", "recentered_jedi_increment.atm.i009" ] %} + {% else %} + {% set ftypes = ["recentered_jedi_increment.atm.i006" ] %} + {% endif %} + {% else %} + {% if DOIAU_ENKF %} + {% set ftypes = ["jedi_increment.atm.i003", "jedi_increment.atm.i006", "jedi_increment.atm.i009" ] %} + {% else %} + {% set ftypes = ["jedi_increment.atm.i006" ] %} + {% endif %} + {% endif %} + + {% for ftype in ftypes %} + {% if path_exists(ICSDIR ~ "/" ~ COMOUT_ATMOS_ANALYSIS | relpath(ROTDIR) ~ "/" ~ RUN ~ ".t" ~ current_cycle_HH ~ "z." ~ ftype ~ ".tile" ~ (itile+1) ~ ".nc") %} + - ["{{ ICSDIR }}/{{ COMOUT_ATMOS_ANALYSIS | relpath(ROTDIR) }}/{{ RUN }}.t{{ current_cycle_HH }}z.{{ ftype }}.tile{{ itile+1 }}.nc", "{{ COMOUT_ATMOS_ANALYSIS }}"] + {% endif %} + {% endfor %} + + {% endfor %} + {# -------------------------------------------------------------------- #} {# GSI Data Assimilation (Non-JEDI) #} {# -------------------------------------------------------------------- #} diff --git a/sorc/gdas.cd b/sorc/gdas.cd index 8fa33c87860..2a31cf4fdd1 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit 8fa33c87860fa2a9913bcc9a8cfd44c28f46e4ec +Subproject commit 2a31cf4fdd1d50775755e27d02b87459d24c3a6d diff --git a/sorc/link_workflow.sh b/sorc/link_workflow.sh index 6a090304f49..caeec0344ac 100755 --- a/sorc/link_workflow.sh +++ b/sorc/link_workflow.sh @@ -457,6 +457,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/satbias2ioda.x" ./satbias2ioda.x cp -f "${HOMEgfs}/sorc/gdas.cd/install/bin/apply_incr.exe" ./gdas_apply_incr.x fi diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 2d6a4cb378c..bc635f4656e 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -195,18 +195,34 @@ 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") increment_file_on_native_grid=".true." - res_latlon_dynamics="jedi_increment.atm.i006" + if [[ "${DOENKFONLY_ATM:-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") + res_latlon_dynamics="jedi_increment.atm.i006" + else + 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") + 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." + 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." + else + increment_file_on_native_grid=".true." + if [[ "${DOENKFONLY_ATM:-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") + res_latlon_dynamics="jedi_increment.atm.i006" + else + 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") + res_latlon_dynamics="jedi_increment.atm.i006" + fi + fi fi if [[ "${USE_ATM_ENS_PERTURB_FILES:-NO}" == "YES" ]]; then # Control member has no perturbation @@ -219,7 +235,11 @@ EOF fi if [[ "${RUN}" == "enkfgfs" ]] || [[ "${RUN}" == "enkfgdas" ]]; then - prefix_atminc="recentered_" + if [[ "${DOENKFONLY_ATM:-NO}" == "YES" ]]; then + prefix_atminc="" + else + prefix_atminc="recentered_" + fi else prefix_atminc="" fi diff --git a/ush/python/pygfs/task/stage_ic.py b/ush/python/pygfs/task/stage_ic.py index f660fb7096d..e8bebb5af88 100644 --- a/ush/python/pygfs/task/stage_ic.py +++ b/ush/python/pygfs/task/stage_ic.py @@ -41,8 +41,8 @@ def _copy_base_config(self) -> Dict[str, Any]: base_keys = [ 'RUN', 'MODE', 'EXP_WARM_START', 'NMEM_ENS', 'assim_freq', 'current_cycle', 'previous_cycle', - 'ROTDIR', 'ICSDIR', 'STAGE_IC_YAML_TMPL', 'DO_JEDIATMVAR', - 'OCNRES', 'waveGRD', 'ntiles', 'DOIAU', 'ATMINC_GRID', + 'ROTDIR', 'ICSDIR', 'STAGE_IC_YAML_TMPL', 'DO_JEDIATMVAR', 'DO_JEDIATMENS', + 'OCNRES', 'waveGRD', 'ntiles', 'DOIAU', 'ATMINC_GRID', 'DOENKFONLY_ATM', 'DO_JEDIOCNVAR', 'DO_STARTMEM_FROM_JEDIICE', 'DO_WAVE', 'DO_OCN', 'DO_ICE', 'DO_NEST', 'DO_CA', 'DO_AERO_ANL', 'MOM6_INTERP_ICS', 'USE_ATM_ENS_PERTURB_FILES', 'USE_OCN_ENS_PERTURB_FILES', 'DO_GSISOILDA', 'DO_LAND_IAU' diff --git a/ush/python/pygfs/utils/archive_tar_vars.py b/ush/python/pygfs/utils/archive_tar_vars.py index b88a50878f3..1be2edafd2f 100644 --- a/ush/python/pygfs/utils/archive_tar_vars.py +++ b/ush/python/pygfs/utils/archive_tar_vars.py @@ -207,6 +207,7 @@ def add_config_vars(config_dict: AttrDict) -> AttrDict: 'ENSGRP', 'NMEM_EARCGRP', 'NMEM_ENS_GFS', # EnKF-specific operations 'DO_CALC_INCREMENT_ENKF_GFS', 'DO_JEDIATMENS', 'DO_JEDIATMENS_SPLIT_OBSSOL', 'DO_CALC_INCREMENT', + 'DOENKFONLY_ATM', # EnKF forecast configuration 'FHMIN_ENKF', 'FHMAX_ENKF_GFS', 'FHOUT_ENKF_GFS', 'FHMAX_ENKF', 'FHOUT_ENKF', # EnKF settings