Skip to content
Merged
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
190 changes: 190 additions & 0 deletions examples/post.v3.eamxx.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Example: EAMxx → CMIP and e3sm_diags, initially contributed by Shixuan Zhang.
# Reproduces the cfg from issue #820 plus e3sm_diags-related tasks.
# (https://github.com/E3SM-Project/zppy/issues/820)
#
# Demonstrates:
# - EAMxx CMORization end-to-end (issue #817)
# - The fix to the fragile component-detection gate (now uses prc_typ),
# so input_component="eamxx" with input_files="AVERAGE.nmonths_x1" works
# - EAMxx-specific ncremap flags (--ps_nm=${file}/ps, --vrt_in=vert_L128.nc)
# auto-emitted when prc_typ == 'eamxx'
# - climo, ts, e3sm_to_cmip, and e3sm_diags wiring for an EAMxx run
#
# Run with: zppy -c examples/post.v3.eamxx.cfg
[default]
input = /pscratch/sd/z/zhan391/e3smv4_project/ne256pg2_ne256pg2.F20TR-SCREAMv1.July-1.spanc800.2xauto.acc150.n0032.test2.1
output = /pscratch/sd/c/chengzhu/tests/ne256pg2_ne256pg2.F20TR-SCREAMv1.July-1.spanc800.2xauto.acc150.n0032.test2.1_05182026
case = ne256pg2_ne256pg2.F20TR-SCREAMv1.July-1.spanc800.2xauto.acc150.n0032.test2.1
www = /global/cfs/cdirs/e3sm/www/chengzhu/tests/zppy_for_eamxx_05182026
partition = "debug"
account = "e3sm"
campaign = "water_cycle"
debug = False
#environment_commands = "source /global/common/software/e3sm/anaconda_envs/test_e3sm_unified_1.13.0rc10_pm-cpu.sh"

[climo]
active = True
walltime = "2:00:00"
years = "1995:2004:10",

[[ atm_monthly_180x360_aave ]]
# The following e3sm_diags sets require it:
# "lat_lon", "zonal_mean_xy", "zonal_mean_2d", "polar", "cosp_histogram",
# "meridional_mean_2d", "annual_cycle_zonal_mean", "zonal_mean_2d_stratosphere",
# "aerosol_aeronet", "aerosol_budget"
input_component = "eamxx"
case = "1ma_ne30pg2"
input_files = "AVERAGE.nmonths_x1"
frequency = "monthly"
input_subdir = "run/"
mapping_file = map_ne30pg2_to_cmip6_180x360_aave.20200201.nc

[[ atm_monthly_diurnal_8xdaily_180x360_aave ]]
# The following e3sm_diags sets require it:
# "diurnal_cycle"
input_component = "eamxx"
case = "3ha_ne30pg2"
input_files = "AVERAGE.nhours_x3"
input_subdir = "run/"
frequency = "diurnal_8xdaily"
mapping_file = map_ne30pg2_to_cmip6_180x360_aave.20200201.nc
vars = "precip_liq_surf_mass_flux,precip_ice_surf_mass_flux"
# Bump walltime for a potential performance issue in ncclimo for processing eamxx high freq data.
walltime = "4:00:00"

[[ land_monthly_climo ]]
active = True
# This subtask is a dependency for the e3sm_diags task's lnd_monthly_mvm_lnd subtask.
# The following e3sm_diags sets require it:
# "lat_lon_land"
input_component = "elm"
frequency = "monthly"
input_files = "elm.h0"
input_subdir = "run/"
vars = "" # Setting this as "" will tell zppy to use ALL variables

[[ land_monthly_180x360_traave ]]
active = True
input_component = "elm"
frequency = "monthly"
input_files = "elm.h0"
input_subdir = "run/"
mapping_file = "map_ne256pg2_to_cmip6_180x360_traave.20250301.nc"
vars = ""

[ts]
active = True
walltime = "00:30:00"
years = "1995:2004:5"
ts_num_years=5
#qos = "debug"

