Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,9 @@ versions/run.ver

# jcb checkout and symlinks
ush/python/jcb


specs/
.specify/
.github/agents/
.github/prompts/
69 changes: 69 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Changelog

All notable changes to global-workflow will be documented in this file.

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- CATChem interactive atmospheric chemistry for GCAFS via a new `APP=ATMC`
option (atmosphere + CATChem), mirroring the existing `ATMA`
(atmosphere + GOCART) forecast-only workflow:
- `dev/workflow/setup_expt.py` accepts `--app ATMC` for GCAFS.
- `dev/parm/config/gcafs/config.base.j2` recognizes `ATMC`, exports a
`CHEM_MODEL` selector (`none`/`gocart`/`catchem`), and widens the EnKF
APP suffix strip to `+([WAC])`.
- `dev/parm/config/gcafs/config.aero.j2` adds `CATCHEM_CONFIG` (default
`gcafs_aero`) and `CATCHEM_CONFIG_DIR`, mirroring `NEXUS_CONFIG`.
- `dev/parm/config/gcafs/config.fcst.j2` passes `--catchem` to `config.ufs`
and selects `FCSTEXEC="ufs_model_gcafs_catchem.x"` when
`CHEM_MODEL="catchem"`.
- `dev/parm/config/gcafs/config.ufs` parses `--catchem`, setting
`cplchm=".true."`, `cplcat=".true."`, and `chm_model="catchem"` while
reusing the `ufs.configure.atmaero` template.
- `ush/parsing_ufs_configure.sh` renders `chm_model`/`cplcat` into the UFS
configure file; `ush/parsing_namelists_fv3.sh` renders `cplcat` into
`global_control.nml`.
- `ush/forecast_predet.sh` and `ush/forecast_postdet.sh` gain
`CATCHEM_predet`, `CATCHEM_rc`, `CATCHEM_postdet`, and `CATCHEM_out`:
the CATChem runtime YAML set (`CATChem_config/species/emissions/
field_mapping_${CATCHEM_CONFIG}.yaml`) is copied and renamed into `DATA`
under the fixed names the CATChem NUOPC cap expects
(`CATChem_new_config.yml`, `CATChem_species.yml`, `CATChem_emission.yml`,
`CATChem_field_mapping.yml`), `ExtData` is linked from
`AERO_INPUTS_DIR`, and `catchem*` diagnostics are copied to
`$COM/model/chem/history`.
- `dev/scripts/exglobal_forecast.sh` branches the chemistry steps onto the
CATChem functions when `cplcat=".true."`.
- `parm/archive/chem.yaml.j2` archives `{{ CHEM_MODEL }}*` history and
`parm/archive/master_gcafs.yaml.j2` includes the `chem` tarball for
`CHEM_MODEL == "catchem"` (GCAFS ATMA archiving is unchanged).
- `dev/scripts/exgfs_aero_init_aerosol.py` uses
`parm/chem/catchem/catchem_tracer.list` when `CHEM_MODEL == "catchem"`.
- `dev/scripts/exglobal_prep_emissions.py` validates the selected CATChem
emissions configuration set when `CHEM_MODEL == "catchem"`.
- Build support: `sorc/build_opts.yaml` adds the `gcafs_catchem_model`
entry (`./build_ufs.sh -a CATCHEM -e gcafs_catchem_model.x`) to the GCAFS
system; `sorc/build_ufs.sh` registers the `COMPILE_ID`;
`sorc/link_workflow.sh` links `exec/ufs_model_gcafs_catchem.x`.
- Docs: `docs/source/user_guide/setup.rst`, `gcafs.rst`, and `clone.rst`
describe the `ATMC` option.
- CI: `dev/ci/cases/pr/C96_gcafs_catchem_cycled.yaml` adds an `APP=ATMC`
cycled GCAFS case (modeled on `C96_gcafs_cycled_noDA.yaml`), registered
in the hera/gaeac6/ursa/derecho matrices of `dev/ci/gitlab-ci-hosts.yml`.

### Changed

