diff --git a/.gitignore b/.gitignore index 04193fca0a..8314f5bae9 100644 --- a/.gitignore +++ b/.gitignore @@ -35,8 +35,10 @@ fix/gsi fix/lut fix/mom6 fix/orog +fix/orog_nest fix/sfc_climo fix/ugwd +fix/ugwd_nest fix/verif fix/wave diff --git a/.gitmodules b/.gitmodules index ea1b5c06af..1c3b7acfa5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,10 +26,6 @@ [submodule "sorc/gsi_monitor.fd"] path = sorc/gsi_monitor.fd url = https://github.com/NOAA-EMC/GSI-Monitor.git -[submodule "sorc/upp.fd"] - path = sorc/upp.fd - url = https://github.com/NOAA-EMC/UPP.git - ignore = dirty [submodule "sorc/jcb"] path = sorc/jcb url = https://github.com/noaa-emc/jcb diff --git a/ci/Jenkinsfile b/ci/Jenkinsfile index 317cb7d820..c6aa0887c7 100644 --- a/ci/Jenkinsfile +++ b/ci/Jenkinsfile @@ -76,7 +76,7 @@ pipeline { Machine = machine[0].toUpperCase() + machine.substring(1) echo "Getting Common Workspace for ${Machine}" ws("${custom_workspace[machine]}/${env.CHANGE_ID}") { - properties([parameters([[$class: 'NodeParameterDefinition', allowedSlaves: ['built-in', 'Hera-EMC', 'Orion-EMC'], defaultSlaves: ['built-in'], name: '', nodeEligibility: [$class: 'AllNodeEligibility'], triggerIfResult: 'allCases']])]) + properties([parameters([[$class: 'NodeParameterDefinition', allowedSlaves: ['built-in', 'Hercules-EMC', 'Hera-EMC', 'Orion-EMC'], defaultSlaves: ['built-in'], name: '', nodeEligibility: [$class: 'AllNodeEligibility'], triggerIfResult: 'allCases']])]) HOME = "${WORKSPACE}" sh(script: "mkdir -p ${HOME}/RUNTESTS;rm -Rf ${HOME}/RUNTESTS/*") sh(script: """${GH} pr edit ${env.CHANGE_ID} --repo ${repo_url} --add-label "CI-${Machine}-Building" --remove-label "CI-${Machine}-Ready" """) diff --git a/ci/scripts/driver.sh b/ci/scripts/driver.sh index ec7702251d..0f53ebff6f 100755 --- a/ci/scripts/driver.sh +++ b/ci/scripts/driver.sh @@ -228,7 +228,7 @@ for pr in ${pr_list}; do } >> "${output_ci}" continue fi - "${HOMEgfs}/workflow/create_experiment.py" --yaml "${HOMEgfs}/ci/cases/pr/${case}.yaml" > "${LOGFILE_PATH}" 2>&1 + "${HOMEgfs}/workflow/create_experiment.py" --yaml "${HOMEgfs}/ci/cases/pr/${case}.yaml" --overwrite > "${LOGFILE_PATH}" 2>&1 ci_status=$? set -e if [[ ${ci_status} -eq 0 ]]; then diff --git a/env/HERA.env b/env/HERA.env index ccaaea32e7..94bab36703 100755 --- a/env/HERA.env +++ b/env/HERA.env @@ -102,6 +102,13 @@ elif [[ "${step}" = "atmanlfv3inc" ]]; then [[ ${NTHREADS_ATMANLFV3INC} -gt ${nth_max} ]] && export NTHREADS_ATMANLFV3INC=${nth_max} export APRUN_ATMANLFV3INC="${launcher} -n ${npe_atmanlfv3inc} --cpus-per-task=${NTHREADS_ATMANLFV3INC}" +elif [[ "${step}" = "prepobsaero" ]]; then + + nth_max=$((npe_node_max / npe_node_prepobsaero)) + + export NTHREADS_PREPOBSAERO=${nth_prepobsaero:-1} + export APRUN_PREPOBSAERO="${launcher} -n ${npe_prepobsaero} --cpus-per-task=${NTHREADS_PREPOBSAERO}" + elif [[ "${step}" = "snowanl" ]]; then nth_max=$((npe_node_max / npe_node_snowanl)) @@ -316,7 +323,6 @@ elif [[ "${step}" = "gempak" ]]; then export NTHREADS_GEMPAK=${nth_gempak:-1} [[ ${NTHREADS_GEMPAK} -gt ${nth_max} ]] && export NTHREADS_GEMPAK=${nth_max} - elif [[ "${step}" = "fit2obs" ]]; then nth_max=$((npe_node_max / npe_node_fit2obs)) diff --git a/env/HERCULES.env b/env/HERCULES.env index 0824ba913a..d43dedad8d 100755 --- a/env/HERCULES.env +++ b/env/HERCULES.env @@ -99,6 +99,12 @@ case ${step} in [[ ${NTHREADS_AEROANL} -gt ${nth_max} ]] && export NTHREADS_AEROANL=${nth_max} export APRUN_AEROANL="${launcher} -n ${npe_aeroanlrun} --cpus-per-task=${NTHREADS_AEROANL}" ;; + "prepobsaero") + nth_max=$((npe_node_max / npe_node_prepobsaero)) + + export NTHREADS_PREPOBSAERO=${nth_prepobsaero:-1} + export APRUN_PREPOBSAERO="${launcher} -n ${npe_prepobsaero} --cpus-per-task=${NTHREADS_PREPOBSAERO}" +;; "snowanl") nth_max=$((npe_node_max / npe_node_snowanl)) diff --git a/env/JET.env b/env/JET.env index 5bd88dc93a..668ec1c2e4 100755 --- a/env/JET.env +++ b/env/JET.env @@ -82,6 +82,13 @@ elif [[ "${step}" = "aeroanlrun" ]]; then [[ ${NTHREADS_AEROANL} -gt ${nth_max} ]] && export NTHREADS_AEROANL=${nth_max} export APRUN_AEROANL="${launcher} -n ${npe_aeroanlrun}" +elif [[ "${step}" = "prepobsaero" ]]; then + + nth_max=$((npe_node_max / npe_node_prepobsaero)) + + export NTHREADS_PREPOBSAERO=${nth_prepobsaero:-1} + export APRUN_PREPOBSAERO="${launcher} -n ${npe_prepobsaero} --cpus-per-task=${NTHREADS_PREPOBSAERO}" + elif [[ "${step}" = "snowanl" ]]; then nth_max=$((npe_node_max / npe_node_snowanl)) diff --git a/env/ORION.env b/env/ORION.env index f701e55aa2..afd1cda052 100755 --- a/env/ORION.env +++ b/env/ORION.env @@ -90,6 +90,13 @@ elif [[ "${step}" = "aeroanlrun" ]]; then [[ ${NTHREADS_AEROANL} -gt ${nth_max} ]] && export NTHREADS_AEROANL=${nth_max} export APRUN_AEROANL="${launcher} -n ${npe_aeroanlrun} --cpus-per-task=${NTHREADS_AEROANL}" +elif [[ "${step}" = "prepobsaero" ]]; then + + nth_max=$((npe_node_max / npe_node_prepobsaero)) + + export NTHREADS_PREPOBSAERO=${nth_prepobsaero:-1} + export APRUN_PREPOBSAERO="${launcher} -n ${npe_prepobsaero} --cpus-per-task=${NTHREADS_PREPOBSAERO}" + elif [[ "${step}" = "snowanl" ]]; then nth_max=$((npe_node_max / npe_node_snowanl)) diff --git a/env/S4.env b/env/S4.env index 9ba3a61b01..8a368bf1d6 100755 --- a/env/S4.env +++ b/env/S4.env @@ -82,6 +82,13 @@ elif [[ "${step}" = "aeroanlrun" ]]; then [[ ${NTHREADS_AEROANL} -gt ${nth_max} ]] && export NTHREADS_AEROANL=${nth_max} export APRUN_AEROANL="${launcher} -n ${npe_aeroanlrun}" +elif [[ "${step}" = "prepobsaero" ]]; then + + nth_max=$((npe_node_max / npe_node_prepobsaero)) + + export NTHREADS_PREPOBSAERO=${nth_prepobsaero:-1} + export APRUN_PREPOBSAERO="${launcher} -n ${npe_prepobsaero} --cpus-per-task=${NTHREADS_PREPOBSAERO}" + elif [[ "${step}" = "snowanl" ]]; then nth_max=$((npe_node_max / npe_node_snowanl)) diff --git a/env/WCOSS2.env b/env/WCOSS2.env index 0876e4127d..9fe9179e6b 100755 --- a/env/WCOSS2.env +++ b/env/WCOSS2.env @@ -76,6 +76,13 @@ elif [[ "${step}" = "aeroanlrun" ]]; then [[ ${NTHREADS_AEROANL} -gt ${nth_max} ]] && export NTHREADS_AEROANL=${nth_max} export APRUN_AEROANL="${launcher} -n ${npe_aeroanlrun}" +elif [[ "${step}" = "prepobsaero" ]]; then + + nth_max=$((npe_node_max / npe_node_prepaeroobs)) + + export NTHREADS_PREPOBSAERO=${nth_prepobsaero:-1} + export APRUN_PREPOBSAERO="${launcher} -n ${npe_prepobsaero} --ppn ${npe_node_prepobsaero}--cpu-bind depth --depth=${NTHREADS_PREPOBSAERO}" + elif [[ "${step}" = "snowanl" ]]; then nth_max=$((npe_node_max / npe_node_snowanl)) diff --git a/jobs/JGLOBAL_PREP_OBS_AERO b/jobs/JGLOBAL_PREP_OBS_AERO new file mode 100755 index 0000000000..7fe701898f --- /dev/null +++ b/jobs/JGLOBAL_PREP_OBS_AERO @@ -0,0 +1,43 @@ +#! /usr/bin/env bash + +source "${HOMEgfs}/ush/preamble.sh" +source "${HOMEgfs}/ush/jjob_header.sh" -e "prepobsaero" -c "base prepobsaero" + +############################################## +# Set variables used in the script +############################################## + +export COMIN_OBS="${DATA}" +YMD=${PDY} HH=${cyc} declare_from_tmpl -rx COMOUT_OBS:COM_OBS_TMPL + +############################################## +# Begin JOB SPECIFIC work +############################################## + +############################################################### +# Run relevant script + +EXSCRIPT=${GDASPREPAEROOBSPY:-${SCRgfs}/exglobal_prep_obs_aero.py} +${EXSCRIPT} +status=$? +[[ ${status} -ne 0 ]] && exit "${status}" + + +############################################## +# End JOB SPECIFIC work +############################################## + +############################################## +# Final processing +############################################## +if [[ -e "${pgmout}" ]] ; then + cat "${pgmout}" +fi + +########################################## +# Remove the Temporary working directory +########################################## +cd "${DATAROOT}" || exit +[[ "${KEEPDATA}" = "NO" ]] && rm -rf "${DATA}" + +exit 0 diff --git a/jobs/rocoto/prepobsaero.sh b/jobs/rocoto/prepobsaero.sh new file mode 100755 index 0000000000..89da7547e8 --- /dev/null +++ b/jobs/rocoto/prepobsaero.sh @@ -0,0 +1,24 @@ +#! /usr/bin/env bash + +source "${HOMEgfs}/ush/preamble.sh" + +############################################################### +# Source UFSDA workflow modules +. "${HOMEgfs}/ush/load_ufsda_modules.sh" +status=$? +[[ ${status} -ne 0 ]] && exit "${status}" + +export job="prepobsaero" +export jobid="${job}.$$" + +############################################################### +# setup python path for workflow utilities and tasks +wxflowPATH="${HOMEgfs}/ush/python:${HOMEgfs}/ush/python/wxflow/src" +PYTHONPATH="${PYTHONPATH:+${PYTHONPATH}:}${wxflowPATH}" +export PYTHONPATH + +############################################################### +# Execute the JJOB +"${HOMEgfs}/jobs/JGLOBAL_PREP_OBS_AERO" +status=$? +exit "${status}" diff --git a/parm/archive/arcdir.yaml.j2 b/parm/archive/arcdir.yaml.j2 index fab93cc2a4..1ed7422761 100644 --- a/parm/archive/arcdir.yaml.j2 +++ b/parm/archive/arcdir.yaml.j2 @@ -47,6 +47,11 @@ Deterministic: &deterministic - ["{{ COM_CHEM_ANALYSIS }}/{{ head }}aerostat", "{{ ARCDIR }}/aerostat.{{ RUN }}.{{ cycle_YMDH }}"] {% endif %} + {% if DO_PREP_OBS_AERO %} + - ["{{ COM_OBS }}/{{ head }}aeroobs", "{{ ARCDIR }}/aeroobs.{{ RUN }}.{{ cycle_YMDH }}"] + - ["{{ COM_OBS }}/{{ head }}aerorawobs", "{{ ARCDIR }}/aerorawobs.{{ RUN }}.{{ cycle_YMDH }}"] + {% endif %} + {% endif %} {% if RUN == "gfs" %} diff --git a/parm/archive/enkf.yaml.j2 b/parm/archive/enkf.yaml.j2 index e05aca2981..ed50a1749d 100644 --- a/parm/archive/enkf.yaml.j2 +++ b/parm/archive/enkf.yaml.j2 @@ -16,7 +16,7 @@ enkf: {% endfor %} {% if DO_JEDIATMENS %} - {% set steps = ["atmensanlinit", "atmensanlrun", "atmensanlfinal"] %} + {% set steps = ["atmensanlinit", "atmensanlletkf", "atmensanlfv3inc", "atmensanlfinal"] %} {% else %} {% set steps = ["eobs", "eupd"] %} {% if lobsdiag_forenkf %} diff --git a/parm/archive/gdas.yaml.j2 b/parm/archive/gdas.yaml.j2 index fd5e074111..26540156cd 100644 --- a/parm/archive/gdas.yaml.j2 +++ b/parm/archive/gdas.yaml.j2 @@ -69,6 +69,10 @@ gdas: {% if AERO_ANL_CDUMP == "gdas" or AERO_ANL_CDUMP == "both" %} - "{{ COM_CHEM_ANALYSIS | relpath(ROTDIR) }}/{{ head }}aerostat" {% endif %} + {% if DO_PREP_OBS_AERO %} + - "{{ COM_OBS | relpath(ROTDIR) }}/{{ head }}aeroobs" + - "{{ COM_OBS | relpath(ROTDIR) }}/{{ head }}aerorawobs" + {% endif %} {% if DO_JEDISNOWDA %} - "{{ COM_SNOW_ANALYSIS | relpath(ROTDIR) }}/{{ head }}snowstat.tgz" {% endif %} diff --git a/parm/archive/gdasice.yaml.j2 b/parm/archive/gdasice.yaml.j2 index 4cfa1eb9af..23337a8856 100644 --- a/parm/archive/gdasice.yaml.j2 +++ b/parm/archive/gdasice.yaml.j2 @@ -4,7 +4,7 @@ gdasice: target: "{{ ATARDIR }}/{{ cycle_YMDH }}/gdasice.tar" required: - "{{ COM_ICE_HISTORY | relpath(ROTDIR) }}/{{ head }}ic.nc" - {% for fhr in range(FHOUT_OCNICE, FHMAX+1, FHOUT_OCNICE) %} + {% for fhr in range(FHOUT_ICE, FHMAX+1, FHOUT_ICE) %} - "{{ COM_ICE_HISTORY | relpath(ROTDIR) }}/{{ head }}inst.f{{ '%03d' % fhr }}.nc" {% endfor %} - '{{ COM_CONF | relpath(ROTDIR) }}/ufs.ice_in' diff --git a/parm/archive/gdasocean.yaml.j2 b/parm/archive/gdasocean.yaml.j2 index 9791709319..4e92bba1a0 100644 --- a/parm/archive/gdasocean.yaml.j2 +++ b/parm/archive/gdasocean.yaml.j2 @@ -3,7 +3,7 @@ gdasocean: name: "GDASOCEAN" target: "{{ ATARDIR }}/{{ cycle_YMDH }}/gdasocean.tar" required: - {% for fhr in range(FHMIN, FHMAX + 1, FHOUT_OCNICE) %} + {% for fhr in range(FHMIN, FHMAX + 1, FHOUT_OCN) %} - "{{ COM_OCEAN_HISTORY | relpath(ROTDIR) }}/{{ head }}inst.f{{ '%03d' % fhr }}.nc" {% endfor %} - '{{ COM_CONF | relpath(ROTDIR) }}/ufs.MOM_input' diff --git a/parm/archive/gfsa.yaml.j2 b/parm/archive/gfsa.yaml.j2 index df90a1a71e..0a8e65d3ef 100644 --- a/parm/archive/gfsa.yaml.j2 +++ b/parm/archive/gfsa.yaml.j2 @@ -40,6 +40,10 @@ gfsa: {% if AERO_ANL_CDUMP == "gfs" or AERO_ANL_CDUMP == "both" %} - "{{ COM_CHEM_ANALYSIS | relpath(ROTDIR) }}/{{ head }}aerostat" {% endif %} + {% if DO_PREP_OBS_AERO %} + - "{{ COM_OBS | relpath(ROTDIR) }}/{{ head }}aeroobs" + - "{{ COM_OBS | relpath(ROTDIR) }}/{{ head }}aerorawobs" + {% endif %} # BUFR inputs - "{{ COM_OBS | relpath(ROTDIR) }}/{{ head }}nsstbufr" diff --git a/parm/archive/ice_grib2.yaml.j2 b/parm/archive/ice_grib2.yaml.j2 index 83e0a30085..9d52f174ab 100644 --- a/parm/archive/ice_grib2.yaml.j2 +++ b/parm/archive/ice_grib2.yaml.j2 @@ -4,7 +4,7 @@ ice_grib2: target: "{{ ATARDIR }}/{{ cycle_YMDH }}/ice_grib2.tar" required: # Ice forecast GRIB2 products - {% for fhr in range(FHOUT_OCNICE_GFS, FHMAX_GFS + FHOUT_OCNICE_GFS, FHOUT_OCNICE_GFS) %} + {% for fhr in range(FHOUT_ICE_GFS, FHMAX_GFS + FHOUT_ICE_GFS, FHOUT_ICE_GFS) %} {% set fhr3 = '%03d' % fhr %} {% if ICERES == 500 %} - "{{ COM_ICE_GRIB | relpath(ROTDIR) }}/5p00/{{ head }}5p00.f{{ fhr3 }}.grib2" diff --git a/parm/archive/master_gfs.yaml.j2 b/parm/archive/master_gfs.yaml.j2 index e96def7a03..67cde482a2 100644 --- a/parm/archive/master_gfs.yaml.j2 +++ b/parm/archive/master_gfs.yaml.j2 @@ -56,7 +56,6 @@ datasets: # Ocean forecasts {% filter indent(width=4) %} {% include "ocean_6hravg.yaml.j2" %} -{% include "ocean_daily.yaml.j2" %} {% include "ocean_grib2.yaml.j2" %} {% include "gfs_flux_1p00.yaml.j2" %} {% endfilter %} diff --git a/parm/archive/ocean_daily.yaml.j2 b/parm/archive/ocean_daily.yaml.j2 deleted file mode 100644 index 0f45264973..0000000000 --- a/parm/archive/ocean_daily.yaml.j2 +++ /dev/null @@ -1,8 +0,0 @@ -ocean_daily: - {% set head = "gfs.ocean.t" + cycle_HH + "z." %} - name: "OCEAN_DAILY" - target: "{{ ATARDIR }}/{{ cycle_YMDH }}/ocean_daily.tar" - required: - {% for fhr in range(24, FHMAX_GFS + 24, 24) %} - - "{{ COM_OCEAN_HISTORY | relpath(ROTDIR) }}/{{ head }}daily.f{{ '%03d' % fhr }}.nc" - {% endfor %} diff --git a/parm/archive/ocean_grib2.yaml.j2 b/parm/archive/ocean_grib2.yaml.j2 index 2e63c0ca98..784e30021d 100644 --- a/parm/archive/ocean_grib2.yaml.j2 +++ b/parm/archive/ocean_grib2.yaml.j2 @@ -3,7 +3,7 @@ ocean_grib2: name: "OCEAN_GRIB2" target: "{{ ATARDIR }}/{{ cycle_YMDH }}/ocean_grib2.tar" required: - {% for fhr in range(FHOUT_OCNICE_GFS, FHMAX_GFS + FHOUT_OCNICE_GFS, FHOUT_OCNICE_GFS) %} + {% for fhr in range(FHOUT_OCN_GFS, FHMAX_GFS + FHOUT_OCN_GFS, FHOUT_OCN_GFS) %} {% set fhr3 = '%03d' % fhr %} {% if OCNRES == 500 %} - "{{ COM_OCEAN_GRIB | relpath(ROTDIR) }}/5p00/{{ head }}5p00.f{{ fhr3 }}.grib2" diff --git a/parm/config/gefs/config.base b/parm/config/gefs/config.base index a7687651d6..29755e41b0 100644 --- a/parm/config/gefs/config.base +++ b/parm/config/gefs/config.base @@ -30,6 +30,8 @@ export FIXgfs=${HOMEgfs}/fix export PARMgfs=${HOMEgfs}/parm export SCRgfs=${HOMEgfs}/scripts export USHgfs=${HOMEgfs}/ush +export FIXorog=${FIXgfs}/orog +export FIXugwd=${FIXgfs}/ugwd ######################################################################## @@ -221,6 +223,13 @@ case "${APP}" in ;; esac +# Output frequency of the forecast model (for cycling) +export FHMIN=0 +export FHMAX=9 +export FHOUT=3 # Will be changed to 1 in config.base if (DOHYBVAR set to NO and l4densvar set to false) +export FHOUT_OCN=3 +export FHOUT_ICE=3 + # GFS cycle info export gfs_cyc=@gfs_cyc@ # 0: no GFS cycle, 1: 00Z only, 2: 00Z and 12Z only, 4: all 4 cycles. @@ -231,7 +240,8 @@ export FHMAX_GFS=@FHMAX_GFS@ export FHOUT_GFS=6 export FHMAX_HF_GFS=0 export FHOUT_HF_GFS=1 -export FHOUT_OCNICE_GFS=6 +export FHOUT_OCN_GFS=6 +export FHOUT_ICE_GFS=6 export FHMIN_WAV=0 export FHOUT_WAV=3 export FHMAX_HF_WAV=120 @@ -285,12 +295,17 @@ export MEMDIR="mem${ENSMEM}" # initialize ocean ensemble members with perturbations # if true, only occurs for members greater than zero -export USE_OCN_PERTURB_FILES=@USE_OCN_PERTURB_FILES@ +export REPLAY_ICS=@REPLAY_ICS@ +if [[ "${REPLAY_ICS:-NO}" == "YES" ]]; then + export OFFSET_START_HOUR=$(( assim_freq / 2 )) +else + export OFFSET_START_HOUR=0 +fi export DOIAU="NO" # While we are not doing IAU, we may want to warm start w/ IAU in the future # Check if cycle is cold starting if [[ "${EXP_WARM_START}" = ".false." ]]; then - export IAU_FHROT=0 + export IAU_FHROT=${OFFSET_START_HOUR} else if [[ "${DOIAU}" = "YES" ]]; then export IAU_FHROT=3 diff --git a/parm/config/gefs/config.efcs b/parm/config/gefs/config.efcs index 915726b974..807ed66d48 100644 --- a/parm/config/gefs/config.efcs +++ b/parm/config/gefs/config.efcs @@ -67,7 +67,7 @@ export EPBL="0.8,0.4,0.2,0.08,0.04" export EPBL_TAU="2.16E4,2.592E5,2.592E6,7.776E6,3.1536E7" export EPBL_LSCALE="500.E3,1000.E3,2000.E3,2000.E3,2000.E3" -if [[ "${USE_OCN_PERTURB_FILES:-false}" == "true" ]]; then +if [[ "${REPLAY_ICS:-NO}" == "YES" ]]; then export ODA_INCUPD="True" export ODA_TEMPINC_VAR='t_pert' export ODA_SALTINC_VAR='s_pert' diff --git a/parm/config/gefs/config.fcst b/parm/config/gefs/config.fcst index 12e461cef8..103d6f091d 100644 --- a/parm/config/gefs/config.fcst +++ b/parm/config/gefs/config.fcst @@ -36,7 +36,8 @@ export FHMAX=${FHMAX_GFS} export FHOUT=${FHOUT_GFS} export FHMAX_HF=${FHMAX_HF_GFS} export FHOUT_HF=${FHOUT_HF_GFS} -export FHOUT_OCNICE=${FHOUT_OCNICE_GFS} +export FHOUT_OCN=${FHOUT_OCN_GFS} +export FHOUT_ICE=${FHOUT_ICE_GFS} # Get task specific resources source "${EXPDIR}/config.resources" fcst @@ -255,6 +256,9 @@ else export io_layout="1,1" fi +if (( OFFSET_START_HOUR != 0 )); then + export reforecast="YES" +fi # Remember config.efcs will over-ride these values for ensemble forecasts # if these variables are re-defined there. # Otherwise, the ensemble forecast will inherit from config.fcst diff --git a/parm/config/gefs/config.oceanice_products b/parm/config/gefs/config.oceanice_products deleted file mode 120000 index f6cf9cd60b..0000000000 --- a/parm/config/gefs/config.oceanice_products +++ /dev/null @@ -1 +0,0 @@ -../gfs/config.oceanice_products \ No newline at end of file diff --git a/parm/config/gefs/config.oceanice_products b/parm/config/gefs/config.oceanice_products new file mode 100644 index 0000000000..3b8b064947 --- /dev/null +++ b/parm/config/gefs/config.oceanice_products @@ -0,0 +1,15 @@ +#! /usr/bin/env bash + +########## config.oceanice_products ########## + +echo "BEGIN: config.oceanice_products" + +# Get task specific resources +source "${EXPDIR}/config.resources" oceanice_products + +export OCEANICEPRODUCTS_CONFIG="${PARMgfs}/post/oceanice_products_gefs.yaml" + +# No. of forecast hours to process in a single job +export NFHRS_PER_GROUP=3 + +echo "END: config.oceanice_products" diff --git a/parm/config/gefs/config.stage_ic b/parm/config/gefs/config.stage_ic index e0c4c77dc9..ac3903b731 100644 --- a/parm/config/gefs/config.stage_ic +++ b/parm/config/gefs/config.stage_ic @@ -13,12 +13,21 @@ case "${CASE}" in export CPL_ICEIC="" export CPL_OCNIC="" export CPL_WAVIC="" + export CPL_MEDIC="" + ;; + "C96") + export CPL_ATMIC="" + export CPL_ICEIC="" + export CPL_OCNIC="" + export CPL_WAVIC="" + export CPL_MEDIC="" ;; "C48") export CPL_ATMIC="gefs_test" export CPL_ICEIC="gefs_test" export CPL_OCNIC="gefs_test" export CPL_WAVIC="gefs_test" + export CPL_MEDIC="gefs_test" ;; *) echo "FATAL ERROR Unrecognized resolution: ${CASE}" diff --git a/parm/config/gefs/config.ufs b/parm/config/gefs/config.ufs index 9c39bf06de..8beb0652f7 100644 --- a/parm/config/gefs/config.ufs +++ b/parm/config/gefs/config.ufs @@ -324,7 +324,7 @@ if [[ "${skip_mom6}" == "false" ]]; then MOM6_RESTART_SETTING='r' MOM6_RIVER_RUNOFF='False' eps_imesh="2.5e-1" - TOPOEDITS="ufs.topo_edits_011818.nc" + TOPOEDITS="topo_edits_011818.nc" if [[ "${DO_JEDIOCNVAR:-NO}" = "YES" ]]; then MOM6_DIAG_COORD_DEF_Z_FILE="oceanda_zgrid_75L.nc" MOM6_DIAG_MISVAL="0.0" diff --git a/parm/config/gefs/yaml/defaults.yaml b/parm/config/gefs/yaml/defaults.yaml index 5c763ad29e..2341c35d05 100644 --- a/parm/config/gefs/yaml/defaults.yaml +++ b/parm/config/gefs/yaml/defaults.yaml @@ -9,5 +9,5 @@ base: DO_AWIPS: "NO" KEEPDATA: "NO" FHMAX_GFS: 120 - USE_OCN_PERTURB_FILES: "false" + REPLAY_ICS: "NO" diff --git a/parm/config/gfs/config.base b/parm/config/gfs/config.base index e61e261864..d32ec509f7 100644 --- a/parm/config/gfs/config.base +++ b/parm/config/gfs/config.base @@ -35,11 +35,9 @@ export FIXam="${FIXgfs}/am" export FIXaer="${FIXgfs}/aer" export FIXcpl="${FIXgfs}/cpl" export FIXlut="${FIXgfs}/lut" -export FIXorog="${FIXgfs}/orog" export FIXcice="${FIXgfs}/cice" export FIXmom="${FIXgfs}/mom6" export FIXreg2grb2="${FIXgfs}/reg2grb2" -export FIXugwd="${FIXgfs}/ugwd" export FIXgdas="${FIXgfs}/gdas" ######################################################################## @@ -181,6 +179,7 @@ export DO_WAVE="NO" export DO_OCN="NO" export DO_ICE="NO" export DO_AERO="NO" +export DO_PREP_OBS_AERO="NO" export AERO_FCST_CDUMP="" # When to run aerosol forecast: gdas, gfs, or both export AERO_ANL_CDUMP="" # When to run aerosol analysis: gdas, gfs, or both export WAVE_CDUMP="" # When to include wave suite: gdas, gfs, or both @@ -191,8 +190,12 @@ export DO_NEST="NO" # Whether to run a global-nested domain if [[ "${DO_NEST:-NO}" == "YES" ]] ; then export ntiles=7 export NEST_OUTPUT_GRID="regional_latlon" + export FIXugwd="${FIXgfs}/ugwd_nest" + export FIXorog="${FIXgfs}/orog_nest" else export ntiles=6 + export FIXugwd="${FIXgfs}/ugwd" + export FIXorog="${FIXgfs}/orog" fi # Set operational resolution @@ -277,7 +280,8 @@ fi export FHMIN=0 export FHMAX=9 export FHOUT=3 # Will be changed to 1 in config.base if (DOHYBVAR set to NO and l4densvar set to false) -export FHOUT_OCNICE=3 +export FHOUT_OCN=3 +export FHOUT_ICE=3 # Cycle to run EnKF (set to BOTH for both gfs and gdas) export EUPD_CYC="@EUPD_CYC@" @@ -291,7 +295,8 @@ export FHMAX_GFS=@FHMAX_GFS@ export FHOUT_GFS=3 # Must be 6 for S2S until #1629 is addressed; 3 for ops export FHMAX_HF_GFS=0 export FHOUT_HF_GFS=1 -export FHOUT_OCNICE_GFS=6 +export FHOUT_OCN_GFS=6 +export FHOUT_ICE_GFS=6 export FHMIN_WAV=0 export FHOUT_WAV=3 export FHMAX_HF_WAV=120 @@ -471,6 +476,10 @@ if [[ ${DO_JEDIATMVAR} = "YES" ]]; then export DO_VMINMON="NO" # GSI minimization monitoring fi +# If starting ICs that are not at cycle hour +export REPLAY_ICS="NO" +export OFFSET_START_HOUR=0 + # Number of regional collectives to create soundings for export NUM_SND_COLLECTIVES=${NUM_SND_COLLECTIVES:-9} diff --git a/parm/config/gfs/config.com b/parm/config/gfs/config.com index 004ca1affb..ec867e64ba 100644 --- a/parm/config/gfs/config.com +++ b/parm/config/gfs/config.com @@ -49,6 +49,8 @@ COM_BASE='${ROTDIR}/${RUN}.${YMD}/${HH}/${MEMDIR}' declare -rx COM_TOP_TMPL='${ROTDIR}/${RUN}.${YMD}/${HH}' declare -rx COM_CONF_TMPL=${COM_BASE}'/conf' +declare -rx COM_OBS_JEDI=${COM_BASE}'/obs_jedi' + declare -rx COM_ATMOS_INPUT_TMPL=${COM_BASE}'/model_data/atmos/input' declare -rx COM_ATMOS_RESTART_TMPL=${COM_BASE}'/model_data/atmos/restart' declare -rx COM_ATMOS_ANALYSIS_TMPL=${COM_BASE}'/analysis/atmos' diff --git a/parm/config/gfs/config.fcst b/parm/config/gfs/config.fcst index f45874a31a..36064d5f2b 100644 --- a/parm/config/gfs/config.fcst +++ b/parm/config/gfs/config.fcst @@ -39,7 +39,8 @@ case ${RUN} in export FHOUT=${FHOUT_GFS} export FHMAX_HF=${FHMAX_HF_GFS} export FHOUT_HF=${FHOUT_HF_GFS} - export FHOUT_OCNICE=${FHOUT_OCNICE_GFS} + export FHOUT_OCN=${FHOUT_OCN_GFS} + export FHOUT_ICE=${FHOUT_ICE_GFS} ;; *gdas) export FHMAX_HF=0 diff --git a/parm/config/gfs/config.prepobsaero b/parm/config/gfs/config.prepobsaero new file mode 100644 index 0000000000..f70138991c --- /dev/null +++ b/parm/config/gfs/config.prepobsaero @@ -0,0 +1,17 @@ +#!/bin/bash -x + +########## config.prepobsaero ########## +# Prepare and thin/superob aerosol observations + +echo "BEGIN: config.prepobsaero" + +# Get task specific resources +source "${EXPDIR}/config.resources" prepobsaero + +export OBSPROCYAML="${PARMgfs}/gdas/aero/obs/lists/gdas_aero_obsproc.yaml.j2" +export OBSPROCEXE="${EXECgfs}/gdas_obsprovider2ioda.x" +export VIIRS_DATA_DIR="/scratch2/NCEPDEV/stmp3/Yaping.Wang/VIIRS/AWS/" +export SENSORS="npp,n20" + + +echo "END: config.prepaeroobs" diff --git a/parm/config/gfs/config.resources b/parm/config/gfs/config.resources index 0972f74f9c..1d1fd2e3c1 100644 --- a/parm/config/gfs/config.resources +++ b/parm/config/gfs/config.resources @@ -13,7 +13,7 @@ if (( $# != 1 )); then echo "atmanlinit atmanlvar atmanlfv3inc atmanlfinal" echo "atmensanlinit atmensanlletkf atmensanlfv3inc atmensanlfinal" echo "snowanl" - echo "aeroanlinit aeroanlrun aeroanlfinal" + echo "prepobsaero aeroanlinit aeroanlrun aeroanlfinal" echo "anal sfcanl analcalc analdiag fcst echgres" echo "upp atmos_products" echo "tracker genesis genesis_fsu" @@ -289,6 +289,14 @@ case ${step} in export npe_node_snowanl=$(( npe_node_max / nth_snowanl )) ;; + "prepobsaero") + export wtime_prepobsaero="00:30:00" + export npe_prepobsaero=1 + export nth_prepobsaero=1 + export npe_node_prepobsaero=1 + export memory_prepobsaero="96GB" + ;; + "aeroanlinit") # below lines are for creating JEDI YAML case ${CASE} in diff --git a/parm/post/oceanice_products_gefs.yaml b/parm/post/oceanice_products_gefs.yaml new file mode 100644 index 0000000000..74c0f0653b --- /dev/null +++ b/parm/post/oceanice_products_gefs.yaml @@ -0,0 +1,73 @@ +ocnicepost: + executable: "ocnicepost.x" + namelist: + debug: False + fix_data: + mkdir: + - "{{ DATA }}" + copy: + - ["{{ EXECgfs }}/ocnicepost.x", "{{ DATA }}/"] + - ["{{ PARMgfs }}/post/ocnicepost.nml.jinja2", "{{ DATA }}/"] + - ["{{ PARMgfs }}/post/{{ component }}.csv", "{{ DATA }}/"] + - ["{{ FIXgfs }}/mom6/post/{{ model_grid }}/tripole.{{ model_grid }}.Bu.to.Ct.bilinear.nc", "{{ DATA }}/"] + - ["{{ FIXgfs }}/mom6/post/{{ model_grid }}/tripole.{{ model_grid }}.Cu.to.Ct.bilinear.nc", "{{ DATA }}/"] + - ["{{ FIXgfs }}/mom6/post/{{ model_grid }}/tripole.{{ model_grid }}.Cv.to.Ct.bilinear.nc", "{{ DATA }}/"] + {% for grid in product_grids %} + - ["{{ FIXgfs }}/mom6/post/{{ model_grid }}/tripole.{{ model_grid }}.Ct.to.rect.{{ grid }}.bilinear.nc", "{{ DATA }}/"] + - ["{{ FIXgfs }}/mom6/post/{{ model_grid }}/tripole.{{ model_grid }}.Ct.to.rect.{{ grid }}.conserve.nc", "{{ DATA }}/"] + - ["{{ FIXgfs }}/mom6/post/template.global.{{ grid }}.gb2", "{{ DATA }}/"] + {% endfor %} + +nc2grib2: + script: "{{ USHgfs }}/oceanice_nc2grib2.sh" + +ocean: + namelist: + ftype: "ocean" + maskvar: "temp" + sinvar: "sin_rot" + cosvar: "cos_rot" + angvar: "" + {% if model_grid == 'mx025' or model_grid == 'mx050' or model_grid == 'mx100' %} + ocean_levels: [5, 15, 25, 35, 45, 55, 65, 75, 85, 95, 105, 115, 125, 135, 145, 155, 165, 175, 185, 195, 205, 215, 226, 241, 267, 309, 374, 467, 594, 757, 960, 1204, 1490, 1817, 2184, 2587, 3024, 3489, 3977, 4481] + {% elif model_grid == 'mx500' %} + ocean_levels: [5, 15, 25, 35, 45, 55, 65, 75, 85, 95, 105, 115, 125, 135, 145, 155, 165, 175, 185, 195, 205, 215, 226, 241, 267] + {% endif %} + subset: ['SSH', 'SST', 'SSS', 'speed', 'MLD_003', 'latent', 'sensible', 'SW', 'LW', 'LwLatSens', 'Heat_PmE', 'SSU', 'SSV', 'taux', 'tauy', 'temp', 'so', 'uo', 'vo'] + data_in: + copy: + - ["{{ COM_OCEAN_HISTORY }}/{{ RUN }}.ocean.t{{ current_cycle | strftime('%H') }}z.{{ interval }}hr_avg.f{{ '%03d' % forecast_hour }}.nc", "{{ DATA }}/ocean.nc"] + data_out: + mkdir: + - "{{ COM_OCEAN_NETCDF }}" + {% for grid in product_grids %} + - "{{ COM_OCEAN_GRIB }}/{{ grid }}" + {% endfor %} + copy: + - ["{{ DATA }}/ocean_subset.nc", "{{ COM_OCEAN_NETCDF }}/{{ RUN }}.ocean.t{{ current_cycle | strftime('%H') }}z.native.f{{ '%03d' % forecast_hour }}.nc"] + {% for grid in product_grids %} + - ["{{ DATA }}/ocean.{{ grid }}.nc", "{{ COM_OCEAN_NETCDF }}/{{ RUN }}.ocean.t{{ current_cycle | strftime('%H') }}z.{{ grid }}.f{{ '%03d' % forecast_hour }}.nc"] + {% endfor %} + +ice: + namelist: + ftype: "ice" + maskvar: "tmask" + sinvar: "" + cosvar: "" + angvar: "ANGLET" + subset: ['hi_h', 'hs_h', 'aice_h', 'Tsfc_h', 'uvel_h', 'vvel_h', 'frzmlt_h', 'albsni_h', 'mlt_onset_h', 'frz_onset_h'] + data_in: + copy: + - ["{{ COM_ICE_HISTORY }}/{{ RUN }}.ice.t{{ current_cycle | strftime('%H') }}z.{{ interval }}hr_avg.f{{ '%03d' % forecast_hour }}.nc", "{{ DATA }}/ice.nc"] + data_out: + mkdir: + - "{{ COM_ICE_NETCDF }}" + {% for grid in product_grids %} + - "{{ COM_ICE_GRIB }}/{{ grid }}" + {% endfor %} + copy: + - ["{{ DATA }}/ice_subset.nc", "{{ COM_ICE_NETCDF }}/{{ RUN }}.ice.t{{ current_cycle | strftime('%H') }}z.native.f{{ '%03d' % forecast_hour }}.nc"] + {% for grid in product_grids %} + - ["{{ DATA }}/ice.{{ grid }}.nc", "{{ COM_ICE_NETCDF }}/{{ RUN }}.ice.t{{ current_cycle | strftime('%H') }}z.{{ grid }}.f{{ '%03d' % forecast_hour }}.nc"] + {% endfor %} diff --git a/parm/ufs/fix/gfs/atmos.fixed_files.yaml b/parm/ufs/fix/gfs/atmos.fixed_files.yaml index 8db691b49c..374c26873e 100644 --- a/parm/ufs/fix/gfs/atmos.fixed_files.yaml +++ b/parm/ufs/fix/gfs/atmos.fixed_files.yaml @@ -1,31 +1,31 @@ copy: # Atmosphere mosaic file linked as the grid_spec file (atm only) - - [$(FIXgfs)/orog/$(CASE)/$(CASE)_mosaic.nc, $(DATA)/INPUT/grid_spec.nc] + - [$(FIXorog)/$(CASE)/$(CASE)_mosaic.nc, $(DATA)/INPUT/grid_spec.nc] # Atmosphere grid tile files - - [$(FIXgfs)/orog/$(CASE)/$(CASE)_grid.tile1.nc, $(DATA)/INPUT/] - - [$(FIXgfs)/orog/$(CASE)/$(CASE)_grid.tile2.nc, $(DATA)/INPUT/] - - [$(FIXgfs)/orog/$(CASE)/$(CASE)_grid.tile3.nc, $(DATA)/INPUT/] - - [$(FIXgfs)/orog/$(CASE)/$(CASE)_grid.tile4.nc, $(DATA)/INPUT/] - - [$(FIXgfs)/orog/$(CASE)/$(CASE)_grid.tile5.nc, $(DATA)/INPUT/] - - [$(FIXgfs)/orog/$(CASE)/$(CASE)_grid.tile6.nc, $(DATA)/INPUT/] + - [$(FIXorog)/$(CASE)/$(CASE)_grid.tile1.nc, $(DATA)/INPUT/] + - [$(FIXorog)/$(CASE)/$(CASE)_grid.tile2.nc, $(DATA)/INPUT/] + - [$(FIXorog)/$(CASE)/$(CASE)_grid.tile3.nc, $(DATA)/INPUT/] + - [$(FIXorog)/$(CASE)/$(CASE)_grid.tile4.nc, $(DATA)/INPUT/] + - [$(FIXorog)/$(CASE)/$(CASE)_grid.tile5.nc, $(DATA)/INPUT/] + - [$(FIXorog)/$(CASE)/$(CASE)_grid.tile6.nc, $(DATA)/INPUT/] - # oro_data_ls and oro_data_ss files from FIXgfs/ugwd - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ls.tile1.nc, $(DATA)/INPUT/oro_data_ls.tile1.nc] - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ls.tile2.nc, $(DATA)/INPUT/oro_data_ls.tile2.nc] - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ls.tile3.nc, $(DATA)/INPUT/oro_data_ls.tile3.nc] - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ls.tile4.nc, $(DATA)/INPUT/oro_data_ls.tile4.nc] - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ls.tile5.nc, $(DATA)/INPUT/oro_data_ls.tile5.nc] - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ls.tile6.nc, $(DATA)/INPUT/oro_data_ls.tile6.nc] - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ss.tile1.nc, $(DATA)/INPUT/oro_data_ss.tile1.nc] - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ss.tile2.nc, $(DATA)/INPUT/oro_data_ss.tile2.nc] - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ss.tile3.nc, $(DATA)/INPUT/oro_data_ss.tile3.nc] - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ss.tile4.nc, $(DATA)/INPUT/oro_data_ss.tile4.nc] - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ss.tile5.nc, $(DATA)/INPUT/oro_data_ss.tile5.nc] - - [$(FIXgfs)/ugwd/$(CASE)/$(CASE)_oro_data_ss.tile6.nc, $(DATA)/INPUT/oro_data_ss.tile6.nc] + # oro_data_ls and oro_data_ss files from FIXugwd + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ls.tile1.nc, $(DATA)/INPUT/oro_data_ls.tile1.nc] + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ls.tile2.nc, $(DATA)/INPUT/oro_data_ls.tile2.nc] + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ls.tile3.nc, $(DATA)/INPUT/oro_data_ls.tile3.nc] + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ls.tile4.nc, $(DATA)/INPUT/oro_data_ls.tile4.nc] + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ls.tile5.nc, $(DATA)/INPUT/oro_data_ls.tile5.nc] + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ls.tile6.nc, $(DATA)/INPUT/oro_data_ls.tile6.nc] + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ss.tile1.nc, $(DATA)/INPUT/oro_data_ss.tile1.nc] + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ss.tile2.nc, $(DATA)/INPUT/oro_data_ss.tile2.nc] + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ss.tile3.nc, $(DATA)/INPUT/oro_data_ss.tile3.nc] + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ss.tile4.nc, $(DATA)/INPUT/oro_data_ss.tile4.nc] + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ss.tile5.nc, $(DATA)/INPUT/oro_data_ss.tile5.nc] + - [$(FIXugwd)/$(CASE)/$(CASE)_oro_data_ss.tile6.nc, $(DATA)/INPUT/oro_data_ss.tile6.nc] # GWD?? - - [$(FIXgfs)/ugwd/ugwp_limb_tau.nc, $(DATA)/ugwp_limb_tau.nc] + - [$(FIXugwd)/ugwp_limb_tau.nc, $(DATA)/ugwp_limb_tau.nc] # CO2 climatology - [$(FIXgfs)/am/co2monthlycyc.txt, $(DATA)/co2monthlycyc.txt] diff --git a/parm/ufs/fix/gfs/land.fixed_files.yaml b/parm/ufs/fix/gfs/land.fixed_files.yaml index 8e4d221dbc..bb2d060963 100644 --- a/parm/ufs/fix/gfs/land.fixed_files.yaml +++ b/parm/ufs/fix/gfs/land.fixed_files.yaml @@ -1,58 +1,58 @@ copy: - # Files from FIXgfs/orog/C??/sfc - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile1.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile2.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile3.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile4.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile5.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile6.nc, $(DATA)/] + # Files from FIXorog/C??/sfc + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile1.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile2.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile3.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile4.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile5.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).facsf.tile6.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile1.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile2.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile3.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile4.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile5.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile6.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile1.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile2.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile3.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile4.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile5.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).maximum_snow_albedo.tile6.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile1.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile2.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile3.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile4.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile5.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile6.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile1.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile2.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile3.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile4.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile5.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).slope_type.tile6.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile1.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile2.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile3.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile4.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile5.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile6.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile1.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile2.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile3.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile4.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile5.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).snowfree_albedo.tile6.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile1.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile2.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile3.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile4.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile5.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile6.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile1.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile2.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile3.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile4.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile5.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).soil_type.tile6.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile1.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile2.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile3.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile4.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile5.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile6.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile1.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile2.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile3.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile4.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile5.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).substrate_temperature.tile6.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile1.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile2.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile3.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile4.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile5.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile6.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile1.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile2.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile3.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile4.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile5.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_greenness.tile6.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile1.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile2.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile3.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile4.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile5.nc, $(DATA)/] - - [$(FIXgfs)/orog/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile6.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile1.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile2.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile3.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile4.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile5.nc, $(DATA)/] + - [$(FIXorog)/$(CASE)/sfc/$(CASE).mx$(OCNRES).vegetation_type.tile6.nc, $(DATA)/] diff --git a/parm/ufs/fix/gfs/ocean.fixed_files.yaml b/parm/ufs/fix/gfs/ocean.fixed_files.yaml index 4ef19bab0d..1ca8ce7a68 100644 --- a/parm/ufs/fix/gfs/ocean.fixed_files.yaml +++ b/parm/ufs/fix/gfs/ocean.fixed_files.yaml @@ -1,9 +1,9 @@ copy: # Orography data tile files - - [$(FIXgfs)/orog/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile1.nc, $(DATA)/INPUT/oro_data.tile1.nc] - - [$(FIXgfs)/orog/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile2.nc, $(DATA)/INPUT/oro_data.tile2.nc] - - [$(FIXgfs)/orog/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile3.nc, $(DATA)/INPUT/oro_data.tile3.nc] - - [$(FIXgfs)/orog/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile4.nc, $(DATA)/INPUT/oro_data.tile4.nc] - - [$(FIXgfs)/orog/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile5.nc, $(DATA)/INPUT/oro_data.tile5.nc] - - [$(FIXgfs)/orog/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile6.nc, $(DATA)/INPUT/oro_data.tile6.nc] + - [$(FIXorog)/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile1.nc, $(DATA)/INPUT/oro_data.tile1.nc] + - [$(FIXorog)/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile2.nc, $(DATA)/INPUT/oro_data.tile2.nc] + - [$(FIXorog)/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile3.nc, $(DATA)/INPUT/oro_data.tile3.nc] + - [$(FIXorog)/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile4.nc, $(DATA)/INPUT/oro_data.tile4.nc] + - [$(FIXorog)/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile5.nc, $(DATA)/INPUT/oro_data.tile5.nc] + - [$(FIXorog)/$(CASE)/$(CASE).mx$(OCNRES)_oro_data.tile6.nc, $(DATA)/INPUT/oro_data.tile6.nc] diff --git a/parm/ufs/fv3/diag_table b/parm/ufs/fv3/diag_table index 9e26d80154..dad8b6fac6 100644 --- a/parm/ufs/fv3/diag_table +++ b/parm/ufs/fv3/diag_table @@ -1,7 +1,6 @@ "fv3_history", 0, "hours", 1, "hours", "time" "fv3_history2d", 0, "hours", 1, "hours", "time" -"@[MOM6_OUTPUT_DIR]/ocn%4yr%2mo%2dy%2hr", @[FHOUT_OCNICE], "hours", 1, "hours", "time", @[FHOUT_OCNICE], "hours", "@[SYEAR] @[SMONTH] @[SDAY] @[CHOUR] 0 0" -"@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", 1, "days", 1, "days", "time", 1, "days", "@[SYEAR] @[SMONTH] @[SDAY] @[CHOUR] 0 0" +"@[MOM6_OUTPUT_DIR]/ocn%4yr%2mo%2dy%2hr", @[FHOUT_OCN], "hours", 1, "hours", "time", @[FHOUT_OCN], "hours", "@[SYEAR] @[SMONTH] @[SDAY] @[CHOUR] 0 0" ############## # Ocean fields @@ -57,25 +56,6 @@ "ocean_model", "LwLatSens", "LwLatSens", "@[MOM6_OUTPUT_DIR]/ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 "ocean_model", "Heat_PmE", "Heat_PmE", "@[MOM6_OUTPUT_DIR]/ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 -# Daily fields -"ocean_model", "geolon", "geolon", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 -"ocean_model", "geolat", "geolat", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 -"ocean_model", "geolon_c", "geolon_c", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 -"ocean_model", "geolat_c", "geolat_c", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 -"ocean_model", "geolon_u", "geolon_u", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 -"ocean_model", "geolat_u", "geolat_u", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 -"ocean_model", "geolon_v", "geolon_v", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 -"ocean_model", "geolat_v", "geolat_v", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 -"ocean_model", "SST", "sst", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 -"ocean_model", "latent", "latent", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 -"ocean_model", "sensible", "sensible", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 -"ocean_model", "SW", "SW", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 -"ocean_model", "LW", "LW", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 -"ocean_model", "evap", "evap", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 -"ocean_model", "lprec", "lprec", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 -"ocean_model", "taux", "taux", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 -"ocean_model", "tauy", "tauy", "@[MOM6_OUTPUT_DIR]/ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 - ################### # Atmosphere fields ################### diff --git a/scripts/exgdas_enkf_sfc.sh b/scripts/exgdas_enkf_sfc.sh index cd6a40a0fa..2720dd5d5f 100755 --- a/scripts/exgdas_enkf_sfc.sh +++ b/scripts/exgdas_enkf_sfc.sh @@ -162,8 +162,8 @@ if [ $DOIAU = "YES" ]; then "${DATA}/fnbgsi.${cmem}" ${NLN} "${COM_ATMOS_RESTART_MEM}/${bPDY}.${bcyc}0000.sfcanl_data.tile${n}.nc" \ "${DATA}/fnbgso.${cmem}" - ${NLN} "${FIXgfs}/orog/${CASE}/${CASE}_grid.tile${n}.nc" "${DATA}/fngrid.${cmem}" - ${NLN} "${FIXgfs}/orog/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile${n}.nc" "${DATA}/fnorog.${cmem}" + ${NLN} "${FIXorog}/${CASE}/${CASE}_grid.tile${n}.nc" "${DATA}/fngrid.${cmem}" + ${NLN} "${FIXorog}/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile${n}.nc" "${DATA}/fnorog.${cmem}" if [[ ${GSI_SOILANAL} = "YES" ]]; then FHR=6 @@ -207,8 +207,8 @@ if [ $DOSFCANL_ENKF = "YES" ]; then "${DATA}/fnbgsi.${cmem}" ${NLN} "${COM_ATMOS_RESTART_MEM}/${PDY}.${cyc}0000.sfcanl_data.tile${n}.nc" \ "${DATA}/fnbgso.${cmem}" - ${NLN} "${FIXgfs}/orog/${CASE}/${CASE}_grid.tile${n}.nc" "${DATA}/fngrid.${cmem}" - ${NLN} "${FIXgfs}/orog/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile${n}.nc" "${DATA}/fnorog.${cmem}" + ${NLN} "${FIXorog}/${CASE}/${CASE}_grid.tile${n}.nc" "${DATA}/fngrid.${cmem}" + ${NLN} "${FIXorog}/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile${n}.nc" "${DATA}/fnorog.${cmem}" done diff --git a/scripts/exgfs_atmos_awips_20km_1p0deg.sh b/scripts/exgfs_atmos_awips_20km_1p0deg.sh index 490875b2c4..4959bbd8e8 100755 --- a/scripts/exgfs_atmos_awips_20km_1p0deg.sh +++ b/scripts/exgfs_atmos_awips_20km_1p0deg.sh @@ -43,20 +43,14 @@ source "${USHgfs}/product_functions.sh" ############################################### # Wait for the availability of the pgrb file ############################################### -icnt=1 -while (( icnt < 1000 )); do - if [[ -s "${COM_ATMOS_GRIB_0p25}/${RUN}.${cycle}.pgrb2b.0p25.f${fcsthrs}.idx" ]]; then - break - fi - - sleep 10 - icnt=$((icnt + 1)) - if (( icnt >= 180 )); then - msg="FATAL ERROR: No GFS pgrb2 file after 30 min of waiting" - err_exit "${msg}" - exit 5 - fi -done +sleep_interval=10 +max_tries=180 +idxfile="${COM_ATMOS_GRIB_0p25}/${RUN}.${cycle}.pgrb2b.0p25.f${fcsthrs}.idx" +if ! wait_for_file "${idxfile}" "${sleep_interval}" "${max_tries}"; then + msg="FATAL ERROR: No GFS pgrb2 file after waiting" + err_exit "${msg}" + exit 5 +fi ######################################## diff --git a/scripts/exgfs_atmos_postsnd.sh b/scripts/exgfs_atmos_postsnd.sh index 23c41157fe..caf5443a50 100755 --- a/scripts/exgfs_atmos_postsnd.sh +++ b/scripts/exgfs_atmos_postsnd.sh @@ -50,6 +50,8 @@ declare -x LEVS ### Loop for the hour and wait for the sigma and surface flux file: export FSTART=$STARTHOUR +sleep_interval=10 +max_tries=360 # while [ $FSTART -lt $ENDHOUR ] do @@ -69,28 +71,18 @@ export FINT=$NINT1 export MAKEBUFR=YES fi - ic=0 - while [ $ic -lt 1000 ]; do - if [[ ! -f "${COM_ATMOS_HISTORY}/${RUN}.${cycle}.atm.logf${FEND}.${logfm}" ]]; then - sleep 10 - ic=$(expr $ic + 1) - else - break - fi - - if [ $ic -ge 360 ] - then - err_exit "COULD NOT LOCATE logf$FEND file AFTER 1 HOUR" - fi - done + filename="${COM_ATMOS_HISTORY}/${RUN}.${cycle}.atm.logf${FEND}.${logfm}" + if ! wait_for_file "${filename}" "${sleep_interval}" "${max_tries}"; then + err_exit "FATAL ERROR: logf${FEND} not found after waiting $((sleep_interval * ( max_tries - 1) )) secs" + fi ## 1-hourly output before $NEND1, 3-hourly output after - if [ $FEND -gt $NEND1 ]; then + if [[ $((10#$FEND)) -gt $((10#$NEND1)) ]]; then export FINT=$NINT3 fi ${USHgfs}/gfs_bufr.sh - export FSTART=$FEND + export FSTART="${FEND}" done ############################################################## diff --git a/scripts/exgfs_wave_nawips.sh b/scripts/exgfs_wave_nawips.sh index 69c4e54ebb..949425cbc1 100755 --- a/scripts/exgfs_wave_nawips.sh +++ b/scripts/exgfs_wave_nawips.sh @@ -44,6 +44,7 @@ pdsext=no g2tbls=g2varswmo2.tbl NAGRIB=nagrib2 +sleep_interval=20 maxtries=15 fhcnt=${fstart} while [ ${fhcnt} -le ${FHMAX_WAV} ]; do @@ -72,28 +73,11 @@ while [ ${fhcnt} -le ${FHMAX_WAV} ]; do esac GRIBIN="${COM_WAVE_GRID}/${RUNwave}.${cycle}.${grdIDin}.f${fhr}.grib2" GRIBIN_chk=${GRIBIN}.idx - - icnt=1 - while [ ${icnt} -lt 1000 ]; do - if [ -r ${GRIBIN_chk} ] ; then - break - else - let "icnt=icnt+1" - sleep 20 - fi - if [ ${icnt} -ge ${maxtries} ]; then - msg="ABORTING after 5 minutes of waiting for ${GRIBIN}." - echo ' ' - echo '**************************** ' - echo '*** ERROR : NO GRIB FILE *** ' - echo '**************************** ' - echo ' ' - echo ${msg} - set_trace - echo "${RUNwave} ${grdID} ${fhr} prdgen ${date} ${cycle} : GRIB file missing." >> ${wavelog} - err=1;export err;${errchk} || exit ${err} - fi - done + if ! wait_for_file "${GRIBIN_chk}" "${sleep_interval}" "${maxtries}"; then + echo "FATAL ERROR: ${GRIBIN_chk} not found after waiting $((sleep_interval * ( max_tries - 1))) secs" + echo "${RUNwave} ${grdID} ${fhr} prdgen ${date} ${cycle} : GRIB file missing." >> "${wavelog}" + err=1;export err;"${errchk}" || exit "${err}" + fi #if [ "$grdIDin" = "global.0p25" && "$grid" = "glo_30m" ]; then if [ "${grdIDin}" = "global.0p25" ]; then diff --git a/scripts/exgfs_wave_post_gridded_sbs.sh b/scripts/exgfs_wave_post_gridded_sbs.sh index cee6d40b49..02aa8c456d 100755 --- a/scripts/exgfs_wave_post_gridded_sbs.sh +++ b/scripts/exgfs_wave_post_gridded_sbs.sh @@ -231,6 +231,7 @@ source "${USHgfs}/preamble.sh" fhr=$FHMIN_WAV fi fhrg=$fhr + sleep_interval=10 iwaitmax=120 # Maximum loop cycles for waiting until wave component output file is ready (fails after max) while [ $fhr -le $FHMAX_WAV ]; do @@ -253,26 +254,21 @@ source "${USHgfs}/preamble.sh" export GRDIDATA=${DATA}/output_$YMDHMS # Gridded data (main part, need to be run side-by-side with forecast - + if [ $fhr = $fhrg ] then - iwait=0 - for wavGRD in ${waveGRD} ; do - gfile=${COM_WAVE_HISTORY}/${WAV_MOD_TAG}.out_grd.${wavGRD}.${YMD}.${HMS} - while [ ! -s ${gfile} ]; do sleep 10; let iwait=iwait+1; done - if [ $iwait -eq $iwaitmax ]; then - echo '*************************************************** ' - echo " FATAL ERROR : NO RAW FIELD OUTPUT FILE out_grd.$grdID " - echo '*************************************************** ' - echo ' ' - set_trace + + for wavGRD in ${waveGRD}; do + gfile="${COM_WAVE_HISTORY}/${WAV_MOD_TAG}.out_grd.${wavGRD}.${YMD}.${HMS}" + if ! wait_for_file "${gfile}" "${sleep_interval}" "${iwaitmax}"; then + echo " FATAL ERROR : NO RAW FIELD OUTPUT FILE out_grd.${grdID}" echo "${WAV_MOD_TAG} post ${grdID} ${PDY} ${cycle} : field output missing." - err=3; export err;${errchk} - exit $err + err=3; export err; "${errchk}" + exit "${err}" fi - ${NLN} ${gfile} ./out_grd.${wavGRD} + ${NLN} "${gfile}" "./out_grd.${wavGRD}" done - + if [ "$DOGRI_WAV" = 'YES' ] then nigrd=1 diff --git a/scripts/exgfs_wave_post_pnt.sh b/scripts/exgfs_wave_post_pnt.sh index 6e456e2aec..56cb83be21 100755 --- a/scripts/exgfs_wave_post_pnt.sh +++ b/scripts/exgfs_wave_post_pnt.sh @@ -247,8 +247,9 @@ source "${USHgfs}/preamble.sh" -e "s/FORMAT/F/g" \ ww3_outp_spec.inp.tmpl > ww3_outp.inp - ${NLN} mod_def.$waveuoutpGRD mod_def.ww3 - HMS="${cyc}0000" + ${NLN} mod_def.${waveuoutpGRD} mod_def.ww3 + HH=$(date --utc -d "${PDY:0:8} ${cyc} + ${FHMIN_WAV} hours" +%H) + HMS="${HH}0000" if [[ -f "${COM_WAVE_HISTORY}/${WAV_MOD_TAG}.out_pnt.${waveuoutpGRD}.${PDY}.${HMS}" ]]; then ${NLN} "${COM_WAVE_HISTORY}/${WAV_MOD_TAG}.out_pnt.${waveuoutpGRD}.${PDY}.${HMS}" \ "./out_pnt.${waveuoutpGRD}" diff --git a/scripts/exgfs_wave_prdgen_gridded.sh b/scripts/exgfs_wave_prdgen_gridded.sh index c51ce60acc..c896423ac1 100755 --- a/scripts/exgfs_wave_prdgen_gridded.sh +++ b/scripts/exgfs_wave_prdgen_gridded.sh @@ -96,30 +96,14 @@ grids=${grids:-ak_10m at_10m ep_10m wc_10m glo_30m} # GRIBIN="${COM_WAVE_GRID}/${RUNwave}.${cycle}.${grdID}.f${fhr}.grib2" - GRIBIN_chk=$GRIBIN.idx - - icnt=1 - while [ $icnt -lt 1000 ]; do - if [ -r $GRIBIN_chk ] ; then - break - else - echo "Waiting for input file: $GRIBIN" - let "icnt=icnt+1" - sleep 5 - fi - if [ $icnt -ge $maxtries ]; then - msg="ABNORMAL EXIT: NO GRIB FILE FOR GRID $GRIBIN" - echo ' ' - echo '**************************** ' - echo '*** ERROR : NO GRIB FILE *** ' - echo '**************************** ' - echo ' ' - echo $msg - set_trace - echo "$RUNwave $grdID ${fhr} prdgen $date $cycle : GRIB file missing." >> $wavelog - err=1;export err;${errchk} || exit ${err} - fi - done + GRIBIN_chk="${GRIBIN}.idx" + sleep_interval=5 + max_tries=1000 + if ! wait_for_file "${GRIBIN_chk}" "${sleep_interval}" "${max_tries}"; then + echo "FATAL ERROR: ${GRIBIN_chk} not found after waiting $((sleep_interval * ( max_tries - 1))) secs" + echo "$RUNwave $grdID ${fhr} prdgen $date $cycle : GRIB file missing." >> $wavelog + err=1;export err;${errchk} || exit ${err} + fi GRIBOUT=$RUNwave.$cycle.$grdID.f${fhr}.clipped.grib2 diff --git a/scripts/exglobal_archive.py b/scripts/exglobal_archive.py index d700eebb5d..bcd8d522d9 100755 --- a/scripts/exglobal_archive.py +++ b/scripts/exglobal_archive.py @@ -19,12 +19,12 @@ def main(): # Pull out all the configuration keys needed to run the rest of archive steps keys = ['ATARDIR', 'current_cycle', 'FHMIN', 'FHMAX', 'FHOUT', 'RUN', 'PDY', - 'DO_VERFRAD', 'DO_VMINMON', 'DO_VERFOZN', 'DO_ICE', 'DO_AERO', 'PARMgfs', - 'DO_OCN', 'DO_WAVE', 'WRITE_DOPOST', 'PSLOT', 'HPSSARCH', 'DO_MOS', + 'DO_VERFRAD', 'DO_VMINMON', 'DO_VERFOZN', 'DO_ICE', 'DO_AERO', 'DO_PREP_OBS_AERO', + 'PARMgfs', 'DO_OCN', 'DO_WAVE', 'WRITE_DOPOST', 'PSLOT', 'HPSSARCH', 'DO_MOS', 'DO_JEDISNOWDA', 'LOCALARCH', 'REALTIME', 'ROTDIR', 'ARCH_WARMICFREQ', 'ARCH_FCSTICFREQ', 'ARCH_CYC', 'assim_freq', 'ARCDIR', 'SDATE', 'FHMIN_GFS', 'FHMAX_GFS', 'FHOUT_GFS', 'ARCH_GAUSSIAN', 'MODE', - 'FHOUT_OCNICE', 'FHOUT_OCNICE_GFS', 'DO_BUFRSND', 'DOHYBVAR', + 'FHOUT_OCN', 'FHOUT_ICE', 'FHOUT_OCN_GFS', 'FHOUT_ICE_GFS', 'DO_BUFRSND', 'DOHYBVAR', 'ARCH_GAUSSIAN_FHMAX', 'ARCH_GAUSSIAN_FHINC', 'ARCH_GAUSSIAN_FHINC', 'DOIAU', 'OCNRES', 'ICERES', 'NUM_SND_COLLECTIVES', 'FHOUT_WAV', 'FHOUT_HF_WAV', 'FHMAX_WAV', 'FHMAX_HF_WAV', 'FHMAX_WAV_GFS', diff --git a/scripts/exglobal_atmos_analysis.sh b/scripts/exglobal_atmos_analysis.sh index 3b3405f871..0e78bed2e0 100755 --- a/scripts/exglobal_atmos_analysis.sh +++ b/scripts/exglobal_atmos_analysis.sh @@ -430,7 +430,18 @@ ${NLN} ${CRTM_FIX}/NPOESS.VISsnow.EmisCoeff.bin ./crtm_coeffs/NPOESS.VISsnow.Em ${NLN} ${CRTM_FIX}/NPOESS.VISwater.EmisCoeff.bin ./crtm_coeffs/NPOESS.VISwater.EmisCoeff.bin ${NLN} ${CRTM_FIX}/FASTEM6.MWwater.EmisCoeff.bin ./crtm_coeffs/FASTEM6.MWwater.EmisCoeff.bin ${NLN} ${CRTM_FIX}/AerosolCoeff.bin ./crtm_coeffs/AerosolCoeff.bin -${NLN} ${CRTM_FIX}/CloudCoeff.GFDLFV3.-109z-1.bin ./crtm_coeffs/CloudCoeff.bin +if (( imp_physics == 8 )); then + echo "using CRTM Thompson cloud optical table" + ${NLN} "${CRTM_FIX}/CloudCoeff.Thompson08.-109z-1.bin" ./crtm_coeffs/CloudCoeff.bin +elif (( imp_physics == 11 )); then + echo "using CRTM GFDL cloud optical table" + ${NLN} "${CRTM_FIX}/CloudCoeff.GFDLFV3.-109z-1.bin" ./crtm_coeffs/CloudCoeff.bin +else + echo "INVALID imp_physics = ${imp_physics}" + echo "FATAL ERROR: No valid CRTM cloud optical table found for imp_physics = ${imp_physics}" + exit 1 +fi + ############################################################## # Observational data diff --git a/scripts/exglobal_cleanup.sh b/scripts/exglobal_cleanup.sh index cdc13c119b..7c3dfafbad 100755 --- a/scripts/exglobal_cleanup.sh +++ b/scripts/exglobal_cleanup.sh @@ -2,6 +2,13 @@ source "${USHgfs}/preamble.sh" +# Remove DATAoutput from the forecast model run +# TODO: Handle this better +DATAfcst="${DATAROOT}/${RUN}fcst.${PDY:-}${cyc}" +if [[ -d "${DATAfcst}" ]]; then rm -rf "${DATAfcst}"; fi +#DATAefcs="${DATAROOT}/${RUN}efcs???${PDY:-}${cyc}" +rm -rf "${DATAROOT}/${RUN}efcs"*"${PDY:-}${cyc}" + ############################################################### # Clean up previous cycles; various depths # PRIOR CYCLE: Leave the prior cycle alone @@ -59,10 +66,11 @@ for (( current_date=first_date; current_date <= last_date; \ # TODO: This needs to be revamped to not look at the rocoto log. # shellcheck disable=SC2312 if [[ $(tail -n 1 "${rocotolog}") =~ "This cycle is complete: Success" ]]; then - YMD="${current_PDY}" HH="${current_cyc}" declare_from_tmpl COM_TOP - if [[ -d "${COM_TOP}" ]]; then + YMD="${current_PDY}" HH="${current_cyc}" declare_from_tmpl \ + COMOUT_TOP:COM_TOP_TMPL + if [[ -d "${COMOUT_TOP}" ]]; then IFS=", " read -r -a exclude_list <<< "${exclude_string:-}" - remove_files "${COM_TOP}" "${exclude_list[@]:-}" + remove_files "${COMOUT_TOP}" "${exclude_list[@]:-}" fi if [[ -d "${rtofs_dir}" ]] && (( current_date < last_rtofs )); then rm -rf "${rtofs_dir}" ; fi fi diff --git a/scripts/exglobal_forecast.sh b/scripts/exglobal_forecast.sh index 590c3aba17..e2bccd43db 100755 --- a/scripts/exglobal_forecast.sh +++ b/scripts/exglobal_forecast.sh @@ -38,9 +38,9 @@ ## Restart files: ## ## Fix files: -## 1. computing grid, ${FIXgfs}/orog/$CASE/${CASE}_grid.tile${n}.nc -## 2. orography data, ${FIXgfs}/orog/$CASE/${CASE}.mx${OCNRES}_oro_data.tile${n}.nc -## 3. mosaic data, ${FIXgfs}/orog/$CASE/${CASE}_mosaic.nc +## 1. computing grid, ${FIXorog}/$CASE/${CASE}_grid.tile${n}.nc +## 2. orography data, ${FIXorog}/$CASE/${CASE}.mx${OCNRES}_oro_data.tile${n}.nc +## 3. mosaic data, ${FIXorog}/$CASE/${CASE}_mosaic.nc ## 4. Global O3 data, ${FIXgfs}/am/${O3FORC} ## 5. Global H2O data, ${FIXgfs}/am/${H2OFORC} ## 6. Global solar constant data, ${FIXgfs}/am/global_solarconstant_noaa_an.txt diff --git a/scripts/exglobal_prep_obs_aero.py b/scripts/exglobal_prep_obs_aero.py new file mode 100755 index 0000000000..08548e6874 --- /dev/null +++ b/scripts/exglobal_prep_obs_aero.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# exglobal_prep_obs_aero.py +# This script collect available viirs +# obs files, combine and preprocess +# them. +import os + +from wxflow import Logger, cast_strdict_as_dtypedict +from pygfs.task.aero_prepobs import AerosolObsPrep + +# Initialize root logger +logger = Logger(level='DEBUG', colored_log=True) + + +if __name__ == '__main__': + + # Take configuration from environment and cast it as python dictionary + config = cast_strdict_as_dtypedict(os.environ) + + AeroObs = AerosolObsPrep(config) + AeroObs.initialize() + AeroObs.runConverter() + AeroObs.finalize() diff --git a/sorc/build_upp.sh b/sorc/build_upp.sh index 1dca0035fd..e217e171db 100755 --- a/sorc/build_upp.sh +++ b/sorc/build_upp.sh @@ -26,6 +26,6 @@ if [[ ! -d "../exec" ]]; then mkdir -p ../exec fi -cd upp.fd/tests +cd ufs_model.fd/FV3/upp/tests # shellcheck disable=SC2086 BUILD_JOBS=${BUILD_JOBS:-8} ./compile_upp.sh ${_opts} diff --git a/sorc/gdas.cd b/sorc/gdas.cd index 3e50a8fdcd..2bd8ffc149 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit 3e50a8fdcd07305a3464a02e20eaf4b033179167 +Subproject commit 2bd8ffc149f30c0ae0f8e1508477a8dc88c46a65 diff --git a/sorc/gsi_utils.fd b/sorc/gsi_utils.fd index d940406161..4332814529 160000 --- a/sorc/gsi_utils.fd +++ b/sorc/gsi_utils.fd @@ -1 +1 @@ -Subproject commit d9404061611553459394173c3ff33116db306326 +Subproject commit 4332814529465ab8eb58e43a38227b952ebfca49 diff --git a/sorc/link_workflow.sh b/sorc/link_workflow.sh index f338f2bad3..1f0de0745c 100755 --- a/sorc/link_workflow.sh +++ b/sorc/link_workflow.sh @@ -84,10 +84,6 @@ esac # Source fix version file source "${HOMEgfs}/versions/fix.ver" -# global-nest uses different versions of orog and ugwd -if [[ "${LINK_NEST:-OFF}" == "ON" ]] ; then - source "${HOMEgfs}/versions/fix.nest.ver" -fi # Link python pacakges in ush/python # TODO: This will be unnecessary when these are part of the virtualenv @@ -134,7 +130,20 @@ do fix_ver="${dir}_ver" ${LINK_OR_COPY} "${FIX_DIR}/${dir}/${!fix_ver}" "${dir}" done - +# global-nest uses different versions of orog and ugwd +if [[ "${LINK_NEST:-OFF}" == "ON" ]] ; then + for dir in orog \ + ugwd + do + nestdir=${dir}_nest + if [[ -d "${nestdir}" ]]; then + [[ "${RUN_ENVIR}" == "nco" ]] && chmod -R 755 "${nestdir}" + rm -rf "${nestdir}" + fi + fix_ver="${dir}_nest_ver" + ${LINK_OR_COPY} "${FIX_DIR}/${dir}/${!fix_ver}" "${nestdir}" + done +fi #--------------------------------------- #--add files from external repositories @@ -370,11 +379,10 @@ fi #--link source code directories #------------------------------ cd "${HOMEgfs}/sorc" || exit 8 -# TODO: Commenting out until UPP is up-to-date with Rocky-8. -#if [[ -d ufs_model.fd ]]; then -# [[ -d upp.fd ]] && rm -rf upp.fd -# ${LINK} ufs_model.fd/FV3/upp upp.fd -#fi +if [[ -d ufs_model.fd ]]; then + [[ -d upp.fd ]] && rm -rf upp.fd + ${LINK} ufs_model.fd/FV3/upp upp.fd +fi if [[ -d gsi_enkf.fd ]]; then [[ -d gsi.fd ]] && rm -rf gsi.fd diff --git a/sorc/ufs_model.fd b/sorc/ufs_model.fd index 5bec704243..485ccdfc4a 160000 --- a/sorc/ufs_model.fd +++ b/sorc/ufs_model.fd @@ -1 +1 @@ -Subproject commit 5bec704243286421fc613838fc67a2129e96acd6 +Subproject commit 485ccdfc4a7ed6deeb02d82c2cebe51b37e892f5 diff --git a/sorc/ufs_utils.fd b/sorc/ufs_utils.fd index f42fae239d..2794d413d0 160000 --- a/sorc/ufs_utils.fd +++ b/sorc/ufs_utils.fd @@ -1 +1 @@ -Subproject commit f42fae239d0824f7b9a83c9afdc3d980894c7df8 +Subproject commit 2794d413d083b43d9ba37a15375d5c61b610d29e diff --git a/sorc/upp.fd b/sorc/upp.fd deleted file mode 160000 index 83e83a938b..0000000000 --- a/sorc/upp.fd +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 83e83a938b5794a628d30e66a54902dabe58737d diff --git a/ush/calcanl_gfs.py b/ush/calcanl_gfs.py index 8c5c643417..ceb75104a2 100755 --- a/ush/calcanl_gfs.py +++ b/ush/calcanl_gfs.py @@ -135,7 +135,7 @@ def calcanl_gfs(DoIAU, l4DEnsVar, Write4Danl, ComOut, APrefix, ExecCMDMPI1 = ExecCMDMPI.replace("$ncmd", str(1)) ExecCMDMPI = ExecCMDMPI.replace("$ncmd", str(nFH)) ExecCMDLevs = ExecCMDMPI.replace("$ncmd", str(levs)) - ExecCMDMPI10 = ExecCMDMPI.replace("$ncmd", str(10)) + ExecCMDMPI13 = ExecCMDMPI.replace("$ncmd", str(13)) # are we using mpirun with lsf, srun, or aprun with Cray? launcher = ExecCMDMPI.split(' ')[0] @@ -156,7 +156,7 @@ def calcanl_gfs(DoIAU, l4DEnsVar, Write4Danl, ComOut, APrefix, ExecCMDMPILevs_host = 'mpirun -np ' + str(levs) + ' --hostfile hosts' ExecCMDMPILevs_nohost = 'mpirun -np ' + str(levs) ExecCMDMPI1_host = 'mpirun -np 1 --hostfile hosts' - ExecCMDMPI10_host = 'mpirun -np 10 --hostfile hosts' + ExecCMDMPI13_host = 'mpirun -np 13 --hostfile hosts' elif launcher == 'mpiexec': hostfile = os.getenv('PBS_NODEFILE', '') with open(hostfile) as f: @@ -175,7 +175,7 @@ def calcanl_gfs(DoIAU, l4DEnsVar, Write4Danl, ComOut, APrefix, ExecCMDMPILevs_host = 'mpiexec -l -n ' + str(levs) ExecCMDMPILevs_nohost = 'mpiexec -l -n ' + str(levs) ExecCMDMPI1_host = 'mpiexec -l -n 1 --cpu-bind depth --depth ' + str(NThreads) - ExecCMDMPI10_host = 'mpiexec -l -n 10 --cpu-bind depth --depth ' + str(NThreads) + ExecCMDMPI13_host = 'mpiexec -l -n 13 --cpu-bind depth --depth ' + str(NThreads) elif launcher == 'srun': nodes = os.getenv('SLURM_JOB_NODELIST', '') hosts_tmp = subprocess.check_output('scontrol show hostnames ' + nodes, shell=True) @@ -200,7 +200,7 @@ def calcanl_gfs(DoIAU, l4DEnsVar, Write4Danl, ComOut, APrefix, ExecCMDMPILevs_host = 'srun -n ' + str(levs) + ' --verbose --export=ALL -c 1 --distribution=arbitrary --cpu-bind=cores' ExecCMDMPILevs_nohost = 'srun -n ' + str(levs) + ' --verbose --export=ALL' ExecCMDMPI1_host = 'srun -n 1 --verbose --export=ALL -c 1 --distribution=arbitrary --cpu-bind=cores' - ExecCMDMPI10_host = 'srun -n 10 --verbose --export=ALL -c 1 --distribution=arbitrary --cpu-bind=cores' + ExecCMDMPI13_host = 'srun -n 13 --verbose --export=ALL -c 1 --distribution=arbitrary --cpu-bind=cores' elif launcher == 'aprun': hostfile = os.getenv('LSB_DJOB_HOSTFILE', '') with open(hostfile) as f: @@ -213,7 +213,7 @@ def calcanl_gfs(DoIAU, l4DEnsVar, Write4Danl, ComOut, APrefix, ExecCMDMPILevs_host = 'aprun -l hosts -d ' + str(NThreads) + ' -n ' + str(levs) ExecCMDMPILevs_nohost = 'aprun -d ' + str(NThreads) + ' -n ' + str(levs) ExecCMDMPI1_host = 'aprun -l hosts -d ' + str(NThreads) + ' -n 1' - ExecCMDMPI10_host = 'aprun -l hosts -d ' + str(NThreads) + ' -n 10' + ExecCMDMPI13_host = 'aprun -l hosts -d ' + str(NThreads) + ' -n 13' else: print('unknown MPI launcher. Failure.') sys.exit(1) @@ -248,13 +248,13 @@ def calcanl_gfs(DoIAU, l4DEnsVar, Write4Danl, ComOut, APrefix, ihost += 1 for a in range(0, 5): hostfile.write(hosts[ihost] + '\n') - for a in range(0, 9): # need 9 more of the same host for the 10 tasks for chgres_inc + for a in range(0, 12): # need 12 more of the same host for the 13 tasks for chgres_inc hostfile.write(hosts[ihost] + '\n') if launcher == 'srun': os.environ['SLURM_HOSTFILE'] = CalcAnlDir + '/hosts' print('interp_inc', fh, namelist) - job = subprocess.Popen(ExecCMDMPI10_host + ' ' + CalcAnlDir + '/chgres_inc.x', shell=True, cwd=CalcAnlDir) - print(ExecCMDMPI10_host + ' ' + CalcAnlDir + '/chgres_inc.x submitted on ' + hosts[ihost]) + job = subprocess.Popen(ExecCMDMPI13_host + ' ' + CalcAnlDir + '/chgres_inc.x', shell=True, cwd=CalcAnlDir) + print(ExecCMDMPI13_host + ' ' + CalcAnlDir + '/chgres_inc.x submitted on ' + hosts[ihost]) sys.stdout.flush() ec = job.wait() if ec != 0: diff --git a/ush/check_ice_netcdf.sh b/ush/check_ice_netcdf.sh new file mode 100755 index 0000000000..02ca4dae80 --- /dev/null +++ b/ush/check_ice_netcdf.sh @@ -0,0 +1,43 @@ +#! /usr/bin/env bash + +yyyy=${1?} +mm=${2?} +dd=${3?} +cyc=${4?} +fhr=${5?} +ROTDIR=${6?} +member=${7?} +FHOUT_ICE_GFS=${8?} + +fhri=$((10#${fhr})) + +#Will need to consider fhmin in the future to calculate the offset if we are to stick with this approach. +((offset = ( cyc ) % FHOUT_ICE_GFS)) + +if (( offset != 0 )); then + (( fhri = fhri - cyc )) + fhr3=$(printf %03i "${fhri}") + if (( fhri <= FHOUT_ICE_GFS )); then + (( interval = FHOUT_ICE_GFS - cyc )) + ncfile=${ROTDIR}/gefs.${yyyy}${mm}${dd}/${cyc}/mem${member}/model_data/ice/history/gefs.ice.t${cyc}z.${interval}hr_avg.f${fhr3}.nc + else + ncfile=${ROTDIR}/gefs.${yyyy}${mm}${dd}/${cyc}/mem${member}/model_data/ice/history/gefs.ice.t${cyc}z.${FHOUT_ICE_GFS}hr_avg.f${fhr3}.nc + fi +else + ncfile=${ROTDIR}/gefs.${yyyy}${mm}${dd}/${cyc}/mem${member}/model_data/ice/history/gefs.ice.t${cyc}z.${FHOUT_ICE_GFS}hr_avg.f${fhr}.nc +fi + +#Check if netcdf file exists. +if [[ ! -f "${ncfile}" ]];then + rc=1 +else + #Check if netcdf file is older than 2 minutes. + ncage="$(find "${ncfile}" -mmin -2)" + if [[ -n "${ncage}" ]]; then + rc=1 + else + rc=0 + fi +fi + +exit "${rc}" diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index d4d1d4ad6f..2cc34eaacd 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -8,40 +8,24 @@ FV3_postdet() { echo "warm_start = ${warm_start}" echo "RERUN = ${RERUN}" + #============================================================================ + # First copy initial conditions # cold start case if [[ "${warm_start}" == ".false." ]]; then - # Create an array of chgres-ed FV3 files - local fv3_input_files tile_files fv3_input_file - fv3_input_files=(gfs_ctrl.nc) - tile_files=(gfs_data sfc_data) - local nn tt - for (( nn = 1; nn <= ntiles; nn++ )); do - for tt in "${tile_files[@]}"; do - fv3_input_files+=("${tt}.tile${nn}.nc") - done - done - + # 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}'" - for fv3_input_file in "${fv3_input_files[@]}"; do - ${NCP} "${COMIN_ATMOS_INPUT}/${fv3_input_file}" "${DATA}/INPUT/${fv3_input_file}" \ + local fv3_file + for fv3_file in ${file_list}; do + ${NCP} "${COMIN_ATMOS_INPUT}/${fv3_file}" "${DATA}/INPUT/${fv3_file}" \ || ( echo "FATAL ERROR: Unable to copy FV3 IC, ABORT!"; exit 1 ) done # warm start case elif [[ "${warm_start}" == ".true." ]]; then - # Create an array of FV3 restart files - local fv3_restart_files tile_files fv3_restart_file restart_file - fv3_restart_files=(coupler.res fv_core.res.nc) - tile_files=(fv_core.res fv_srf_wnd.res fv_tracer.res phy_data sfc_data ca_data) - local nn tt - for (( nn = 1; nn <= ntiles; nn++ )); do - for tt in "${tile_files[@]}"; do - fv3_restart_files+=("${tt}.tile${nn}.nc") - done - done - # Determine restart date and directory containing restarts local restart_date restart_dir if [[ "${RERUN}" == "YES" ]]; then @@ -52,26 +36,18 @@ FV3_postdet() { 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}'" - for fv3_restart_file in "${fv3_restart_files[@]}"; do - restart_file="${restart_date:0:8}.${restart_date:8:2}0000.${fv3_restart_file}" - ${NCP} "${restart_dir}/${restart_file}" "${DATA}/INPUT/${fv3_restart_file}" \ + 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}" + ${NCP} "${restart_dir}/${restart_file}" "${DATA}/INPUT/${fv3_file}" \ || ( echo "FATAL ERROR: Unable to copy FV3 IC, ABORT!"; exit 1 ) done - 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 - - else # "${RERUN}" == "NO" - + if [[ "${RERUN}" != "YES" ]]; then # Replace sfc_data with sfcanl_data restart files from current cycle (if found) local nn for (( nn = 1; nn <= ntiles; nn++ )); do @@ -84,9 +60,55 @@ FV3_postdet() { break fi done + fi # if [[ "${RERUN}" != "YES" ]]; then - # Need a coupler.res that is consistent with the model start time + fi # if [[ "${warm_start}" == ".true." ]]; then + + #============================================================================ + # Determine increment files when doing cold start + if [[ "${warm_start}" == ".false." ]]; then + + if [[ "${REPLAY_ICS:-NO}" == "YES" ]]; then + IAU_FHROT=${half_window} # Replay ICs start at the end of the assimilation window + if (( MEMBER == 0 )); then + inc_files=() + else + inc_files=("atminc.nc") + read_increment=".true." + res_latlon_dynamics="atminc.nc" + fi + local increment_file + for inc_file in "${inc_files[@]}"; do + increment_file="${COMIN_ATMOS_INPUT}/${RUN}.t${cyc}z.${inc_file}" + if [[ -f "${increment_file}" ]]; then + ${NCP} "${increment_file}" "${DATA}/INPUT/${inc_file}" + else + echo "FATAL ERROR: missing increment file '${increment_file}', ABORT!" + exit 1 + fi + 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 + + #-------------------------------------------------------------------------- + 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}" @@ -121,6 +143,15 @@ EOF inc_files=("atminc.nc") read_increment=".true." res_latlon_dynamics="atminc.nc" + if [[ "${REPLAY_ICS:-NO}" == "YES" ]]; then + IAU_FHROT=${half_window} # Replay ICs start at the end of the assimilation window + # Control member has no perturbation + if (( MEMBER == 0 )); then + inc_files=() + read_increment=".false." + res_latlon_dynamics='""' + fi + fi fi local increment_file @@ -135,17 +166,22 @@ EOF done fi # if [[ "${RERUN}" == "YES" ]]; then + #-------------------------------------------------------------------------- fi # if [[ "${warm_start}" == ".true." ]]; then + #============================================================================ + #============================================================================ # If doing IAU, change forecast hours - if [[ "${DOIAU:-}" == "YES" ]]; then + 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 @@ -162,8 +198,9 @@ EOF na_init=0 fi # warm_start == .true. + #============================================================================ - cd "${DATA}" || exit 1 + #============================================================================ if [[ "${QUILTING}" = ".true." ]] && [[ "${OUTPUT_GRID}" = "gaussian_grid" ]]; then local FH2 FH3 for fhr in ${FV3_OUTPUT_FH}; do @@ -181,16 +218,8 @@ EOF fi fi done - else # TODO: Is this even valid anymore? - local nn - for (( nn = 1; nn <= ntiles; nn++ )); do - ${NLN} "nggps2d.tile${nn}.nc" "${COMOUT_ATMOS_HISTORY}/nggps2d.tile${nn}.nc" - ${NLN} "nggps3d.tile${nn}.nc" "${COMOUT_ATMOS_HISTORY}/nggps3d.tile${nn}.nc" - ${NLN} "grid_spec.tile${nn}.nc" "${COMOUT_ATMOS_HISTORY}/grid_spec.tile${nn}.nc" - ${NLN} "atmos_static.tile${nn}.nc" "${COMOUT_ATMOS_HISTORY}/atmos_static.tile${nn}.nc" - ${NLN} "atmos_4xdaily.tile${nn}.nc" "${COMOUT_ATMOS_HISTORY}/atmos_4xdaily.tile${nn}.nc" - done fi + #============================================================================ } FV3_nml() { @@ -217,51 +246,41 @@ FV3_out() { echo "SUB ${FUNCNAME[0]}: copying output data for FV3" # Copy configuration files - if [[ "${RUN}" == "gfs" || "${RUN}" == "gefs" ]]; then - ${NCP} "${DATA}/input.nml" "${COMOUT_CONF}/ufs.input.nml" - ${NCP} "${DATA}/model_configure" "${COMOUT_CONF}/ufs.model_configure" - ${NCP} "${DATA}/ufs.configure" "${COMOUT_CONF}/ufs.ufs.configure" - ${NCP} "${DATA}/diag_table" "${COMOUT_CONF}/ufs.diag_table" - fi - - # Create an array of fv3 restart files - local fv3_restart_files tile_files fv3_restart_file restart_file - fv3_restart_files=(coupler.res fv_core.res.nc) - tile_files=(fv_core.res fv_srf_wnd.res fv_tracer.res phy_data sfc_data ca_data) - local nn tt - for (( nn = 1; nn <= ntiles; nn++ )); do - for tt in "${tile_files[@]}"; do - fv3_restart_files+=("${tt}.tile${nn}.nc") - done - done - + ${NCP} "${DATA}/input.nml" "${COMOUT_CONF}/ufs.input.nml" + ${NCP} "${DATA}/model_configure" "${COMOUT_CONF}/ufs.model_configure" + ${NCP} "${DATA}/ufs.configure" "${COMOUT_CONF}/ufs.ufs.configure" + ${NCP} "${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=() # Copy restarts in the assimilation window for RUN=gdas|enkfgdas|enkfgfs if [[ "${RUN}" =~ "gdas" || "${RUN}" == "enkfgfs" ]]; then - local restart_date - restart_date=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${restart_interval} hours" +%Y%m%d%H) + restart_date="${model_start_date_next_cycle}" while (( restart_date <= forecast_end_cycle )); do - echo "Copying FV3 restarts for 'RUN=${RUN}' at ${restart_date}" - for fv3_restart_file in "${fv3_restart_files[@]}"; do - restart_file="${restart_date:0:8}.${restart_date:8:2}0000.${fv3_restart_file}" - ${NCP} "${DATArestart}/FV3_RESTART/${restart_file}" \ - "${COMOUT_ATMOS_RESTART}/${restart_file}" - done + 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 + elif [[ "${RUN}" == "gfs" || "${RUN}" == "gefs" ]]; then # Copy restarts at the end of the forecast segment for RUN=gfs|gefs + if [[ "${COPY_FINAL_RESTARTS}" == "YES" ]]; then + restart_dates+=("${forecast_end_cycle:0:8}.${forecast_end_cycle:8:2}0000") + fi fi - # Copy the final restart files at the end of the forecast segment - # The final restart written at the end of the forecast does not include the valid date - # TODO: verify the above statement since RM found that it did! - # TODO: For other components, this is only for gfs/gefs - check to see if this should also have this - if [[ "${COPY_FINAL_RESTARTS}" == "YES" ]]; then - echo "Copying FV3 restarts for 'RUN=${RUN}' at the end of the forecast segment: ${forecast_end_cycle}" - for fv3_restart_file in "${fv3_restart_files[@]}"; do - restart_file="${forecast_end_cycle:0:8}.${forecast_end_cycle:8:2}0000.${fv3_restart_file}" - ${NCP} "${DATArestart}/FV3_RESTART/${restart_file}" \ - "${COMOUT_ATMOS_RESTART}/${restart_file}" + # 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 + ${NCP} "${DATArestart}/FV3_RESTART/${restart_date}.${fv3_file}" \ + "${COMOUT_ATMOS_RESTART}/${restart_date}.${fv3_file}" done - fi + done + echo "SUB ${FUNCNAME[0]}: Output data for FV3 copied" } @@ -363,7 +382,7 @@ WW3_out() { CPL_out() { echo "SUB ${FUNCNAME[0]}: Copying output data for general cpl fields" - if [[ "${esmf_profile:-}" == ".true." ]]; then + if [[ "${esmf_profile:-.false.}" == ".true." ]]; then ${NCP} "${DATA}/ESMF_Profile.summary" "${COMOUT_ATMOS_HISTORY}/ESMF_Profile.summary" fi } @@ -407,7 +426,7 @@ MOM6_postdet() { # TODO if [[ $RUN} == "gefs" ]] block maybe be needed # to ensure it does not interfere with the GFS when ensemble is updated in the GFS if (( MEMBER > 0 )) && [[ "${ODA_INCUPD:-False}" == "True" ]]; then - ${NCP} "${COMIN_OCEAN_RESTART_PREV}/${restart_date:0:8}.${restart_date:0:8}0000.mom6_increment.nc" "${DATA}/INPUT/mom6_increment.nc" \ + ${NCP} "${COMIN_OCEAN_ANALYSIS}/mom6_increment.nc" "${DATA}/INPUT/mom6_increment.nc" \ || ( echo "FATAL ERROR: Unable to copy ensemble MOM6 increment, ABORT!"; exit 1 ) fi fi # if [[ "${RERUN}" == "NO" ]]; then @@ -436,13 +455,6 @@ MOM6_postdet() { dest_file="${RUN}.ocean.t${cyc}z.${interval}hr_avg.f${fhr3}.nc" ${NLN} "${COMOUT_OCEAN_HISTORY}/${dest_file}" "${DATA}/MOM6_OUTPUT/${source_file}" - # Daily output - if (( fhr > 0 & fhr % 24 == 0 )); then - source_file="ocn_daily_${vdate:0:4}_${vdate:4:2}_${vdate:6:2}.nc" - dest_file="${RUN}.ocean.t${cyc}z.daily.f${fhr3}.nc" - ${NLN} "${COMOUT_OCEAN_HISTORY}/${dest_file}" "${DATA}/MOM6_OUTPUT/${source_file}" - fi - last_fhr=${fhr} done @@ -545,14 +557,14 @@ CICE_postdet() { # Link CICE forecast output files from DATA/CICE_OUTPUT to COM local source_file dest_file - for fhr in ${CICE_OUTPUT_FH}; do - fhr3=$(printf %03i "${fhr}") + 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) @@ -560,7 +572,7 @@ CICE_postdet() { vdatestr="${vdate:0:4}-${vdate:4:2}-${vdate:6:2}-${seconds}" if [[ "${RUN}" =~ "gfs" || "${RUN}" =~ "gefs" ]]; then - source_file="iceh_$(printf "%0.2d" "${interval}")h.${vdatestr}.nc" + source_file="iceh_$(printf "%0.2d" "${FHOUT_ICE}")h.${vdatestr}.nc" dest_file="${RUN}.ice.t${cyc}z.${interval}hr_avg.f${fhr3}.nc" elif [[ "${RUN}" =~ "gdas" ]]; then source_file="iceh_inst.${vdatestr}.nc" diff --git a/ush/forecast_predet.sh b/ush/forecast_predet.sh index c26b214fc9..9183e86002 100755 --- a/ush/forecast_predet.sh +++ b/ush/forecast_predet.sh @@ -36,6 +36,38 @@ nhour(){ echo "${hours}" } +FV3_coldstarts(){ + # Function to return an comma-separated string of cold-start input files for FV3 + # Create an array of chgres-ed FV3 files + local fv3_input_files tile_files + fv3_input_files=(gfs_ctrl.nc) + tile_files=(gfs_data sfc_data) + local nn tt + for (( nn = 1; nn <= ntiles; nn++ )); do + for tt in "${tile_files[@]}"; do + fv3_input_files+=("${tt}.tile${nn}.nc") + done + done + # Create a comma separated string from array using IFS + IFS=, echo "${fv3_input_files[*]}" +} + +FV3_restarts(){ + # Function to return an comma-separated string of warm-start input files for FV3 + # Create an array of FV3 restart files + local fv3_restart_files tile_files + fv3_restart_files=(coupler.res fv_core.res.nc) + tile_files=(fv_core.res fv_srf_wnd.res fv_tracer.res phy_data sfc_data ca_data) + local nn tt + for (( nn = 1; nn <= ntiles; nn++ )); do + for tt in "${tile_files[@]}"; do + fv3_restart_files+=("${tt}.tile${nn}.nc") + done + done + # Create a comma separated string from array using IFS + IFS=, echo "${fv3_restart_files[*]}" +} + # shellcheck disable=SC2034 common_predet(){ echo "SUB ${FUNCNAME[0]}: Defining variables for shared through model components" @@ -54,15 +86,20 @@ common_predet(){ current_cycle_begin=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} - ${half_window} hours" +%Y%m%d%H) current_cycle_end=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${half_window} hours" +%Y%m%d%H) next_cycle_begin=$(date --utc -d "${next_cycle:0:8} ${next_cycle:8:2} - ${half_window} hours" +%Y%m%d%H) - #Define model start date for current_cycle and next_cycle as the time the forecast will start - if [[ "${DOIAU:-}" == "YES" ]]; then + forecast_end_cycle=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${FHMAX} hours" +%Y%m%d%H) + + # Define model start date for current_cycle and next_cycle as the time the forecast will start + if [[ "${DOIAU:-NO}" == "YES" ]]; then model_start_date_current_cycle="${current_cycle_begin}" model_start_date_next_cycle="${next_cycle_begin}" else - model_start_date_current_cycle=${current_cycle} + if [[ "${REPLAY_ICS:-NO}" == "YES" ]]; then + model_start_date_current_cycle=${current_cycle_end} + else + model_start_date_current_cycle=${current_cycle} + fi model_start_date_next_cycle=${next_cycle} - fi - forecast_end_cycle=$(date --utc -d "${current_cycle:0:8} ${current_cycle:8:2} + ${FHMAX} hours" +%Y%m%d%H) + fi FHMIN=${FHMIN:-0} FHMAX=${FHMAX:-9} @@ -346,18 +383,18 @@ FV3_predet(){ FNSNOC=${FNSNOC:-"${FIXgfs}/am/global_snoclim.1.875.grb"} FNZORC=${FNZORC:-"igbp"} FNAISC=${FNAISC:-"${FIXgfs}/am/IMS-NIC.blended.ice.monthly.clim.grb"} - FNALBC2=${FNALBC2:-"${FIXgfs}/orog/${CASE}/sfc/${CASE}.mx${OCNRES}.facsf.tileX.nc"} - FNTG3C=${FNTG3C:-"${FIXgfs}/orog/${CASE}/sfc/${CASE}.mx${OCNRES}.substrate_temperature.tileX.nc"} - FNVEGC=${FNVEGC:-"${FIXgfs}/orog/${CASE}/sfc/${CASE}.mx${OCNRES}.vegetation_greenness.tileX.nc"} + FNALBC2=${FNALBC2:-"${FIXorog}/${CASE}/sfc/${CASE}.mx${OCNRES}.facsf.tileX.nc"} + FNTG3C=${FNTG3C:-"${FIXorog}/${CASE}/sfc/${CASE}.mx${OCNRES}.substrate_temperature.tileX.nc"} + FNVEGC=${FNVEGC:-"${FIXorog}/${CASE}/sfc/${CASE}.mx${OCNRES}.vegetation_greenness.tileX.nc"} FNMSKH=${FNMSKH:-"${FIXgfs}/am/global_slmask.t1534.3072.1536.grb"} - FNVMNC=${FNVMNC:-"${FIXgfs}/orog/${CASE}/sfc/${CASE}.mx${OCNRES}.vegetation_greenness.tileX.nc"} - FNVMXC=${FNVMXC:-"${FIXgfs}/orog/${CASE}/sfc/${CASE}.mx${OCNRES}.vegetation_greenness.tileX.nc"} - FNSLPC=${FNSLPC:-"${FIXgfs}/orog/${CASE}/sfc/${CASE}.mx${OCNRES}.slope_type.tileX.nc"} - FNALBC=${FNALBC:-"${FIXgfs}/orog/${CASE}/sfc/${CASE}.mx${OCNRES}.snowfree_albedo.tileX.nc"} - FNVETC=${FNVETC:-"${FIXgfs}/orog/${CASE}/sfc/${CASE}.mx${OCNRES}.vegetation_type.tileX.nc"} - FNSOTC=${FNSOTC:-"${FIXgfs}/orog/${CASE}/sfc/${CASE}.mx${OCNRES}.soil_type.tileX.nc"} - FNSOCC=${FNSOCC:-"${FIXgfs}/orog/${CASE}/sfc/${CASE}.mx${OCNRES}.soil_color.tileX.nc"} - FNABSC=${FNABSC:-"${FIXgfs}/orog/${CASE}/sfc/${CASE}.mx${OCNRES}.maximum_snow_albedo.tileX.nc"} + FNVMNC=${FNVMNC:-"${FIXorog}/${CASE}/sfc/${CASE}.mx${OCNRES}.vegetation_greenness.tileX.nc"} + FNVMXC=${FNVMXC:-"${FIXorog}/${CASE}/sfc/${CASE}.mx${OCNRES}.vegetation_greenness.tileX.nc"} + FNSLPC=${FNSLPC:-"${FIXorog}/${CASE}/sfc/${CASE}.mx${OCNRES}.slope_type.tileX.nc"} + FNALBC=${FNALBC:-"${FIXorog}/${CASE}/sfc/${CASE}.mx${OCNRES}.snowfree_albedo.tileX.nc"} + FNVETC=${FNVETC:-"${FIXorog}/${CASE}/sfc/${CASE}.mx${OCNRES}.vegetation_type.tileX.nc"} + FNSOTC=${FNSOTC:-"${FIXorog}/${CASE}/sfc/${CASE}.mx${OCNRES}.soil_type.tileX.nc"} + FNSOCC=${FNSOCC:-"${FIXorog}/${CASE}/sfc/${CASE}.mx${OCNRES}.soil_color.tileX.nc"} + FNABSC=${FNABSC:-"${FIXorog}/${CASE}/sfc/${CASE}.mx${OCNRES}.maximum_snow_albedo.tileX.nc"} FNSMCC=${FNSMCC:-"${FIXgfs}/am/global_soilmgldas.statsgo.t${JCAP}.${LONB}.${LATB}.grb"} # If the appropriate resolution fix file is not present, use the highest resolution available (T1534) @@ -365,21 +402,21 @@ FV3_predet(){ # Grid and orography data if [[ "${cplflx}" == ".false." ]] ; then - ${NCP} "${FIXgfs}/orog/${CASE}/${CASE}_mosaic.nc" "${DATA}/INPUT/grid_spec.nc" + ${NCP} "${FIXorog}/${CASE}/${CASE}_mosaic.nc" "${DATA}/INPUT/grid_spec.nc" else - ${NCP} "${FIXgfs}/orog/${CASE}/${CASE}_mosaic.nc" "${DATA}/INPUT/${CASE}_mosaic.nc" + ${NCP} "${FIXorog}/${CASE}/${CASE}_mosaic.nc" "${DATA}/INPUT/${CASE}_mosaic.nc" fi # Files for GWD - ${NCP} "${FIXgfs}/ugwd/ugwp_limb_tau.nc" "${DATA}/ugwp_limb_tau.nc" + ${NCP} "${FIXugwd}/ugwp_limb_tau.nc" "${DATA}/ugwp_limb_tau.nc" # Files for orography, GWD tiles local tt for (( tt = 1; tt <= ntiles; tt++ )); do - ${NCP} "${FIXgfs}/orog/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile${tt}.nc" "${DATA}/INPUT/oro_data.tile${tt}.nc" - ${NCP} "${FIXgfs}/orog/${CASE}/${CASE}_grid.tile${tt}.nc" "${DATA}/INPUT/${CASE}_grid.tile${tt}.nc" - ${NCP} "${FIXgfs}/ugwd/${CASE}/${CASE}_oro_data_ls.tile${tt}.nc" "${DATA}/INPUT/oro_data_ls.tile${tt}.nc" - ${NCP} "${FIXgfs}/ugwd/${CASE}/${CASE}_oro_data_ss.tile${tt}.nc" "${DATA}/INPUT/oro_data_ss.tile${tt}.nc" + ${NCP} "${FIXorog}/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile${tt}.nc" "${DATA}/INPUT/oro_data.tile${tt}.nc" + ${NCP} "${FIXorog}/${CASE}/${CASE}_grid.tile${tt}.nc" "${DATA}/INPUT/${CASE}_grid.tile${tt}.nc" + ${NCP} "${FIXugwd}/${CASE}/${CASE}_oro_data_ls.tile${tt}.nc" "${DATA}/INPUT/oro_data_ls.tile${tt}.nc" + ${NCP} "${FIXugwd}/${CASE}/${CASE}_oro_data_ss.tile${tt}.nc" "${DATA}/INPUT/oro_data_ss.tile${tt}.nc" done if [[ "${DO_NEST:-NO}" == "YES" ]] ; then ${NLN} "${DATA}/INPUT/oro_data.tile7.nc" "${DATA}/INPUT/oro_data.nest02.tile7.nc" @@ -568,7 +605,15 @@ CICE_predet(){ # CICE does not have a concept of high frequency output like FV3 # Convert output settings into an explicit list for CICE - CICE_OUTPUT_FH=$(seq -s ' ' "${FHMIN}" "${FHOUT_OCNICE}" "${FHMAX}") + if (( $(( ( cyc + FHMIN ) % FHOUT_ICE )) == 0 )); then + # shellcheck disable=SC2312 + mapfile -t CICE_OUTPUT_FH < <(seq "${FHMIN}" "${FHOUT_ICE}" "${FHMAX}") || exit 10 + else + CICE_OUTPUT_FH=("${FHMIN}") + # shellcheck disable=SC2312 + mapfile -t -O "${#CICE_OUTPUT_FH[@]}" CICE_OUTPUT_FH < <(seq "$(( FHMIN + $(( ( cyc + FHMIN ) % FHOUT_ICE )) ))" "${FHOUT_ICE}" "${FHMAX}") || exit 10 + CICE_OUTPUT_FH+=("${FHMAX}") + fi # Fix files ${NCP} "${FIXgfs}/cice/${ICERES}/${CICE_GRID}" "${DATA}/" @@ -591,7 +636,7 @@ MOM6_predet(){ # MOM6 does not have a concept of high frequency output like FV3 # Convert output settings into an explicit list for MOM6 - MOM6_OUTPUT_FH=$(seq -s ' ' "${FHMIN}" "${FHOUT_OCNICE}" "${FHMAX}") + MOM6_OUTPUT_FH=$(seq -s ' ' "${FHMIN}" "${FHOUT_OCN}" "${FHMAX}") # If using stochastic parameterizations, create a seed that does not exceed the # largest signed integer diff --git a/ush/gaussian_sfcanl.sh b/ush/gaussian_sfcanl.sh index 794dbb7f7f..4ac762824b 100755 --- a/ush/gaussian_sfcanl.sh +++ b/ush/gaussian_sfcanl.sh @@ -73,7 +73,7 @@ # # programs : $GAUSFCANLEXE # -# fixed data : ${FIXgfs}/orog/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile*.nc +# fixed data : ${FIXorog}/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile*.nc # ${FIXWGTS} # ${FIXgfs}/am/global_hyblev.l65.txt # @@ -111,7 +111,7 @@ LATB_SFC=${LATB_SFC:-$LATB_CASE} DONST=${DONST:-"NO"} LEVS=${LEVS:-64} LEVSP1=$(($LEVS+1)) -FIXWGTS=${FIXWGTS:-${FIXgfs}/orog/${CASE}/fv3_SCRIP_${CASE}_GRIDSPEC_lon${LONB_SFC}_lat${LATB_SFC}.gaussian.neareststod.nc} +FIXWGTS=${FIXWGTS:-${FIXorog}/${CASE}/fv3_SCRIP_${CASE}_GRIDSPEC_lon${LONB_SFC}_lat${LATB_SFC}.gaussian.neareststod.nc} DATA=${DATA:-$(pwd)} # Filenames. @@ -161,12 +161,12 @@ ${NLN} "${COM_ATMOS_RESTART}/${PDY}.${cyc}0000.sfcanl_data.tile5.nc" "./anal.til ${NLN} "${COM_ATMOS_RESTART}/${PDY}.${cyc}0000.sfcanl_data.tile6.nc" "./anal.tile6.nc" # input orography tiles -${NLN} "${FIXgfs}/orog/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile1.nc" "./orog.tile1.nc" -${NLN} "${FIXgfs}/orog/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile2.nc" "./orog.tile2.nc" -${NLN} "${FIXgfs}/orog/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile3.nc" "./orog.tile3.nc" -${NLN} "${FIXgfs}/orog/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile4.nc" "./orog.tile4.nc" -${NLN} "${FIXgfs}/orog/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile5.nc" "./orog.tile5.nc" -${NLN} "${FIXgfs}/orog/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile6.nc" "./orog.tile6.nc" +${NLN} "${FIXorog}/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile1.nc" "./orog.tile1.nc" +${NLN} "${FIXorog}/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile2.nc" "./orog.tile2.nc" +${NLN} "${FIXorog}/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile3.nc" "./orog.tile3.nc" +${NLN} "${FIXorog}/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile4.nc" "./orog.tile4.nc" +${NLN} "${FIXorog}/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile5.nc" "./orog.tile5.nc" +${NLN} "${FIXorog}/${CASE}/${CASE}.mx${OCNRES}_oro_data.tile6.nc" "./orog.tile6.nc" ${NLN} "${SIGLEVEL}" "./vcoord.txt" diff --git a/ush/gfs_bufr.sh b/ush/gfs_bufr.sh index 287365ba88..8a7d9b1091 100755 --- a/ush/gfs_bufr.sh +++ b/ush/gfs_bufr.sh @@ -51,26 +51,20 @@ cat << EOF > gfsparm / EOF +sleep_interval=10 +max_tries=1000 for (( hr = 10#${FSTART}; hr <= 10#${FEND}; hr = hr + 10#${FINT} )); do hh2=$(printf %02i "${hr}") hh3=$(printf %03i "${hr}") #--------------------------------------------------------- # Make sure all files are available: - ic=0 - while (( ic < 1000 )); do - if [[ ! -f "${COM_ATMOS_HISTORY}/${RUN}.${cycle}.atm.logf${hh3}.${logfm}" ]]; then - sleep 10 - ic=$((ic + 1)) - else - break - fi - - if (( ic >= 360 )); then - echo "FATAL: COULD NOT LOCATE logf${hh3} file AFTER 1 HOUR" - exit 2 - fi - done + filename="${COM_ATMOS_HISTORY}/${RUN}.${cycle}.atm.logf${hh3}.${logfm}" + if ! wait_for_file "${filename}" "${sleep_interval}" "${max_tries}"; then + echo "FATAL ERROR: COULD NOT LOCATE logf${hh3} file" + exit 2 + fi + #------------------------------------------------------------------ ${NLN} "${COM_ATMOS_HISTORY}/${RUN}.${cycle}.atmf${hh3}.${atmfm}" "sigf${hh2}" ${NLN} "${COM_ATMOS_HISTORY}/${RUN}.${cycle}.sfcf${hh3}.${atmfm}" "flxf${hh2}" @@ -96,11 +90,11 @@ esac ${APRUN_POSTSND} "${EXECgfs}/${pgm}" < gfsparm > "out_gfs_bufr_${FEND}" export err=$? -if [ $err -ne 0 ]; then +if [[ "${err}" -ne 0 ]]; then echo "GFS postsnd job error, Please check files " echo "${COM_ATMOS_HISTORY}/${RUN}.${cycle}.atmf${hh2}.${atmfm}" echo "${COM_ATMOS_HISTORY}/${RUN}.${cycle}.sfcf${hh2}.${atmfm}" err_chk fi -exit ${err} +exit "${err}" diff --git a/ush/gfs_bufr_netcdf.sh b/ush/gfs_bufr_netcdf.sh index f10ba40730..f03ff3b9af 100755 --- a/ush/gfs_bufr_netcdf.sh +++ b/ush/gfs_bufr_netcdf.sh @@ -66,6 +66,9 @@ hh=$FSTART hh1=$(echo "${hh#"${hh%??}"}") hh=$hh1 fi + +sleep_interval=10 +max_tries=360 while test $hh -le $FEND do if test $hh -lt 100 @@ -75,24 +78,11 @@ do hh2=$hh fi -#--------------------------------------------------------- -# Make sure all files are available: - ic=0 - while [ $ic -lt 1000 ] - do - if [ ! -f $COMIN/${RUN}.${cycle}.logf${hh2}.txt ] - then - sleep 10 - ic=$(expr $ic + 1) - else - break - fi + filename="${COMIN}/${RUN}.${cycle}.logf${hh2}.txt" + if ! wait_for_file "${filename}" "${sleep_interval}" "${max_tries}" ; then + err_exit "FATAL ERROR COULD NOT LOCATE logf${hh2} file" + fi - if [ $ic -ge 360 ] - then - err_exit "COULD NOT LOCATE logf${hh2} file AFTER 1 HOUR" - fi - done #------------------------------------------------------------------ ${NLN} $COMIN/${RUN}.${cycle}.atmf${hh2}.nc sigf${hh} ${NLN} $COMIN/${RUN}.${cycle}.${SFCF}f${hh2}.nc flxf${hh} diff --git a/ush/parsing_namelists_CICE.sh b/ush/parsing_namelists_CICE.sh index 9aed59e214..aa495d1864 100755 --- a/ush/parsing_namelists_CICE.sh +++ b/ush/parsing_namelists_CICE.sh @@ -69,7 +69,7 @@ local CICE_RESTART_FORMAT="pnetcdf2" local CICE_DUMPFREQ="y" # "h","d","m" or "y" for restarts at intervals of "hours", "days", "months" or "years" local CICE_DUMPFREQ_N=10000 # Set this to a really large value, as cice, mom6 and cmeps restart interval is controlled by ufs.configure local CICE_DIAGFREQ=$(( 86400 / DT_CICE )) # frequency of diagnostic output in timesteps, recommended for 1x per day -local CICE_HISTFREQ_N="0, 0, ${FHOUT_OCNICE}, 1, 1" +local CICE_HISTFREQ_N="0, 0, ${FHOUT_ICE}, 1, 1" if [[ "${RUN}" =~ "gdas" ]]; then local CICE_HIST_AVG=".false., .false., .false., .false., .false." # DA needs instantaneous else diff --git a/ush/parsing_namelists_WW3.sh b/ush/parsing_namelists_WW3.sh index a01d694710..c57a90e50a 100755 --- a/ush/parsing_namelists_WW3.sh +++ b/ush/parsing_namelists_WW3.sh @@ -18,7 +18,7 @@ WW3_namelists(){ fi # Set time stamps for model start and output # For special case when IAU is on but this is an initial half cycle - if [ $IAU_OFFSET = 0 ]; then + if [ ${IAU_OFFSET:-0} = 0 ]; then ymdh_beg=$YMDH else ymdh_beg=$($NDATE -$WAVHINDH $YMDH) diff --git a/ush/python/pygfs/task/aero_prepobs.py b/ush/python/pygfs/task/aero_prepobs.py new file mode 100644 index 0000000000..f2344241a9 --- /dev/null +++ b/ush/python/pygfs/task/aero_prepobs.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 + +import os +import glob +import gzip +import tarfile +import re +from logging import getLogger +from typing import List, Dict, Any, Union + +from wxflow import (AttrDict, FileHandler, rm_p, rmdir, + Task, add_to_datetime, to_timedelta, to_datetime, + datetime_to_YMD, + chdir, Executable, WorkflowException, + parse_j2yaml, save_as_yaml, logit) + +logger = getLogger(__name__.split('.')[-1]) + + +class AerosolObsPrep(Task): + """ + Class for preparing and managing aerosol observations + """ + def __init__(self, config: Dict[str, Any]) -> None: + super().__init__(config) + + _window_begin = add_to_datetime(self.runtime_config.current_cycle, -to_timedelta(f"{self.config['assim_freq']}H") / 2) + _window_end = add_to_datetime(self.runtime_config.current_cycle, +to_timedelta(f"{self.config['assim_freq']}H") / 2) + + local_dict = AttrDict( + { + 'window_begin': _window_begin, + 'window_end': _window_end, + 'sensors': str(self.config['SENSORS']).split(','), + 'data_dir': self.config['VIIRS_DATA_DIR'], + 'input_files': '', + 'OPREFIX': f"{self.runtime_config.RUN}.t{self.runtime_config.cyc:02d}z.", + 'APREFIX': f"{self.runtime_config.RUN}.t{self.runtime_config.cyc:02d}z." + } + ) + + # task_config is everything that this task should need + self.task_config = AttrDict(**self.config, **self.runtime_config, **local_dict) + + @logit(logger) + def initialize(self) -> None: + """ + List needed raw obs files. + Copy the raw obs files to $DATA/obs. + Link over the needed executable. + Generate corresponding YAML file. + Run IODA converter. + """ + self.task_config.DATA_OBS = os.path.join(self.task_config.DATA, 'obs') + if os.path.exists(self.task_config.DATA_OBS): + rmdir(self.task_config.DATA_OBS) + FileHandler({'mkdir': [self.task_config.DATA_OBS]}).sync() + + self.task_config.prepaero_yaml = [] + for sensor in self.task_config.sensors: + raw_files = self.list_raw_files(sensor) + self.task_config.input_files = self.copy_obs(raw_files) + self.link_obsconvexe() + self.task_config.prepaero_config = self.get_obsproc_config(sensor) + + # generate converter YAML file + template = f"{self.runtime_config.CDUMP}.t{self.runtime_config['cyc']:02d}z.prepaero_viirs_{sensor}.yaml" + _prepaero_yaml = os.path.join(self.runtime_config.DATA, template) + self.task_config.prepaero_yaml.append(_prepaero_yaml) + logger.debug(f"Generate PrepAeroObs YAML file: {_prepaero_yaml}") + save_as_yaml(self.task_config.prepaero_config, _prepaero_yaml) + logger.info(f"Wrote PrepAeroObs YAML to: {_prepaero_yaml}") + + @logit(logger) + def list_raw_files(self, sensor) -> List[str]: + """ + List all files in the predefined directory that match the predefined sensor and within the time window. + """ + if sensor == 'n20': + sensor = 'j01' + dir1 = os.path.join(self.task_config.data_dir, datetime_to_YMD(self.task_config.window_begin)) + dir2 = os.path.join(self.task_config.data_dir, datetime_to_YMD(self.task_config.window_end)) + + if dir1 == dir2: + files = os.listdir(dir1) + allfiles = [os.path.join(dir1, file) for file in files] + allfiles.sort() + else: + files_1 = os.listdir(dir1) + allfiles_1 = [os.path.join(dir1, file) for file in files_1] + files_2 = os.listdir(dir2) + allfiles_2 = [os.path.join(dir2, file) for file in files_2] + allfiles = sorted(allfiles_1, allfiles_2) + matching_files = [] + try: + for file in allfiles: + basename = os.path.basename(file) + pattern = r"s(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{3})" + match = re.match(pattern, basename.split('_')[3]) + yyyy, mm, dd, HH, MM = match.group(1), match.group(2), match.group(3), match.group(4), match.group(5) + fstart = to_datetime(f'{yyyy}-{mm}-{dd}T{HH}:{MM}Z') + if sensor == basename.split('_')[2]: + # temporally select obs files based on time stamp in the filename. + if (fstart > self.task_config.window_begin) and (fstart < self.task_config.window_end): + matching_files.append(os.path.join(self.task_config.data_dir, file)) + logger.info("Found %d matching files.", len(matching_files)) + except FileNotFoundError: + logger.error("The specified file/directory does not exist.") + raise + return matching_files + + @logit(logger) + def copy_obs(self, inputfiles) -> Dict[str, Any]: + """ + Copy the raw obs files to $DATA/obs. + """ + copylist = [] + destlist = [] + for filename in inputfiles: + basename = os.path.basename(filename) + dest = os.path.join(self.task_config.DATA_OBS, basename) + copylist.append([filename, dest]) + destlist.append(dest) + FileHandler({'copy': copylist}).sync() + + return destlist + + @logit(logger) + def get_obsproc_config(self, sensor) -> Dict[str, Any]: + """ + Compile a dictionary of obs proc configuration from OBSPROCYAML template file + Parameters + ---------- + Returns + ---------- + obsproc_config : Dict + a dictionary containing the fully rendered obs proc yaml configuration + """ + self.task_config.sensor = sensor + # generate JEDI YAML file + logger.info(f"Generate gdas_obsprovider2ioda YAML config: {self.task_config.OBSPROCYAML}") + prepaero_config = parse_j2yaml(self.task_config.OBSPROCYAML, self.task_config) + + return prepaero_config + + @logit(logger) + def link_obsconvexe(self) -> None: + """ + This method links the gdas executable to the run directory + Parameters + ---------- + Task: GDAS task + Returns + ---------- + None + """ + exe_src = self.task_config.OBSPROCEXE + + logger.info(f"Link executable {exe_src} to DATA/") + exe_dest = os.path.join(self.task_config.DATA, os.path.basename(exe_src)) + if os.path.exists(exe_dest): + rm_p(exe_dest) + os.symlink(exe_src, exe_dest) + + return + + @logit(logger) + def runConverter(self) -> None: + """ + Run the IODA converter gdas_obsprovider2ioda.x + """ + chdir(self.task_config.DATA) + exec_cmd = Executable(self.task_config.APRUN_PREPOBSAERO) + exec_name = os.path.join(self.task_config.DATA, 'gdas_obsprovider2ioda.x') + exec_cmd.add_default_arg(exec_name) + + for prepaero_yaml in self.task_config.prepaero_yaml: + try: + logger.debug(f"Executing {exec_cmd} on {prepaero_yaml}") + exec_cmd(f"{prepaero_yaml}") + except OSError: + raise OSError(f"Failed to execute {exec_cmd} on {prepaero_yaml}") + except Exception: + raise WorkflowException(f"An error occured during execution of {exec_cmd} on {prepaero_yaml}") + + pass + + @logit(logger) + def finalize(self) -> None: + """ + Copy the output viirs files to COMIN_OBS. + Tar and archive the output files. + Tar and archive the raw obs files. + """ + # get list of viirs files + obsfiles = glob.glob(os.path.join(self.task_config['DATA'], '*viirs*nc4')) + copylist = [] + for obsfile in obsfiles: + basename = os.path.basename(obsfile) + src = os.path.join(self.task_config['DATA'], basename) + dest = os.path.join(self.task_config.COMOUT_OBS, basename) + copylist.append([src, dest]) + FileHandler({'copy': copylist}).sync() + + # gzip the files first + for obsfile in obsfiles: + with open(obsfile, 'rb') as f_in, gzip.open(f"{obsfile}.gz", 'wb') as f_out: + f_out.writelines(f_in) + + aeroobs = os.path.join(self.task_config.COMOUT_OBS, f"{self.task_config['APREFIX']}aeroobs") + # open tar file for writing + with tarfile.open(aeroobs, "w") as archive: + for obsfile in obsfiles: + aeroobsgzip = f"{obsfile}.gz" + archive.add(aeroobsgzip, arcname=os.path.basename(aeroobsgzip)) + # get list of raw viirs L2 files + rawfiles = glob.glob(os.path.join(self.task_config.DATA_OBS, 'JRR-AOD*')) + # gzip the raw L2 files first + for rawfile in rawfiles: + with open(rawfile, 'rb') as f_in, gzip.open(f"{rawfile}.gz", 'wb') as f_out: + f_out.writelines(f_in) + + aerorawobs = os.path.join(self.task_config.COMOUT_OBS, f"{self.task_config['APREFIX']}aerorawobs") + # open tar file for writing + with tarfile.open(aerorawobs, "w") as archive: + for rawfile in rawfiles: + aerorawobsgzip = f"{rawfile}.gz" + archive.add(aerorawobsgzip, arcname=os.path.basename(aerorawobsgzip)) + copylist = [] + for prepaero_yaml in self.task_config.prepaero_yaml: + basename = os.path.basename(prepaero_yaml) + dest = os.path.join(self.task_config.COMOUT_OBS, basename) + copylist.append([prepaero_yaml, dest]) + FileHandler({'copy': copylist}).sync() + + pass diff --git a/ush/python/pygfs/task/oceanice_products.py b/ush/python/pygfs/task/oceanice_products.py index c865a9f408..690aac9542 100644 --- a/ush/python/pygfs/task/oceanice_products.py +++ b/ush/python/pygfs/task/oceanice_products.py @@ -58,17 +58,35 @@ def __init__(self, config: Dict[str, Any]) -> None: valid_datetime = add_to_datetime(self.runtime_config.current_cycle, to_timedelta(f"{self.config.FORECAST_HOUR}H")) + if self.config.COMPONENT == 'ice': + offset = int(self.runtime_config.current_cycle.strftime("%H")) % self.config.FHOUT_ICE_GFS + # For CICE cases where offset is not 0, forecast_hour needs to be adjusted based on the offset. + # TODO: Consider FHMIN when calculating offset. + if offset != 0: + forecast_hour = self.config.FORECAST_HOUR - int(self.runtime_config.current_cycle.strftime("%H")) + # For the first forecast hour, the interval may be different from the intervals of subsequent forecast hours + if forecast_hour <= self.config.FHOUT_ICE_GFS: + interval = self.config.FHOUT_ICE_GFS - int(self.runtime_config.current_cycle.strftime("%H")) + else: + interval = self.config.FHOUT_ICE_GFS + else: + forecast_hour = self.config.FORECAST_HOUR + interval = self.config.FHOUT_ICE_GFS + if self.config.COMPONENT == 'ocean': + forecast_hour = self.config.FORECAST_HOUR + interval = self.config.FHOUT_OCN_GFS + # TODO: This is a bit of a hack, but it works for now # FIXME: find a better way to provide the averaging period - # This will be different for ocean and ice, so when they are made flexible, this will need to be addressed - avg_period = f"{self.config.FORECAST_HOUR-self.config.FHOUT_OCNICE_GFS:03d}-{self.config.FORECAST_HOUR:03d}" + avg_period = f"{forecast_hour-interval:03d}-{forecast_hour:03d}" localdict = AttrDict( {'component': self.config.COMPONENT, - 'forecast_hour': self.config.FORECAST_HOUR, + 'forecast_hour': forecast_hour, 'valid_datetime': valid_datetime, 'avg_period': avg_period, 'model_grid': model_grid, + 'interval': interval, 'product_grids': self.VALID_PRODUCT_GRIDS[model_grid]} ) self.task_config = AttrDict(**self.config, **self.runtime_config, **localdict) diff --git a/ush/wave_outp_spec.sh b/ush/wave_outp_spec.sh index db9997fd54..159d0eb2cf 100755 --- a/ush/wave_outp_spec.sh +++ b/ush/wave_outp_spec.sh @@ -31,6 +31,7 @@ source "${USHgfs}/preamble.sh" workdir=$4 YMDHE=$($NDATE $FHMAX_WAV_PNT $CDATE) + model_start_date=$(${NDATE} ${OFFSET_START_HOUR} "${PDY}${cyc}") cd $workdir @@ -196,7 +197,7 @@ source "${USHgfs}/preamble.sh" if [ -f $outfile ] then - if [ "${ymdh}" = "${CDATE}" ] + if [ "${ymdh}" = "${model_start_date}" ] then if [ "$specdir" = "bull" ] then @@ -237,6 +238,6 @@ source "${USHgfs}/preamble.sh" # 3.b Clean up the rest cd .. -rm -rf ${specdir}_${bloc} +rm -rf "${specdir}_${bloc}" # End of ww3_outp_spec.sh ---------------------------------------------------- # diff --git a/ush/wave_tar.sh b/ush/wave_tar.sh index bb8836df2c..e01ef61f15 100755 --- a/ush/wave_tar.sh +++ b/ush/wave_tar.sh @@ -29,7 +29,7 @@ source "${USHgfs}/preamble.sh" # 0.a Basic modes of operation - cd $DATA + cd "${DATA}" echo "Making TAR FILE" alertName=$(echo $RUN|tr [a-z] [A-Z]) @@ -47,7 +47,7 @@ source "${USHgfs}/preamble.sh" # 0.b Check if type set - if [ "$#" -lt '3' ] + if [[ "$#" -lt '3' ]] then set +x echo ' ' @@ -64,9 +64,9 @@ source "${USHgfs}/preamble.sh" fi filext=$type - if [ "$type" = "ibp" ]; then filext='spec'; fi - if [ "$type" = "ibpbull" ]; then filext='bull'; fi - if [ "$type" = "ibpcbull" ]; then filext='cbull'; fi + if [[ "$type" = "ibp" ]]; then filext='spec'; fi + if [[ "$type" = "ibpbull" ]]; then filext='bull'; fi + if [[ "$type" = "ibpcbull" ]]; then filext='cbull'; fi rm -rf TAR_${filext}_$ID @@ -88,7 +88,7 @@ source "${USHgfs}/preamble.sh" exit 2 fi - cd ${STA_DIR}/${filext} + cd "${STA_DIR}/${filext}" # --------------------------------------------------------------------------- # # 2. Generate tar file (spectral files are compressed) @@ -98,21 +98,27 @@ source "${USHgfs}/preamble.sh" echo ' Making tar file ...' set_trace - count=0 countMAX=5 tardone='no' - - while [ "$count" -lt "$countMAX" ] && [ "$tardone" = 'no' ] + sleep_interval=10 + + while [[ "${tardone}" = "no" ]] do nf=$(ls | awk '/'$ID.*.$filext'/ {a++} END {print a}') nbm2=$(( $nb - 2 )) - if [ $nf -ge $nbm2 ] - then - tar -cf $ID.$cycle.${type}_tar ./$ID.*.$filext + if [[ "${nf}" -ge "${nbm2}" ]] + then + + tar -cf "${ID}.${cycle}.${type}_tar" ./${ID}.*.${filext} exit=$? + filename="${ID}.${cycle}.${type}_tar" + if ! wait_for_file "${filename}" "${sleep_interval}" "${countMAX}" ; then + echo "FATAL ERROR: File ${filename} not found after waiting $(( sleep_interval * (countMAX + 1) )) secs" + exit 3 + fi - if [ "$exit" != '0' ] + if [[ "${exit}" != '0' ]] then set +x echo ' ' @@ -124,21 +130,15 @@ source "${USHgfs}/preamble.sh" exit 3 fi - if [ -f "$ID.$cycle.${type}_tar" ] + if [[ -f "${ID}.${cycle}.${type}_tar" ]] then tardone='yes' fi - else - set +x - echo ' All files not found for tar. Sleeping 10 seconds and trying again ..' - set_trace - sleep 10 - count=$(expr $count + 1) fi done - if [ "$tardone" = 'no' ] + if [[ "${tardone}" = 'no' ]] then set +x echo ' ' @@ -150,15 +150,15 @@ source "${USHgfs}/preamble.sh" exit 3 fi - if [ "$type" = 'spec' ] + if [[ "${type}" = 'spec' ]] then - if [ -s $ID.$cycle.${type}_tar ] + if [[ -s "${ID}.${cycle}.${type}_tar" ]] then - file_name=$ID.$cycle.${type}_tar.gz - /usr/bin/gzip -c $ID.$cycle.${type}_tar > ${file_name} + file_name="${ID}.${cycle}.${type}_tar.gz" + /usr/bin/gzip -c "${ID}.${cycle}.${type}_tar" > "${file_name}" exit=$? - if [ "$exit" != '0' ] + if [[ "${exit}" != '0' ]] then set +x echo ' ' @@ -171,7 +171,7 @@ source "${USHgfs}/preamble.sh" fi fi else - file_name=$ID.$cycle.${type}_tar + file_name="${ID}.${cycle}.${type}_tar" fi # --------------------------------------------------------------------------- # @@ -186,7 +186,7 @@ source "${USHgfs}/preamble.sh" exit=$? - if [ "$exit" != '0' ] + if [[ "${exit}" != '0' ]] then set +x echo ' ' @@ -198,7 +198,7 @@ source "${USHgfs}/preamble.sh" exit 4 fi - if [ "$SENDDBN" = 'YES' ] + if [[ "${SENDDBN}" = 'YES' ]] then set +x echo ' ' @@ -212,7 +212,7 @@ source "${USHgfs}/preamble.sh" # --------------------------------------------------------------------------- # # 4. Final clean up -cd $DATA +cd "${DATA}" if [[ ${KEEPDATA:-NO} == "NO" ]]; then set -v diff --git a/versions/fix.nest.ver b/versions/fix.nest.ver deleted file mode 100644 index d08ea32af1..0000000000 --- a/versions/fix.nest.ver +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -# Fix file subfolder versions -export orog_ver=global-nest.20240419 -export ugwd_ver=global-nest.20240419 diff --git a/versions/fix.ver b/versions/fix.ver index 6b5ec7b670..1d54572c0b 100644 --- a/versions/fix.ver +++ b/versions/fix.ver @@ -21,3 +21,5 @@ export sfc_climo_ver=20220805 export ugwd_ver=20231027 export verif_ver=20220805 export wave_ver=20240105 +export orog_nest_ver=global-nest.20240419 +export ugwd_nest_ver=global-nest.20240419 diff --git a/versions/run.hera.ver b/versions/run.hera.ver index 6280e8e115..34f81bfe96 100644 --- a/versions/run.hera.ver +++ b/versions/run.hera.ver @@ -5,6 +5,7 @@ export spack_env=gsi-addon-dev-rocky8 export hpss_ver=hpss export ncl_ver=6.6.2 export R_ver=3.6.1 + export gempak_ver=7.17.0 export perl_ver=5.38.0 diff --git a/workflow/applications/applications.py b/workflow/applications/applications.py index 50a9a7cdd0..6a4d240fe5 100644 --- a/workflow/applications/applications.py +++ b/workflow/applications/applications.py @@ -51,6 +51,7 @@ def __init__(self, conf: Configuration) -> None: self.do_ocean = _base.get('DO_OCN', False) self.do_ice = _base.get('DO_ICE', False) self.do_aero = _base.get('DO_AERO', False) + self.do_prep_obs_aero = _base.get('DO_PREP_OBS_AERO', False) self.do_bufrsnd = _base.get('DO_BUFRSND', False) self.do_gempak = _base.get('DO_GEMPAK', False) self.do_awips = _base.get('DO_AWIPS', False) diff --git a/workflow/applications/gfs_cycled.py b/workflow/applications/gfs_cycled.py index 10ff6bb966..ab53b72885 100644 --- a/workflow/applications/gfs_cycled.py +++ b/workflow/applications/gfs_cycled.py @@ -108,6 +108,8 @@ def _get_app_configs(self): if self.do_aero: configs += ['aeroanlinit', 'aeroanlrun', 'aeroanlfinal'] + if self.do_prep_obs_aero: + configs += ['prepobsaero'] if self.do_jedisnowda: configs += ['prepsnowobs', 'snowanl'] @@ -178,6 +180,8 @@ def get_task_names(self): if self.do_aero and 'gdas' in self.aero_anl_cdumps: gdas_tasks += ['aeroanlinit', 'aeroanlrun', 'aeroanlfinal'] + if self.do_prep_obs_aero: + gdas_tasks += ['prepobsaero'] gdas_tasks += ['stage_ic', 'atmanlupp', 'atmanlprod', 'fcst'] @@ -215,6 +219,8 @@ def get_task_names(self): if self.do_aero and 'gfs' in self.aero_anl_cdumps: gfs_tasks += ['aeroanlinit', 'aeroanlrun', 'aeroanlfinal'] + if self.do_prep_obs_aero: + gfs_tasks += ['prepobsaero'] gfs_tasks += ['atmanlupp', 'atmanlprod', 'fcst'] diff --git a/workflow/rocoto/gefs_tasks.py b/workflow/rocoto/gefs_tasks.py index 31f70e4ce0..51c5d71bdb 100644 --- a/workflow/rocoto/gefs_tasks.py +++ b/workflow/rocoto/gefs_tasks.py @@ -1,6 +1,7 @@ from applications.applications import AppConfig from rocoto.tasks import Tasks import rocoto.rocoto as rocoto +from datetime import datetime, timedelta class GEFSTasks(Tasks): @@ -9,7 +10,6 @@ def __init__(self, app_config: AppConfig, cdump: str) -> None: super().__init__(app_config, cdump) def stage_ic(self): - cpl_ic = self._configs['stage_ic'] resources = self.get_resource('stage_ic') @@ -153,15 +153,17 @@ def ice_prod(self): def _atmosoceaniceprod(self, component: str): + fhout_ocn_gfs = self._configs['base']['FHOUT_OCN_GFS'] + fhout_ice_gfs = self._configs['base']['FHOUT_ICE_GFS'] products_dict = {'atmos': {'config': 'atmos_products', 'history_path_tmpl': 'COM_ATMOS_MASTER_TMPL', 'history_file_tmpl': f'{self.cdump}.t@Hz.master.grb2f#fhr#'}, 'ocean': {'config': 'oceanice_products', 'history_path_tmpl': 'COM_OCEAN_HISTORY_TMPL', - 'history_file_tmpl': f'{self.cdump}.ocean.t@Hz.6hr_avg.f#fhr#.nc'}, + 'history_file_tmpl': f'{self.cdump}.ocean.t@Hz.{fhout_ocn_gfs}hr_avg.f#fhr#.nc'}, 'ice': {'config': 'oceanice_products', 'history_path_tmpl': 'COM_ICE_HISTORY_TMPL', - 'history_file_tmpl': f'{self.cdump}.ice.t@Hz.6hr_avg.f#fhr#.nc'}} + 'history_file_tmpl': f'{self.cdump}.ice.t@Hz.{fhout_ice_gfs}hr_avg.f#fhr#.nc'}} component_dict = products_dict[component] config = component_dict['config'] @@ -173,14 +175,21 @@ def _atmosoceaniceprod(self, component: str): history_path = self._template_to_rocoto_cycstring(self._base[history_path_tmpl], {'MEMDIR': 'mem#member#'}) deps = [] data = f'{history_path}/{history_file_tmpl}' - dep_dict = {'type': 'data', 'data': data, 'age': 120} - deps.append(rocoto.add_dependency(dep_dict)) if component in ['ocean']: + dep_dict = {'type': 'data', 'data': data, 'age': 120} + deps.append(rocoto.add_dependency(dep_dict)) command = f"{self.HOMEgfs}/ush/check_netcdf.sh {history_path}/{history_file_tmpl}" dep_dict = {'type': 'sh', 'command': command} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep=deps, dep_condition='and') + elif component in ['ice']: + command = f"{self.HOMEgfs}/ush/check_ice_netcdf.sh @Y @m @d @H #fhr# &ROTDIR; #member# {fhout_ice_gfs}" + dep_dict = {'type': 'sh', 'command': command} + deps.append(rocoto.add_dependency(dep_dict)) + dependencies = rocoto.create_dependency(dep=deps) else: + dep_dict = {'type': 'data', 'data': data, 'age': 120} + deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep=deps) postenvars = self.envars.copy() @@ -202,10 +211,10 @@ def _atmosoceaniceprod(self, component: str): 'log': f'{self.rotdir}/logs/@Y@m@d@H/{task_name}.log', 'maxtries': '&MAXTRIES;'} - fhrs = self._get_forecast_hours('gefs', self._configs[config]) + fhrs = self._get_forecast_hours('gefs', self._configs[config], component) # ocean/ice components do not have fhr 0 as they are averaged output - if component in ['ocean', 'ice']: + if component in ['ocean', 'ice'] and 0 in fhrs: fhrs.remove(0) fhr_var_dict = {'fhr': ' '.join([f"{fhr:03d}" for fhr in fhrs])} diff --git a/workflow/rocoto/gfs_tasks.py b/workflow/rocoto/gfs_tasks.py index 3992dcd6ee..7e49ceb55e 100644 --- a/workflow/rocoto/gfs_tasks.py +++ b/workflow/rocoto/gfs_tasks.py @@ -434,10 +434,35 @@ def atmanlfinal(self): return task + def prepobsaero(self): + deps = [] + dep_dict = {'type': 'task', 'name': f'{self.cdump}prep'} + deps.append(rocoto.add_dependency(dep_dict)) + dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) + + resources = self.get_resource('prepobsaero') + task_name = f'{self.cdump}prepobsaero' + task_dict = {'task_name': task_name, + 'resources': resources, + 'dependency': dependencies, + 'envars': self.envars, + 'cycledef': self.cdump.replace('enkf', ''), + 'command': f'{self.HOMEgfs}/jobs/rocoto/prepobsaero.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 aeroanlinit(self): deps = [] dep_dict = {'type': 'task', 'name': f'{self.cdump}prep'} + if self.app_config.do_prep_obs_aero: + dep_dict = {'type': 'task', 'name': f'{self.cdump}prepobsaero'} deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) diff --git a/workflow/rocoto/tasks.py b/workflow/rocoto/tasks.py index 52d5466d10..ad135be713 100644 --- a/workflow/rocoto/tasks.py +++ b/workflow/rocoto/tasks.py @@ -130,10 +130,17 @@ def _get_forecast_hours(cdump, config, component='atmos') -> List[str]: # Ocean/Ice components do not have a HF output option like the atmosphere if component in ['ocean', 'ice']: - local_config['FHMAX_HF_GFS'] = config['FHMAX_GFS'] - local_config['FHOUT_HF_GFS'] = config['FHOUT_OCNICE_GFS'] - local_config['FHOUT_GFS'] = config['FHOUT_OCNICE_GFS'] - local_config['FHOUT'] = config['FHOUT_OCNICE'] + local_config['FHMAX_HF_GFS'] = 0 + + if component in ['ocean']: + local_config['FHOUT_HF_GFS'] = config['FHOUT_OCN_GFS'] + local_config['FHOUT_GFS'] = config['FHOUT_OCN_GFS'] + local_config['FHOUT'] = config['FHOUT_OCN'] + + if component in ['ice']: + local_config['FHOUT_HF_GFS'] = config['FHOUT_ICE_GFS'] + local_config['FHOUT_GFS'] = config['FHOUT_ICE_GFS'] + local_config['FHOUT'] = config['FHOUT_ICE'] fhmin = local_config['FHMIN'] @@ -152,7 +159,7 @@ def _get_forecast_hours(cdump, config, component='atmos') -> List[str]: fhrs = list(fhrs_hf) + list(range(fhrs_hf[-1] + fhout, fhmax + fhout, fhout)) # ocean/ice components do not have fhr 0 as they are averaged output - if component in ['ocean', 'ice']: + if component in ['ocean', 'ice'] and 0 in fhrs: fhrs.remove(0) return fhrs diff --git a/workflow/setup_expt.py b/workflow/setup_expt.py index 7234862f80..0952a51c95 100755 --- a/workflow/setup_expt.py +++ b/workflow/setup_expt.py @@ -58,6 +58,8 @@ def _update_defaults(dict_in: dict) -> dict: data = AttrDict(host.info, **inputs.__dict__) data.HOMEgfs = _top yaml_path = inputs.yaml + if not os.path.exists(yaml_path): + raise IOError(f'YAML file does not exist, check path:' + yaml_path) yaml_dict = _update_defaults(AttrDict(parse_j2yaml(yaml_path, data))) # First update config.base