[[atm_monthly_180x360_aave]]
# Merged 2D+3D atm timeseries: vrt_remap_vars selectively vert-remaps the
# 3D vars into a sibling ts_vrt_remap/ directory, so downstream e3sm_to_cmip
# sees a single clean ts subsection.
input_component = "eamxx"
input_subdir = "run/"
case = "1ma_ne30pg2"
input_files = "AVERAGE.nmonths_x1"
frequency = "monthly"
mapping_file = map_ne30pg2_to_cmip6_180x360_aave.20200201.nc
vars="ps,surf_radiative_T,SeaLevelPressure,IceWaterPath,qv_2m,precip_liq_surf_mass_flux,precip_ice_surf_mass_flux,omega_at_500hPa,omega_at_700hPa,omega_at_850hPa,T_mid_at_700hPa,T_2m,surface_upward_latent_heat_flux,surf_sens_flux,z_mid_at_700hPa,wind_speed_10m,surf_evap,U_at_10m_above_surface,V_at_10m_above_surface,LW_clrsky_flux_dn_at_model_bot,LW_clrsky_flux_up_at_model_top,LW_flux_dn_at_model_bot,LW_flux_up_at_model_bot,LW_flux_up_at_model_top,SW_clrsky_flux_dn_at_model_bot,SW_clrsky_flux_dn_at_model_top,SW_clrsky_flux_up_at_model_bot,SW_clrsky_flux_up_at_model_top,SW_flux_dn_at_model_bot,SW_flux_dn_at_model_top,SW_flux_up_at_model_bot,SW_flux_up_at_model_top,ShortwaveCloudForcing,LongwaveCloudForcing,isccp_cldtot,U,V,T_mid,z_mid,omega,RelativeHumidity,p_mid,qv"
# NOTE: ncclimo --prc_typ=eamxx does NOT auto-extract ps/hyai/hyam/hybi/hybm
# for 3D vars the way --prc_typ=cam/eam does due to a meta data issue, so we must list them explicitly
# in extra_vars. ps is load-bearing for the vrt_remap step (ts.bash:138
# passes --ps_nm=${file}/ps to ncremap).
# If ncclimo and eamxx is fixed upstream to mirror cam/eam behavior, drop
# ps + hybrid coeffs here.
extra_vars= "ps,hyai,hyam,hybi,hybm,area,landfrac,ocnfrac"
vrt_remap_vars = "U,V,T_mid,z_mid,omega,RelativeHumidity,p_mid,qv"

[[ atm_daily_180x360_aave ]]
active = True
# This subtask is a dependency for the e3sm_diags task's atm_monthly_180x360 subtask.
# The following e3sm_diags sets require it:
# "tropical_subseasonal", "precip_pdf"
input_component = "eamxx"
case = "1da_ne30pg2"
input_files = "AVERAGE.ndays_x1"
frequency = "daily"
input_subdir = "run/"
mapping_file = map_ne30pg2_to_cmip6_180x360_aave.20200201.nc
# Needed for Wheeler Kiladis
vars = "LW_flux_up_at_model_top,precip_liq_surf_mass_flux,precip_ice_surf_mass_flux,U_at_850hPa"
# For this simulation's "1da_ne30pg2.AVERAGE.ndays_x1" stream, each file
# holds one daily average (1 day, 1 timestep). Override the zppy defaults
# (dpf=30, tpd=1) which assume E3SM EAM monthly h0 files; otherwise ncclimo
# treats each daily file as 30 days and silently produces ts files whose
# contents (~2 months) don't match their filenames.
dpf = 1
tpd = 1

[[ atm_monthly_glb ]]
active = True
# This subtask is a dependency for the global_time_series task.
input_component = "eam"
input_subdir = "run/"
case = "1ma_ne30pg2"
input_files = "AVERAGE.nmonths_x1"
frequency = "monthly"
mapping_file = "glb"
vars="ps,surf_radiative_T,SeaLevelPressure,IceWaterPath,qv_2m,precip_liq_surf_mass_flux,precip_ice_surf_mass_flux"


[[ rof_monthly ]]
active = True
# The following e3sm_diags sets require it:
# "streamflow"
input_component = "mosart"
frequency = "monthly"
input_files = "mosart.h0"
input_subdir = "run/"
mapping_file = ""
vars = "RIVER_DISCHARGE_OVER_LAND_LIQ"
extra_vars = 'areatotal2'

[e3sm_to_cmip]
active = True
frequency = "monthly"
ts_grid = "180x360_aave"
ts_num_years=5
walltime = "00:10:00"
years = "1995:2004:5"
qos = "debug"