- `sorc/ufs_model.fd` pinned to ufs-weather-model
`6dc36481b6d1347f3c5332905ad48e7e9da8675e`, the first revision exposing the
`CATCHEM` application (`-DAPP=CATCHEM`) and the `cplcat` entry in
`global_control.nml.IN`.

### Compatibility

- No behavior change for existing `APP=ATMA`/`ATM`/`S2S*` configurations: the
GOCART code paths, GCAFS archive contents, and NEXUS/fire emissions
preprocessing are untouched; all new logic is gated on `APP=ATMC` /
`CHEM_MODEL=="catchem"` / `cplcat==".true."`.
23 changes: 23 additions & 0 deletions dev/ci/cases/gcafsv1/C96_gcafs_cycled_noDA_dev_catchem.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
experiment:
net: gcafs
mode: cycled
pslot: {{ 'pslot' | getenv }}
app: ATMC
resdetatmos: 96
comroot: {{ 'RUNTESTS' | getenv }}/COMROOT
expdir: {{ 'RUNTESTS' | getenv }}/EXPDIR
icsdir: {{ BASE_IC }}/C96C48/20250808
idate: 2021122012
edate: 2021122200
nens: 0
interval: 0
start: cold
yaml: {{ HOMEglobal }}/dev/ci/cases/yamls/gcafs_cycled_noDA_defaults_dev.yaml

workflow:
engine: rocoto
rocoto:
maxtries: 2
cyclethrottle: 3
taskthrottle: 25
verbosity: 2
28 changes: 28 additions & 0 deletions dev/ci/cases/pr/C96_gcafs_catchem_cycled.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
experiment:
net: gcafs
mode: cycled
pslot: {{ 'pslot' | getenv }}
app: ATMC
resdetatmos: 96
comroot: {{ 'RUNTESTS' | getenv }}/COMROOT
expdir: {{ 'RUNTESTS' | getenv }}/EXPDIR
icsdir: {{ BASE_IC }}/C96C48/20250808
idate: 2021122012
edate: 2021122100
nens: 0
interval: 12
start: cold
yaml: {{ HOMEglobal }}/dev/ci/cases/yamls/gcafs_cycled_noDA_defaults_ci.yaml

skip_ci_on_hosts:
- orion
- hercules
- awsepicglobalworkflow

workflow:
engine: rocoto
rocoto:
maxtries: 2
cyclethrottle: 3
taskthrottle: 25
verbosity: 2
18 changes: 17 additions & 1 deletion dev/parm/config/gcafs/config.base.j2
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ shopt -s extglob
# If a component (WAVES, etc) needs to be turned off by RUN, set it here
case "${RUN}" in
enkf*) # Turn off aerosols and waves
APP="${APP/%+([WA])}"
APP="${APP/%+([WAC])}"
;;
*) # Keep app unchanged
;;
Expand Down Expand Up @@ -234,6 +234,9 @@ case "${APP}" in
ATMA)
DO_AERO="YES"
;;
ATMC) # Atmosphere + CATChem interactive chemistry
DO_AERO="YES"
;;
ATMW)
export DO_COUPLED="YES"
export DO_WAVE="YES"
Expand Down Expand Up @@ -262,6 +265,19 @@ case "${APP}" in
;;
esac

# Chemistry model selector: none (default), gocart (ATM*A apps), catchem (ATMC)
case "${APP}" in
ATMC)
export CHEM_MODEL="catchem"
;;
*A)
export CHEM_MODEL="gocart"
;;
*)
export CHEM_MODEL="none"
;;
esac

# Aerosol forecasts and analyses may be RUN-dependent
if [[ "${DO_AERO}" == "YES" ]]; then
if [[ ${aero_anl_runs} =~ ${RUN} ]]; then
Expand Down
12 changes: 10 additions & 2 deletions dev/parm/config/gcafs/config.fcst.j2
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ if [[ "${DO_WAVE}" == "YES" ]]; then
string="${string} --ww3 ${waveGRD}"
fi
if [[ "${DO_AERO_FCST}" == "YES" ]]; then
string="${string} --gocart"
if [[ "${CHEM_MODEL}" == "catchem" ]]; then
string="${string} --catchem"
else
string="${string} --gocart"
fi
fi
# We are counting on $string being multiple arguments
# shellcheck disable=SC2086
Expand Down Expand Up @@ -78,7 +82,11 @@ export esmf_logkind="ESMF_LOGKIND_MULTI_ON_ERROR" #Options: ESMF_LOGKIND_MULTI_O

