diff --git a/.gitmodules b/.gitmodules index 5c9e569243..c80d24c03a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,6 @@ [submodule "sorc/ufs_model.fd"] path = sorc/ufs_model.fd url = https://github.com/ufs-community/ufs-weather-model - ignore = dirty [submodule "sorc/wxflow"] path = sorc/wxflow url = https://github.com/NOAA-EMC/wxflow diff --git a/parm/archive/enkf_restartb_grp.yaml.j2 b/parm/archive/enkf_restartb_grp.yaml.j2 index 7cd799f0a9..c7aaf6682e 100644 --- a/parm/archive/enkf_restartb_grp.yaml.j2 +++ b/parm/archive/enkf_restartb_grp.yaml.j2 @@ -27,8 +27,11 @@ enkf_restartb_grp: {% set r_dt = current_cycle | add_to_datetime(r_timedelta) %} {% set r_prefix = r_dt | to_YMD + "." + r_dt | strftime("%H") + "0000" %} {% for itile in range(1, 7) %} - {% for datatype in ["ca_data", "fv_core.res", "fv_srf_wnd.res", "fv_tracer.res", "phy_data", "sfc_data"] %} + {% for datatype in ["fv_core.res", "fv_srf_wnd.res", "fv_tracer.res", "phy_data", "sfc_data"] %} - "{{ COMIN_ATMOS_RESTART_MEM | relpath(ROTDIR) }}/{{ r_prefix }}.{{datatype}}.tile{{ itile }}.nc" + {% if DO_CA %} + - "{{ COMIN_ATMOS_RESTART_MEM | relpath(ROTDIR) }}/{{ r_prefix }}.ca_data.tile{{ itile }}.nc" + {% endif %} {% endfor %} {% endfor %} - "{{ COMIN_ATMOS_RESTART_MEM | relpath(ROTDIR) }}/{{ r_prefix }}.coupler.res" diff --git a/parm/archive/gdas_restartb.yaml.j2 b/parm/archive/gdas_restartb.yaml.j2 index 0bbf517fb2..620e0fb988 100644 --- a/parm/archive/gdas_restartb.yaml.j2 +++ b/parm/archive/gdas_restartb.yaml.j2 @@ -30,8 +30,11 @@ gdas_restartb: {% set r_HH = r_dt | strftime("%H") %} {% set r_prefix = r_YMD + "." + r_HH + "0000" %} {% for itile in range(1, 7) %} - {% for datatype in ["ca_data", "fv_core.res", "fv_srf_wnd.res", "fv_tracer.res", "phy_data", "sfc_data"] %} + {% for datatype in ["fv_core.res", "fv_srf_wnd.res", "fv_tracer.res", "phy_data", "sfc_data"] %} - "{{ COMIN_ATMOS_RESTART | relpath(ROTDIR) }}/{{ r_prefix }}.{{datatype}}.tile{{ itile }}.nc" + {% if DO_CA %} + - "{{ COMIN_ATMOS_RESTART | relpath(ROTDIR) }}/{{ r_prefix }}.ca_data.tile{{ itile }}.nc" + {% endif %} {% endfor %} {% endfor %} - "{{ COMIN_ATMOS_RESTART | relpath(ROTDIR) }}/{{ r_prefix }}.coupler.res" diff --git a/parm/config/gefs/config.base b/parm/config/gefs/config.base index 65bca1b377..2bafde04f5 100644 --- a/parm/config/gefs/config.base +++ b/parm/config/gefs/config.base @@ -287,10 +287,17 @@ export DO_MERGENSST="NO" export NMEM_ENS=@NMEM_ENS@ # set default member number memdir for control -# this will be overwritten for the perturbed members +# this will be overwridden for the perturbed members export ENSMEM=${ENSMEM:-"000"} export MEMDIR="mem${ENSMEM}" +# cellular automata +if (( ENSMEM == 0 )); then + export DO_CA="YES" +else + export DO_CA="YES" +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 warm starting with IAU diff --git a/parm/config/gefs/config.efcs b/parm/config/gefs/config.efcs index 6bf0ed0a18..d1f7f7f714 100644 --- a/parm/config/gefs/config.efcs +++ b/parm/config/gefs/config.efcs @@ -44,16 +44,18 @@ export SPPT_TAU="2.16E4,2.592E5,2.592E6,7.776E6,3.1536E7" export SPPT_LSCALE="500.E3,1000.E3,2000.E3,2000.E3,2000.E3" export SPPT_LOGIT=".true." export SPPT_SFCLIMIT=".true." -export DO_CA="YES" # OCN options -export DO_OCN_SPPT="YES" -export OCNSPPT="0.8,0.4,0.2,0.08,0.04" -export OCNSPPT_TAU="2.16E4,2.592E5,2.592E6,7.776E6,3.1536E7" -export OCNSPPT_LSCALE="500.E3,1000.E3,2000.E3,2000.E3,2000.E3" -export DO_OCN_PERT_EPBL="YES" -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 (( OCNRES <= 100 )); then + # Ocean stochastic options not supported at 5p00 + export DO_OCN_SPPT="YES" + export OCNSPPT="0.8,0.4,0.2,0.08,0.04" + export OCNSPPT_TAU="2.16E4,2.592E5,2.592E6,7.776E6,3.1536E7" + export OCNSPPT_LSCALE="500.E3,1000.E3,2000.E3,2000.E3,2000.E3" + export DO_OCN_PERT_EPBL="YES" + 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" +fi if [[ "${REPLAY_ICS:-NO}" == "YES" ]]; then export ODA_INCUPD="True" diff --git a/parm/config/gefs/config.fcst b/parm/config/gefs/config.fcst index 0461c7e909..d57e7e9e92 100644 --- a/parm/config/gefs/config.fcst +++ b/parm/config/gefs/config.fcst @@ -225,11 +225,12 @@ case ${imp_physics} in esac # Stochastic physics -export DO_SPPT=${DO_SPPT:-"NO"} -export DO_SKEB=${DO_SKEB:-"NO"} -export DO_SHUM=${DO_SHUM:-"NO"} -export DO_LAND_PERT=${DO_LAND_PERT:-"NO"} -export DO_CA=${DO_CA:-"YES"} +export DO_SPPT="NO" +export DO_SKEB="NO" +export DO_SHUM="NO" +export DO_LAND_PERT="NO" +export DO_OCN_SPPT="NO" +export DO_OCN_PERT_EPBL="NO" #coupling settings export cplmode="ufs.frac" diff --git a/parm/config/gfs/config.base b/parm/config/gfs/config.base index 46e27b4541..8e54bc321c 100644 --- a/parm/config/gfs/config.base +++ b/parm/config/gfs/config.base @@ -460,6 +460,9 @@ export INCVARS_EFOLD="5" export netcdf_diag=".true." export binary_diag=".false." +# Cellular automata +export DO_CA="YES" + # Verification options export DO_METP="@DO_METP@" # Run METPLUS jobs - set METPLUS settings in config.metp export DO_FIT2OBS="YES" # Run fit to observations package diff --git a/parm/config/gfs/config.fcst b/parm/config/gfs/config.fcst index b154d37114..c95f8796e5 100644 --- a/parm/config/gfs/config.fcst +++ b/parm/config/gfs/config.fcst @@ -245,14 +245,12 @@ case ${imp_physics} in esac # Stochastic physics -export DO_SPPT=${DO_SPPT:-"NO"} -export DO_SKEB=${DO_SKEB:-"NO"} -export DO_SHUM=${DO_SHUM:-"NO"} -export DO_LAND_PERT=${DO_LAND_PERT:-"NO"} -export DO_CA=${DO_CA:-"YES"} -if [[ "${DO_NEST:-NO}" == "YES" ]] ; then - export DO_CA="NO" # CA does not work with nesting. -fi +export DO_SPPT="NO" +export DO_SKEB="NO" +export DO_SHUM="NO" +export DO_LAND_PERT="NO" +export DO_OCN_SPPT="NO" +export DO_OCN_PERT_EPBL="NO" #coupling settings export cplmode="ufs.frac" diff --git a/parm/stage/atmosphere_nest.yaml.j2 b/parm/stage/atmosphere_nest.yaml.j2 index 13ec0ed8c5..d86942c1ba 100644 --- a/parm/stage/atmosphere_nest.yaml.j2 +++ b/parm/stage/atmosphere_nest.yaml.j2 @@ -11,8 +11,11 @@ atmosphere_nest: {% for mem in range(first_mem, last_mem + 1) %} {% set imem = mem - first_mem %} {% set COMOUT_ATMOS_RESTART_PREV_MEM = COMOUT_ATMOS_RESTART_PREV_MEM_list[imem] %} - {% for ftype in ["ca_data", "fv_core.res", "fv_srf_wnd.res", "fv_tracer.res", "phy_data", "sfc_data"] %} + {% for ftype in ["fv_core.res", "fv_srf_wnd.res", "fv_tracer.res", "phy_data", "sfc_data"] %} - ["{{ ICSDIR }}/{{ COMOUT_ATMOS_RESTART_PREV_MEM | relpath(ROTDIR) }}/{{ m_prefix }}.{{ ftype }}.tile{{ ntile }}.nc", "{{ COMOUT_ATMOS_RESTART_PREV_MEM }}/{{ m_prefix }}.{{ ftype }}.nest0{{ ntile-5 }}.tile{{ ntile }}.nc"] + {% if DO_CA %} + - ["{{ ICSDIR }}/{{ COMOUT_ATMOS_RESTART_PREV_MEM | relpath(ROTDIR) }}/{{ m_prefix }}.ca_data.tile{{ ntile }}.nc", "{{ COMOUT_ATMOS_RESTART_PREV_MEM }}/{{ m_prefix }}.ca_data.nest0{{ ntile-5 }}.tile{{ ntile }}.nc"] + {% endif %} {% endfor %} {% endfor %} # mem loop {% else %} # cold start diff --git a/parm/stage/atmosphere_warm.yaml.j2 b/parm/stage/atmosphere_warm.yaml.j2 index 14c8615262..44d6d78e30 100644 --- a/parm/stage/atmosphere_warm.yaml.j2 +++ b/parm/stage/atmosphere_warm.yaml.j2 @@ -15,9 +15,12 @@ atmosphere_warm: {% for ftype in ["coupler.res", "fv_core.res.nc"] %} - ["{{ ICSDIR }}/{{ COMOUT_ATMOS_RESTART_PREV_MEM | relpath(ROTDIR) }}/{{ m_prefix }}.{{ ftype }}", "{{ COMOUT_ATMOS_RESTART_PREV_MEM }}"] {% endfor %} - {% for ftype in ["ca_data", "fv_core.res", "fv_srf_wnd.res", "fv_tracer.res", "phy_data", "sfc_data"] %} + {% for ftype in ["fv_core.res", "fv_srf_wnd.res", "fv_tracer.res", "phy_data", "sfc_data"] %} {% for ntile in range(1, ntiles + 1) %} - ["{{ ICSDIR }}/{{ COMOUT_ATMOS_RESTART_PREV_MEM | relpath(ROTDIR) }}/{{ m_prefix }}.{{ ftype }}.tile{{ ntile }}.nc", "{{ COMOUT_ATMOS_RESTART_PREV_MEM }}"] + {% if DO_CA %} + - ["{{ ICSDIR }}/{{ COMOUT_ATMOS_RESTART_PREV_MEM | relpath(ROTDIR) }}/{{ m_prefix }}.ca_data.tile{{ ntile }}.nc", "{{ COMOUT_ATMOS_RESTART_PREV_MEM }}"] + {% endif %} {% endfor %} # ntile {% endfor %} # ftype {% for ntile in range(1, ntiles + 1) %} diff --git a/scripts/exgdas_enkf_earc.py b/scripts/exgdas_enkf_earc.py index c724bdbd67..467cfa88dc 100755 --- a/scripts/exgdas_enkf_earc.py +++ b/scripts/exgdas_enkf_earc.py @@ -25,7 +25,7 @@ def main(): 'lobsdiag_forenkf', 'FHMIN_ENKF', 'FHMAX_ENKF_GFS', 'FHOUT_ENKF_GFS', 'FHMAX_ENKF', 'FHOUT_ENKF', 'ENKF_SPREAD', 'restart_interval_enkfgdas', 'restart_interval_enkfgfs', - 'DOHYBVAR', 'DOIAU_ENKF', 'IAU_OFFSET', 'DOIAU', + 'DOHYBVAR', 'DOIAU_ENKF', 'IAU_OFFSET', 'DOIAU', 'DO_CA', 'DO_CALC_INCREMENT', 'assim_freq', 'ARCH_CYC', 'ARCH_WARMICFREQ', 'ARCH_FCSTICFREQ', 'IAUFHRS_ENKF', 'NET'] diff --git a/scripts/exglobal_archive.py b/scripts/exglobal_archive.py index 2d3fa58313..6998831366 100755 --- a/scripts/exglobal_archive.py +++ b/scripts/exglobal_archive.py @@ -29,7 +29,7 @@ def main(): 'DOIAU', 'OCNRES', 'ICERES', 'NUM_SND_COLLECTIVES', 'FHOUT_WAV', 'FHOUT_HF_WAV', 'FHMAX_WAV', 'FHMAX_HF_WAV', 'FHMAX_WAV_GFS', 'restart_interval_gdas', 'restart_interval_gfs', - 'DO_AERO_ANL', 'DO_AERO_FCST', 'DOIBP_WAV', 'DO_JEDIOCNVAR', + 'DO_AERO_ANL', 'DO_AERO_FCST', 'DO_CA', 'DOIBP_WAV', 'DO_JEDIOCNVAR', 'NMEM_ENS', 'DO_JEDIATMVAR', 'DO_VRFY_OCEANDA', 'FHMAX_FITS', 'waveGRD', 'IAUFHRS', 'DO_FIT2OBS', 'NET', 'FHOUT_HF_GFS', 'FHMAX_HF_GFS', 'REPLAY_ICS', 'OFFSET_START_HOUR'] diff --git a/scripts/exglobal_stage_ic.py b/scripts/exglobal_stage_ic.py index 1a49c4f64d..9d74d227fc 100755 --- a/scripts/exglobal_stage_ic.py +++ b/scripts/exglobal_stage_ic.py @@ -22,7 +22,7 @@ def main(): 'assim_freq', 'current_cycle', 'previous_cycle', 'ROTDIR', 'ICSDIR', 'STAGE_IC_YAML_TMPL', 'DO_JEDIATMVAR', 'OCNRES', 'waveGRD', 'ntiles', 'DOIAU', 'DO_JEDIOCNVAR', - 'REPLAY_ICS', 'DO_WAVE', 'DO_OCN', 'DO_ICE', 'DO_NEST', + 'REPLAY_ICS', 'DO_WAVE', 'DO_OCN', 'DO_ICE', 'DO_NEST', 'DO_CA', 'USE_ATM_ENS_PERTURB_FILES', 'USE_OCN_ENS_PERTURB_FILES'] stage_dict = AttrDict() diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index aade469ddc..532e0bb883 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -47,7 +47,19 @@ FV3_postdet() { || ( echo "FATAL ERROR: Unable to copy FV3 IC, ABORT!"; exit 1 ) done - if [[ "${RERUN}" != "YES" ]]; then + if [[ "${RERUN}" == "YES" ]]; then + if [[ "${DO_SPPT:-}" == "YES" || "${DO_SKEB:-}" == "YES" || \ + "${DO_SHUM:-}" == "YES" || "${DO_LAND_PERT:-}" == "YES" ]]; then + stochini=".true." + file_list=$(stoch_restarts) + echo "Copying stochastic restarts for 'RUN=${RUN}' at '${restart_date}' from '${restart_dir}'" + for stoch_file in $(stoch_restarts); do + restart_file="${restart_date:0:8}.${restart_date:8:2}0000.${stoch_file}" + ${NCP} "${restart_dir}/${restart_file}" "${DATA}/INPUT/${stoch_file}" \ + || ( echo "FATAL ERROR: Unable to copy stochastic restart, ABORT!"; exit 1 ) + done + fi + else # Replace sfc_data with sfcanl_data restart files from current cycle (if found) local nn for (( nn = 1; nn <= ntiles; nn++ )); do @@ -78,7 +90,7 @@ FV3_postdet() { "${DATA}/INPUT/fv_tracer.res.tile${nn}.nc" done fi # if [[ ${use_anl_aero} == "YES" ]]; then - fi # if [[ "${RERUN}" != "YES" ]]; then + fi # if [[ "${RERUN}" == "YES" ]]; then fi # if [[ "${warm_start}" == ".true." ]]; then diff --git a/ush/forecast_predet.sh b/ush/forecast_predet.sh index 3c3dd719ef..59afe483ea 100755 --- a/ush/forecast_predet.sh +++ b/ush/forecast_predet.sh @@ -57,7 +57,10 @@ FV3_restarts(){ # 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) + tile_files=(fv_core.res fv_srf_wnd.res fv_tracer.res phy_data sfc_data) + if [[ ${DO_CA:-"NO"} == "YES" ]]; then + tile_files+=(ca_data) + fi local nn tt for (( nn = 1; nn <= ntiles; nn++ )); do for tt in "${tile_files[@]}"; do @@ -68,6 +71,22 @@ FV3_restarts(){ IFS=, echo "${fv3_restart_files[*]}" } +stoch_restarts(){ + # These only get copied for reruns + local stoch_restart_files + stoch_restart_files=( ) + + if [[ "${DO_SPPT:-}" == "YES" || "${DO_SKEB:-}" == "YES" || \ + "${DO_SHUM:-}" == "YES" || "${DO_LAND_PERT:-}" == "YES" ]]; then + stoch_restart_files+=(atm_stoch.res.nc) + fi + if [[ "${DO_OCN:-}" == "YES" && ( "${DO_OCN_SPPT:-}" == "YES" || "${DO_OCN_PERT_EPBL}" == "YES" ) ]]; then + stoch_restart_files+=(ocn_stoch.res.nc) + fi + # Create a comma separated string from array using IFS + IFS=, echo "${stoch_restart_files[*]}" +} + # shellcheck disable=SC2034 common_predet(){ echo "SUB ${FUNCNAME[0]}: Defining variables for shared through model components" @@ -377,41 +396,38 @@ FV3_predet(){ do_sppt=".false." do_ca=".false." ISEED=0 - if (( MEMBER > 0 )); then # these are only applicable for ensemble members - local imem=${MEMBER#0} - local base_seed=$((current_cycle*10000 + imem*100)) - - if [[ "${DO_SKEB:-}" == "YES" ]]; then - do_skeb=".true." - ISEED_SKEB=$((base_seed + 1)) - fi + local imem=${MEMBER#0} + local base_seed=$((current_cycle*10000 + imem*100)) - if [[ "${DO_SHUM:-}" == "YES" ]]; then - do_shum=".true." - ISEED_SHUM=$((base_seed + 2)) - fi + if [[ "${DO_SKEB:-}" == "YES" ]]; then + do_skeb=".true." + ISEED_SKEB=$((base_seed + 1)) + fi - if [[ "${DO_SPPT:-}" == "YES" ]]; then - do_sppt=".true." - ISEED_SPPT=$((base_seed + 3)),$((base_seed + 4)),$((base_seed + 5)),$((base_seed + 6)),$((base_seed + 7)) - fi + if [[ "${DO_SHUM:-}" == "YES" ]]; then + do_shum=".true." + ISEED_SHUM=$((base_seed + 2)) + fi - if [[ "${DO_CA:-}" == "YES" ]]; then - do_ca=".true." - ISEED_CA=$(( (base_seed + 18) % 2147483647 )) - fi + if [[ "${DO_SPPT:-}" == "YES" ]]; then + do_sppt=".true." + ISEED_SPPT=$((base_seed + 3)),$((base_seed + 4)),$((base_seed + 5)),$((base_seed + 6)),$((base_seed + 7)) + fi - if [[ "${DO_LAND_PERT:-}" == "YES" ]]; then - lndp_type=${lndp_type:-2} - ISEED_LNDP=$(( (base_seed + 5) % 2147483647 )) - LNDP_TAU=${LNDP_TAU:-21600} - LNDP_SCALE=${LNDP_SCALE:-500000} - lndp_var_list=${lndp_var_list:-"'smc', 'vgf',"} - lndp_prt_list=${lndp_prt_list:-"0.2,0.1"} - n_var_lndp=$(echo "${lndp_var_list}" | wc -w) - fi + if [[ "${DO_CA:-}" == "YES" ]]; then + do_ca=".true." + ISEED_CA=$(( (base_seed + 18) % 2147483647 )) + fi - fi # end of ensemble member specific options + if [[ "${DO_LAND_PERT:-}" == "YES" ]]; then + lndp_type=${lndp_type:-2} + ISEED_LNDP=$(( (base_seed + 5) % 2147483647 )) + LNDP_TAU=${LNDP_TAU:-21600} + LNDP_SCALE=${LNDP_SCALE:-500000} + lndp_var_list=${lndp_var_list:-"'smc', 'vgf',"} + lndp_prt_list=${lndp_prt_list:-"0.2,0.1"} + n_var_lndp=$(echo "${lndp_var_list}" | wc -w) + fi #-------------------------------------------------------------------------- @@ -680,17 +696,15 @@ MOM6_predet(){ # If using stochastic parameterizations, create a seed that does not exceed the # largest signed integer - if (( MEMBER > 0 )); then # these are only applicable for ensemble members - local imem=${MEMBER#0} - local base_seed=$((current_cycle*10000 + imem*100)) + local imem=${MEMBER#0} + local base_seed=$((current_cycle*10000 + imem*100)) - if [[ "${DO_OCN_SPPT:-}" == "YES" ]]; then - ISEED_OCNSPPT=$((base_seed + 8)),$((base_seed + 9)),$((base_seed + 10)),$((base_seed + 11)),$((base_seed + 12)) - fi + if [[ "${DO_OCN_SPPT:-}" == "YES" ]]; then + ISEED_OCNSPPT=$((base_seed + 8)),$((base_seed + 9)),$((base_seed + 10)),$((base_seed + 11)),$((base_seed + 12)) + fi - if [[ "${DO_OCN_PERT_EPBL:-}" == "YES" ]]; then - ISEED_EPBL=$((base_seed + 13)),$((base_seed + 14)),$((base_seed + 15)),$((base_seed + 16)),$((base_seed + 17)) - fi + if [[ "${DO_OCN_PERT_EPBL:-}" == "YES" ]]; then + ISEED_EPBL=$((base_seed + 13)),$((base_seed + 14)),$((base_seed + 15)),$((base_seed + 16)),$((base_seed + 17)) fi # Fix files diff --git a/ush/parsing_namelists_FV3.sh b/ush/parsing_namelists_FV3.sh index 9279b284f8..bb6a204cc8 100755 --- a/ush/parsing_namelists_FV3.sh +++ b/ush/parsing_namelists_FV3.sh @@ -656,6 +656,7 @@ if [[ "${DO_SPPT}" = "YES" || "${DO_SHUM}" = "YES" || "${DO_SKEB}" = "YES" || "$ cat >> input.nml << EOF &nam_stochy + stochini=${stochini:-".false."} EOF if [[ ${DO_SKEB} = "YES" ]]; then