[[atm_monthly_180x360_aave]]
# Merged subsection matching the [ts] atm_monthly_180x360_aave output.
# Without cmip_vars, e3sm_to_cmip uses its built-in default list (~41 vars).
# Uncomment to override the default ~41-var list.
#cmip_vars = "pr, cltisccp, evspsbl, hfls, hfss, huss, ps, psl, rlds, rldscs, rlus, rlut, rlutcs, rsds, rsdscs, rsdt, rsus, rsuscs, rtmt, uas, vas, sfcWind, tas, ts, ta, ua, va, zg"
input_component = "eamxx"
case = "1ma_ne30pg2"
input_files = "AVERAGE.nmonths_x1"


[e3sm_diags]
active = True
multiprocessing = True
num_workers = 8
ref_start_yr = 1995
ref_final_yr = 2004
ts_num_years = 5
walltime = "2:00:00"
years = "1995:2004:10",

# case inherits the top-level [default] case; climo output naming includes
# the stream id automatically via fml_nm, so this subsection can consume
# both monthly and diurnal climo without per-frequency overrides.

[[ atm_monthly_180x360_aave ]]
# `e3sm_diags` is largely driven by which e3sm_diags sets are requested:
sets="lat_lon","zonal_mean_xy","zonal_mean_2d","polar","cosp_histogram","meridional_mean_2d","annual_cycle_zonal_mean","enso_diags","qbo","zonal_mean_2d_stratosphere","aerosol_aeronet","mp_partition","tropical_subseasonal","precip_pdf","streamflow","diurnal_cycle",
# sets = #"tc_analysis," # not yet supported for eamxx!
climo_diurnal_frequency = "diurnal_8xdaily"
climo_diurnal_subsection = "atm_monthly_diurnal_8xdaily_180x360_aave"
ts_daily_subsection = "atm_daily_180x360_aave"
# ts_subsection defaults to "atm_monthly_180x360_aave" — matches the merged
# [ts] subsection above, so no explicit override needed.
grid = '180x360_aave'
short_name = 'e3sm.amip.EAMXX.test2_1'
27 changes: 27 additions & 0 deletions tests/test_sections.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ def test_sections():
"mapping_file": "MAPPING_FILE_TS",
"tpd": 1,
"vars": "FSNTOA,FLUT,FSNT,FLNT,FSNS,FLNS,SHFLX,QFLX,PRECC,PRECL,PRECSC,PRECSL,TS,TREFHT",
"vrt_remap_vars": "",
"vrt_in_file": "",
"vrt_remap_file": "",
"years": ["0001:0020:5"],
}
compare(actual_section, expected_section)
Expand All @@ -135,6 +138,7 @@ def test_sections():
"case": "CASE",
"constraint": "",
"debug": False,
"default_case": "CASE",
"dpf": 30,
"dry_run": False,
"environment_commands": "",
Expand Down Expand Up @@ -171,6 +175,9 @@ def test_sections():
"ts_num_years": 5,
"ts_subsection": "",
"vars": "FSNTOA,FLUT,FSNT,FLNT,FSNS,FLNS,SHFLX,QFLX,PRECC,PRECL,PRECSC,PRECSL,TS,TREFHT",
"vrt_remap_vars": "",
"vrt_in_file": "",
"vrt_remap_file": "",
"walltime": "02:00:00",
"www": "WWWW",
"years": ["0001:0020:5"],
Expand Down Expand Up @@ -204,6 +211,7 @@ def test_sections():
"climo_jobs": 0,
"constraint": "",
"debug": False,
"default_case": "CASE",
"dry_run": False,
"environment_commands": "",
"environment_commands_secondary": "",
Expand Down Expand Up @@ -326,6 +334,9 @@ def test_subsections():
"job_nbr": None,
"mapping_file": "MAPPING_FILE_TS_GRID1",
"tpd": None,
"vrt_remap_vars": None,
"vrt_in_file": None,
"vrt_remap_file": None,
"years": ["0001:0020:5"],
},
"ts_grid2": {
Expand All @@ -336,9 +347,15 @@ def test_subsections():
"job_nbr": None,
"mapping_file": "MAPPING_FILE_TS_GRID2",
"tpd": None,
"vrt_remap_vars": None,
"vrt_in_file": None,
"vrt_remap_file": None,
"years": ["0001:0020:10"],
},
"vars": "FSNTOA,FLUT,FSNT,FLNT,FSNS,FLNS,SHFLX,QFLX,PRECC,PRECL,PRECSC,PRECSL,TS,TREFHT",
"vrt_remap_vars": "",
"vrt_in_file": "",
"vrt_remap_file": "",
}
compare(actual_section, expected_section)
actual_tasks = get_tasks(config, section_name)
Expand All @@ -353,6 +370,7 @@ def test_subsections():
"case": "CASE",
"constraint": "",
"debug": False,
"default_case": "CASE",
"dpf": 30,
"dry_run": False,
"environment_commands": "",
Expand Down Expand Up @@ -389,6 +407,9 @@ def test_subsections():
"ts_num_years": 5,
"ts_subsection": "",
"vars": "FSNTOA,FLUT,FSNT,FLNT,FSNS,FLNS,SHFLX,QFLX,PRECC,PRECL,PRECSC,PRECSL,TS,TREFHT",
"vrt_remap_vars": "",
"vrt_in_file": "",
"vrt_remap_file": "",
"walltime": "02:00:00",
"www": "WWWW",
"years": ["0001:0020:5"],
Expand All @@ -404,6 +425,7 @@ def test_subsections():
"case": "CASE",
"constraint": "",
"debug": False,
"default_case": "CASE",
"dpf": 30,
"dry_run": False,
"environment_commands": "",
Expand Down Expand Up @@ -440,6 +462,9 @@ def test_subsections():
"ts_num_years": 5,
"ts_subsection": "",
"vars": "FSNTOA,FLUT,FSNT,FLNT,FSNS,FLNS,SHFLX,QFLX,PRECC,PRECL,PRECSC,PRECSL,TS,TREFHT",
"vrt_remap_vars": "",
"vrt_in_file": "",
"vrt_remap_file": "",
"walltime": "02:00:00",
"www": "WWWW",
"years": ["0001:0020:10"],
Expand Down Expand Up @@ -491,6 +516,7 @@ def test_subsections():
"climo_jobs": 0,
"constraint": "",
"debug": False,
"default_case": "CASE",
"dry_run": False,
"environment_commands": "",
"environment_commands_secondary": "",
Expand Down Expand Up @@ -539,6 +565,7 @@ def test_subsections():
"climo_jobs": 0,
"constraint": "",
"debug": False,
"default_case": "CASE",
"dry_run": False,
"environment_commands": "",
"environment_commands_secondary": "",
Expand Down
9 changes: 9 additions & 0 deletions zppy/climo.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ def climo(config: ConfigObj, script_dir: str, existing_bundles, job_ids_file):
set_mapping_file(c)
set_grid(c)
set_component_and_prc_typ(c)
# Compose the climo output filename prefix. For EAMxx, subsection-level
# `case` (e.g., "1ma_ne30pg2") is the stream id ncclimo needs to find
# input files; prefixing with the top-level case keeps output names
# unified across streams so a single e3sm_diags subsection can consume
# both monthly and diurnal climo via one `case` setting.
if c["prc_typ"] == "eamxx" and c["case"] != c["default_case"]:
c["fml_nm"] = f"{c['default_case']}.{c['case']}"
else:
c["fml_nm"] = c["case"]
year_sets: List[Tuple[int, int]] = get_years(c["years"])
# Loop over year sets
for s in year_sets:
Expand Down
19 changes: 19 additions & 0 deletions zppy/defaults/default.ini
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,18 @@ job_nbr = integer(default=0)
tpd = integer(default=1)
# Model component having generated input files (eam, eamxx, elm, mosart, ...)
input_component = string(default="")
# Vertical regrid (model levels → pressure levels) — applied after ncclimo splits
# files into per-var time-series. Vars listed here will additionally be regridded
# and written to a sibling directory `ts_vrt_remap/` parallel to `ts/`, so users
# can use native-level and pressure-level data at the same time.
# If empty, no vertical regrid is performed.
vrt_remap_vars = string(default="")
# Target vertical grid file (output pressure levels) for ncremap.
# If empty, zppy defaults to a vrt_remap_plev19.nc under diagnostics_base_path.
vrt_remap_file = string(default="")
# Source vertical coordinate file for ncremap. Required for EAMxx (L128 grid).
# If empty, zppy defaults to a vert_L128.nc under diagnostics_base_path when prc_typ=='eamxx'.
vrt_in_file = string(default="")