export FORECASTSH="${SCRglobal}/exglobal_forecast.sh"
#export FORECASTSH="${SCRglobal}/exglobal_forecast.py" # Temp. while this is worked on
export FCSTEXEC="ufs_model_gcafs.x"
if [[ "${CHEM_MODEL}" == "catchem" ]]; then
export FCSTEXEC="ufs_model_gcafs_catchem.x"
else
export FCSTEXEC="ufs_model_gcafs.x"
fi

#######################################################################
# Model configuration
Expand Down
20 changes: 18 additions & 2 deletions dev/parm/config/gfs/config.aero.j2
Original file line number Diff line number Diff line change
Expand Up @@ -228,5 +228,21 @@ export NEXUS_DO_CAMS=.false. # Use CAMS global emissions
# Enables time-varying scaling when CAMS is active.
export NEXUS_DO_CAMSTEMPO=.true. # Use CAMS temporal emissions

#================================================================================
echo "END: config.aero"
#================================================================================# 4. CATChem settings
#===============================================================================
# CATChem is an interactive atmospheric chemistry model coupled to FV3 through
# its own NUOPC cap (chm_model='catchem'). Runtime configuration is provided as
# a set of four YAML files (config, species, emissions, field mapping) that are
# staged into the DATA directory under fixed names before the forecast runs.

# CATChem configuration set (selects the *_<CATCHEM_CONFIG>.yaml bundle under
# parm/chem/catchem). Options: gcafs_aero (default)
#---------------------------------------------------------------------------------------------------
export CATCHEM_CONFIG="{{ CATCHEM_CONFIG | default('gcafs_aero') }}"

# Directory containing the CATChem runtime YAML sets. The selected config set is
# resolved by filename suffix, e.g. CATChem_config_${CATCHEM_CONFIG}.yaml.
#---------------------------------------------------------------------------------------------------
export CATCHEM_CONFIG_DIR="${PARMglobal}/chem/catchem"

#===============================================================================echo "END: config.aero"
17 changes: 17 additions & 0 deletions dev/parm/config/gfs/config.ufs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ if (( $# <= 1 )); then
echo "--cice6 500|100|025"
echo "--ww3 gwes_30m|glo_025|glo_100|glo_200|glo_500|mx025|uglo_100km"
echo "--gocart"
echo "--catchem"

exit 1

Expand All @@ -27,6 +28,7 @@ skip_mom6=true
skip_cice6=true
skip_ww3=true
skip_gocart=true
skip_catchem=true
skip_mediator=true

# Loop through named arguments
Expand Down Expand Up @@ -55,6 +57,9 @@ while (( $# > 0 )); do
"--gocart")
skip_gocart=false
;;
"--catchem")
skip_catchem=false
;;
*) # unknown option
echo "FATAL ERROR: Unknown option: ${key}, ABORT!"
exit 1
Expand Down Expand Up @@ -648,6 +653,18 @@ if [[ "${skip_gocart}" == "false" ]]; then
model_list="${model_list}.aero"
fi

# CATChem specific settings
# CATChem couples through its own NUOPC cap (chm_model='catchem') but reuses the
# atmaero configure template: cplcat=true implies cplchm=true (the chemistry PETs
# are the same as the GOCART/aerosol PETs), so the model_list suffix stays .aero.
if [[ "${skip_catchem}" == "false" ]]; then
source "${EXPDIR}/config.aero"
export cplchm=".true."
export cplcat=".true."
export chm_model="catchem"
model_list="${model_list}.aero"
fi

# Set the name of the UFS (previously nems) configure template to use
# Default ufs.configure templates for supported model configurations
# WW3 restart field variable is different for slow vs fast loop. Add WW3_RSTFLDS="ice" for slow loop variables based on coupling scheme.
Expand Down
9 changes: 7 additions & 2 deletions dev/scripts/exgfs_aero_init_aerosol.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@
tracer_file_pattern = "{file_base}/{timestamp}fv_tracer.res.{tile}.nc"
# Name of restart dycore file (time when restart is valid)
dycore_file_pattern = "{file_base}/{timestamp}fv_core.res.nc"
# Text list of tracer names to copy
# Text list of tracer names to copy (selected from CHEM_MODEL at runtime)
tracer_list_file_pattern = "{parm_gfs}/ufs/gocart/gocart_tracer.list"
catchem_tracer_list_file_pattern = "{parm_gfs}/chem/catchem/catchem_tracer.list"
merge_script_pattern = "{ush_gfs}/merge_fv3_aerosol_tile.py"
n_tiles = 6
# Maximum number of past cycles to look for for tracer data
Expand All @@ -84,11 +85,15 @@ def main() -> None:
rot_dir = get_env_var("ROTDIR")
ush_gfs = get_env_var("USHglobal")
parm_gfs = get_env_var("PARMglobal")
chem_model = get_env_var("CHEM_MODEL", fail_on_missing=False) or "none"

# os.chdir(data)

merge_script = merge_script_pattern.format(ush_gfs=ush_gfs)
tracer_list_file = tracer_list_file_pattern.format(parm_gfs=parm_gfs)
if chem_model == "catchem":
tracer_list_file = catchem_tracer_list_file_pattern.format(parm_gfs=parm_gfs)
else:
tracer_list_file = tracer_list_file_pattern.format(parm_gfs=parm_gfs)

time = datetime.strptime(f"{pdy}{cyc}", "%Y%m%d%H")
atm_source_path = time.strftime(atm_base_pattern.format(**locals()))
Expand Down
25 changes: 21 additions & 4 deletions dev/scripts/exglobal_forecast.sh
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ cpl=${cpl:-.false.}
cplflx=${cplflx:-.false.} # default off,import from outside source
cplwav=${cplwav:-.false.} # ? how to control 1-way/2-way?
cplchm=${cplchm:-.false.} # Chemistry model
cplcat=${cplcat:-.false.} # CATChem interactive chemistry model
cplice=${cplice:-.false.} # ICE model

OCNTIM=${OCNTIM:-1800}
Expand Down Expand Up @@ -122,7 +123,11 @@ if [[ "${cplice}" == ".true." ]]; then
CICE_predet
fi
if [[ "${cplchm}" == ".true." ]]; then
GOCART_predet
if [[ "${cplcat}" == ".true." ]]; then
CATCHEM_predet
else
GOCART_predet
fi
fi
echo "MAIN: Variables before determination of run type loaded"

Expand All @@ -145,7 +150,11 @@ if [[ "${cplice}" == ".true." ]]; then
CICE_postdet
fi
if [[ "${cplchm}" == ".true." ]]; then
GOCART_postdet
if [[ "${cplcat}" == ".true." ]]; then
CATCHEM_postdet
else
GOCART_postdet
fi
fi
echo "MAIN: Post-determination set up of run type finished"

Expand All @@ -161,7 +170,11 @@ if [[ "${cplice}" == ".true." ]]; then
CICE_nml
fi
if [[ "${cplchm}" == ".true." ]]; then
GOCART_rc
if [[ "${cplcat}" == ".true." ]]; then
CATCHEM_rc
else
GOCART_rc
fi
fi
UFS_configure
echo "MAIN: Name lists and model configuration written"
Expand Down Expand Up @@ -202,7 +215,11 @@ if [[ "${cplice}" == ".true." ]]; then
CICE_out
fi
if [[ "${cplchm}" == ".true." ]]; then
GOCART_out
if [[ "${cplcat}" == ".true." ]]; then
CATCHEM_out
else
GOCART_out
fi
fi
if [[ "${esmf_profile:-}" == ".true." ]]; then
CPL_out
Expand Down
Loading
Loading