[[__many__]]
area_nm = string(default=None)
Expand All @@ -159,6 +171,9 @@ input_component = string(default="")
job_nbr = integer(default=None)
tpd = integer(default=None)
input_component = string(default=None)
vrt_remap_vars = string(default=None)
vrt_remap_file = string(default=None)
vrt_in_file = string(default=None)

[e3sm_to_cmip]
# Metadata json file
Expand All @@ -172,13 +187,17 @@ cmip_vars = string(default="")
input_component = string(default="")
# TBD: description here
interp_vars = string(default="U,V,T,Q,RELHUM,OMEGA,Z3")
# Source vertical coordinate file for ncremap. Required for EAMxx (L128 grid).
# Defaults to a vert_L128.nc under diagnostics_base_path when prc_typ=='eamxx'.
Comment thread
chengzhuzhang marked this conversation as resolved.
vrt_in_file = string(default="")

[[__many__]]
cmip_metadata = string(default=None)
cmip_plevdata = string(default=None)
cmip_vars = string(default=None)
input_component = string(default=None)
interp_vars = string(default=None)
vrt_in_file = string(default=None)

[tc_analysis]
# NOTE: always overrides value in [default]
Expand Down
1 change: 1 addition & 0 deletions zppy/e3sm_diags.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def e3sm_diags(config: ConfigObj, script_dir: str, existing_bundles, job_ids_fil
dependencies: List[str] = []
check_parameters_for_bash(c)
c["scriptDir"] = script_dir
c["default_case"] = config["default"]["case"]
if "ts_num_years" in c.keys():
c["ts_num_years"] = int(c["ts_num_years"])
# Loop over year sets
Expand Down
12 changes: 12 additions & 0 deletions zppy/e3sm_to_cmip.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ def e3sm_to_cmip(config: ConfigObj, script_dir: str, existing_bundles, job_ids_f
default_cmip_plevdata,
ParameterInferenceType.PATH_INFERENCE,
)
# EAMxx needs an explicit source vertical grid file (L128);
# EAM/CAM have vertical coord info embedded in the file already.
if c["prc_typ"] == "eamxx":
default_vrt_in_file = (
f"{c['diagnostics_base_path']}/e3sm_to_cmip_data/grids/vert_L128.nc"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the code already had a reference to {c['diagnostics_base_path']}/e3sm_to_cmip_data/ a few lines above, but it does seem a little strange since e3sm_to_cmip is downstream from ts.

Claude says the following, emphasis my own:

diagnostics_base_path points to a shared data installation directory (something like /usr/share/e3sm_unified/...) that happens to be organized under a folder named e3sm_to_cmip_data/ because that's where the e3sm_to_cmip package installs its reference data files (grid descriptors, pressure-level maps, etc.). The ts task is just borrowing files from that same installed data directory — it doesn't depend on the e3sm_to_cmip task having run first.
So the path e3sm_to_cmip_data/grids/vert_L128.nc means "the vert_L128.nc file that ships with the e3sm_to_cmip software package," not "a file produced by the e3sm_to_cmip zppy task." The e3sm_to_cmip task uses the same path for the same reason.
The slight awkwardness is that ts.py now has a hard-coded dependency on the directory layout of the e3sm_to_cmip package's data installation. If that package ever reorganizes its data files, both ts.py and e3sm_to_cmip.py would need updating. It might be worth a comment in the code noting that these are static reference files from the installed package, not outputs of the downstream task.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth a comment in the code noting that these are static reference files from the installed package, not outputs of the downstream task.

@forsyth2 Prefixing with diagnostics_base_path should already imply the data are pre-installed. I think the current approach is fine, but feel free to update if you think it improves clarity.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefixing with diagnostics_base_path should already imply the data are pre-installed

Yes I suppose looking at it again, that makes sense. It was just a little confusing when I was trying to figure out which tasks had e3sm_to_cmip as a dependency. A comment might be nice, but not necessary.

)
set_value_of_parameter_if_undefined(
c,
"vrt_in_file",
default_vrt_in_file,
ParameterInferenceType.PATH_INFERENCE,
)
year_sets: List[Tuple[int, int]] = get_years(c["years"])
# Loop over year sets
for s in year_sets:
Expand Down
Loading
Loading