runcase.py
Overview
runcase.py is the core CIME interaction layer for OLMT, orchestrating the complete lifecycle of a single E3SM/ELM (or CLM/CTSM) simulation. This ~3600-line script is not called directly by users — it is invoked by site_fullrun.py and global_fullrun.py to build and configure each phase (ad_spinup, final spinup, transient) of a BGC simulation sequence.
Key responsibilities:
Generate point/regional surface, domain, and land-use data (via
makepointdata.py)Call
create_newcasewith specified compset, resolution, machine, and MPI configurationApply XML configuration changes (
./xmlchange) for CIME environment and run settingsWrite land model namelists (
user_nl_elm,user_nl_datm,user_nl_mosart) with physics options, output variables, and forcing pathsModify parameter files (
clm_params.nc,CNP_parameters.nc) for parameter perturbations or custom physics (hummock/hollow, marsh, polygonal tundra, etc.)Copy source modifications from
--srcmods_locBuild the model (
./case.build) or skip if--no_buildOptionally submit the case (
./case.submit) or generate ensemble PBS/SLURM scripts for MPI-parallel parameter sweeps
All shell commands are logged via runcmd(), which records to --options_log_json and traps a CIME quirk where case.submit converts exceptions to warnings.
Seven-Step Workflow
From the script docstring (lines 88–96), runcase.py performs these steps in sequence:
Create point/domain/surface data — shell out to
makepointdata.py(unless--nopointdataor--makepointdata_only).Create new case — run
create_newcasewith machine, compset, resolution, MPI library, walltime, project, and compiler.Set point and case-specific namelist options — write
user_nl_elmwith physics flags, output variables, parameter file paths, finidat, forcing paths, and transient/spinup settings.Configure case — run
./case.setup(unless--no_config).Build model — run
./case.build(unless--no_build); optionally--clean_buildfirst.Apply user-specified PBS/SLURM and submit information — for ensemble runs (
--ensemble_fileor--mc_ensemble), generate MPI job scripts that callmanage_ensemble.py.Submit job — run
./case.submitfor single runs, or submit ensemble scripts (unless--no_submit).
Command-Line Arguments
runcase.py uses optparse (not argparse) with ~150 options. They are grouped below by category.
General OLMT Options
Option |
Description |
|---|---|
|
Unique identifier prepended to case name (default: |
|
Case directory root (default: |
|
Directory where run directories are created (required) |
|
Per-invocation staging directory; defaults to |
|
Base model directory (E3SM or CESM source tree) |
|
Input data directory (required) |
|
Set project code for machine accounting |
|
Location of executable (if pre-built) |
|
Directory containing model constraints (ensemble mode) |
|
Directory containing |
|
Use this PFT for all gridcells |
|
File for parameter modifications (whitespace-delimited: |
|
User-specified parameter values (format: |
|
File for P parameter modifications (ELM only) |
Model Build Options
Option |
Description |
|---|---|
|
Target machine ( |
|
Compiler to use ( |
|
MPI library ( |
|
Write special outputs for diagnostics (hourly, daily, PFT-level) |
|
Use debug queue |
|
Copy sourcemods from this location |
|
PIO version ( |
Case Options
Option |
Description |
|---|---|
|
Set cold start (mutually exclusive with |
|
Component set (default: |
|
Force compset to act like transient |
|
Latitude/longitude range for regional run |
|
Use hummock/hollow microtopography |
|
Use marsh hydrology/elevation |
|
NOAA tide components file (for marsh) |
|
Mask file to use (regional only) |
|
Model to use ( |
|
File containing custom namelist options for |
|
Write special output variables |
|
Resolution for global simulation (default: |
|
File containing list of points to run |
Surface Data Options
Option |
Description |
|---|---|
|
Site group to use (default: |
|
6-character FLUXNET code to run (required for site runs) |
|
6-character FLUXNET code for forcing data |
|
Subdirectory for met data forcing |
|
User-provided surface/domain file |
|
User-defined dynamic PFT file |
|
Use gridded surface data instead of site data |
|
Include non-vegetated columns/landunits in surface data |
Meteorological Forcing Options
Option |
Description |
|---|---|
|
Use CRU-NCEP forcing (v5 or v8) |
|
Use CRUJRA forcing |
|
Use TRENDY 2025 forcing |
|
Use GSWP3 forcing (v1 or W5E5 variant) |
|
Use ERA5 atmospheric reanalysis |
|
Use Princeton forcing |
|
Use CPLHIST forcing |
|
Apply correction to CONUS precipitation |
|
File containing met data biases ( |
|
Temperature to add to atmospheric forcing (K) |
|
CO₂ (ppmv) to add to atmospheric forcing |
|
CO₂ data file (default: |
Spinup and Restart Options
Option |
Description |
|---|---|
|
Run accelerated decomposition spinup |
|
Run exit spinup (CLM 4.0 only) |
|
Case containing initial data file |
|
Initial data file (absolute path) |
|
Model year of initial data file (default: last available) |
|
Switch for branch run |
|
Run length units ( |
|
Run length (in |
|
Restart interval (in |
|
Starting year for model output |
Model Output Options
Option |
Description |
|---|---|
|
Number of output timesteps per file |
|
Output file timestep (0=monthly, -24=daily, 1=hourly, etc.) |
|
Output only selected variables in h0 file (comma-delimited) |
|
Limit output vars in spinup runs |
|
Transient outputs (comma-delimited) |
|
Comma-separated list of vars to output at PFT level |
Build and Submit Options
Option |
Description |
|---|---|
|
Run |
|
Perform clean build before building |
|
Do NOT configure case |
|
Do NOT build model |
|
Do NOT submit built model to queue (build only) |
|
Remove old case directory before proceeding |
|
Number of processors (default: 1) |
|
Number of land model instances (default: 1) |
|
Number of groups to run in ensemble mode (default: 64) |
|
Model timestep in hours (default: 0.5) |
|
Desired walltime for each job in hours (default: 6) |
BGC and Physics Options
Option |
Description |
|---|---|
|
Turn off wildfires |
|
Do not use dynamic PFT file |
|
Turn on harvest modification (all harvest in first timestep) |
|
Turn off dynamic root distribution |
|
Turn on CN with multiple soil layers (excluding CENTURY) |
|
Turn on CN with CENTURY C module |
|
Turn CH₄ on/off |
|
Use constant 1850 or RCP8.5 N deposition |
|
Use constant 1850 or RCP8.5 aerosol deposition |
|
Use constant 1850 CO₂ concentration |
|
Switch to turn on C13/C14 |
|
Run carbon-only, CN-only, or CP-only (supplemental nutrients) |
|
Use variable soil thickness from surface data |
|
Turn off CNP budget calculations |
|
Turn on hydraulic stress |
FATES Options
Option |
Description |
|---|---|
|
Set FATES hydro to true |
|
Which version of FATES nutrient to use ( |
|
Set FATES logging to true |
|
FATES parameter file to use |
NGEE Arctic Options
Option |
Description |
|---|---|
|
Disable square scaling of organic matter fraction in soil thermal conductivity |
|
Use atmospheric downscaling in topounits |
|
Downscale radiation input to topounits |
|
Use Hao et al. dust/snow mixing albedo parameterization |
|
Turn off SNICAR-AD snow microphysics model |
|
Turn on extra snow layers |
|
Turn on firn percolation and compaction |
|
Turn on polygonal tundra parameterizations (NGEE Arctic Phase 3 IM1) |
|
Use unified polygonal tundra across all topounits |
|
Use colder and saturated initial conditions (NGEE Arctic IM2 and IM0) |
|
Use NGEE Arctic Hillslope Hydrology across topounits |
|
Activate topounit-level and PFT-level outputs ( |
|
Extend leaf onset based on accumulated GDD past summer solstice |
|
Use Balland and Arp (2005) soil thermal conductivity model |
Ensemble Options
Option |
Description |
|---|---|
|
Parameter sample file to generate ensemble |
|
Monte Carlo ensemble (argument is # of simulations) |
|
Do not copy files to ensemble directories |
|
File containing list of parameters to vary (format: |
|
File for ensemble post-processing |
|
Run SPRUCE treatment simulations (ensemble mode) |
Other Options
Option |
Description |
|---|---|
|
Do NOT make point data (use data already created) |
|
Make point data for later use ONLY (no model config/build/submit) |
|
Compile model with Alquimia BGC interface using specified input file |
|
Full path to JSON file recording all OLMT options and syscalls (default: |
|
Archive root directory (only for mesabi) |
|
Path to modified parameter file (PFT or P) |
CIME Integration
create_newcase Command
Line 1871–1895. Constructs the create_newcase command with:
./create_newcase --case <casedir> --driver <driver> --mach <machine> --compset <compset> --res <res> \
--mpilib <mpilib> --walltime <timestr> --handle-preexisting-dirs u \
[--run-unsupported] [--project <project>] [--compiler <compiler>]
Note that as of June 2026, E3SM made MOAB the default coupler. The E3SM project tested the MOAB driver thoroughly to ensure it behaves bit-for-bit with the MCT driver, but the MOAB driver is not compiled as part of the E3SM build process and is instead required to pre-exist as a compiled library. This complication is undesirable for OLMT usage, so we made MCT the default driver when running from OLMT for now. This decision may be revisited in the future if MOAB features are required or MCT support stops.
xmlchange Variables
After case creation, runcase.py applies dozens of ./xmlchange commands to configure CIME XML files. Key examples:
Build settings:
SAVE_TIMING=FALSE,EXEROOT,PIO_VERSION,MOSART_MODE=NULLRun settings:
RUNDIR,DOUT_S,DOUT_S_ROOT,DIN_LOC_ROOT,DIN_LOC_ROOT_CLMFORCDomain/resolution:
<LSM>_USRDAT_NAME(for site runs)Spinup:
CLM_ACCELERATED_SPINUP=on(CLM5) or--append <LSM>_BLDNML_OPTS='-bgc_spinup on'(ELM)DATM forcing:
DATM_MODE(CLMCRUNCEP,CLMGSWP3v1,CLM1PT),DATM_CLMNCEP_YR_START,DATM_CLMNCEP_YR_END,DATM_CLMNCEP_YR_ALIGNTasks:
NTASKS_<comp>,NTHRDS_<comp>,MAX_TASKS_PER_NODE,MAX_MPITASKS_PER_NODEStop/restart:
STOP_OPTION,STOP_N,REST_NTransient/branch:
RUN_TYPE=branch,RUN_REFDATE,RUN_REFCASE,CCSM_BGC=CO2A,<LSM>_CO2_TYPE=diagnostic
Configuration options are also appended to <LSM>_BLDNML_OPTS for features like topounits (-topounit), maximum PFT number (-maxpft), or methane disabling (stripping -methane).
Namelist Generation
user_nl_elm (or user_nl_clm)
Lines 2087–3035 write the land model namelist. Structure:
&clm_inparm
! Custom namelist from --namelist_file (if provided)
! History file options (hist_mfilt, hist_nhtfrq, hist_fincl*, hist_dov2xy)
! Initial data (finidat)
! Surface data (fsurdat, flanduse_timeseries)
! Parameter files (paramfile, fsoilordercon, fates_paramfile)
! Forcing paths (metdata_type, metdata_bypass, co2_file, aero_file)
! Physics flags (use_lch4, use_c13, use_c14, use_nofire, use_hydrstress, etc.)
! NGEE Arctic flags (use_polygonal_tundra, use_arctic_init, use_IM2_hillslope_hydrology, etc.)
/
Key branches:
Spinup mode (
--ad_spinup): write long-term average pool variables tohist_fincl2(CWDC_vr,SOIL2C_vr,SOIL3C_vr, etc.), setfinidat = '', adjusthist_mfilt/hist_nhtfrq.Transient mode (
20TRin compset or--istrans): disablefinidatauto-setting, writeflanduse_timeseries, setcheck_finidat_fsurdat_consistency = .false..Diagnostics mode (
--diags): create 5 history streams (annual, hourly, daily-column, daily-PFT, annual-PFT) with extensive variable lists.CPL_BYPASS mode (
CBCN/ICBcompsets): writemetdata_type('cru-ncep','gswp3','gswp3_daymet4','era5','era5_daymet4','site', etc.) andmetdata_bypasspath. If site forcing, useCLM1PT_data/<ptstr>_<site>/. If reanalysis, use fullcpl_bypass_full/paths.Hummock/hollow or marsh (
--humhol,--marsh): sethumhol_ht,hum_frac,humhol_dist,qflx_h2osfc_surfrate,rsub_top_globalmax,h2osoi_offsetinclm_params.nc(viancap2commands, lines 1592–1730); optionally parse--tide_components_fileto generate tidal harmonic coefficients.
user_nl_datm
Lines 3163–3264 write the DATM namelist when not using cpl_bypass. Key modifications:
``streams``: construct list of DATM stream files with start/end/align years. For
CLMCRUNCEPorCLMGSWP3v1, three streams (Solar, Precip, TPQW) pluspresaeroand optionalco2tseries.20trfor transient runs. ForCLM1PT, single user stream.``taxmode``: set to
'cycle', 'cycle', 'cycle', 'extend', 'extend'(for reanalysis) or'cycle', 'extend', 'extend'(for site forcing). Append'extend'for transient CO₂.
Also writes user stream override files (user_datm.streams.txt.<stream_name>) to patch aerosol file names or CO₂ file paths, and reverse directories for CLM1PT site forcing.
user_nl_mosart
Not explicitly written in runcase.py; MOSART is set to NULL mode via ./xmlchange MOSART_MODE=NULL (line 1917).
Source Modifications
--srcmods_loc Handling
Lines 3131–3136. If --srcmods_loc is provided, runcase.py:
Checks that the directory exists.
Converts to absolute path.
Copies all contents to
<casename>/SourceMods/viacp -r.
For example, the CI workflow uses --srcmods_loc srcmods_era5cb to copy lnd_import_export.F90 overrides for ERA5 + cpl_bypass simulations.
PBS/SLURM Submission Script Generation
Ensemble Mode (lines 3423–3596)
When --ensemble_file or --mc_ensemble is provided, runcase.py generates a PBS or SLURM script (scripts/<caseid>/ensemble_run_<casename>.pbs) that:
Sets walltime (
--walltime), job name, project, nodes, and partition based on--machine.Sources environment from
<casedir>/software_environment.txt(for CADES, compy, anvil, chrysalis).Runs
mpirun(orsrun) withmanage_ensemble.pyto distribute parameter samples across MPI ranks.
Command constructed (lines 3504–3582):
mpirun -n <np_total> python manage_ensemble.py \
--case <casename> --runroot <runroot> --n_ensemble <nsamples> \
--ens_file <ensemble_file> --exeroot <exeroot> --parm_list <parm_list> \
--cnp <True/False> --site <site> --model_name <model_name> \
[--constraints <constraints>] [--postproc_file <postproc_file>] \
[--spruce_treatments]
If --no_submit is False, submits via qsub or sbatch.
Single-Run Mode (line 3342)
For non-ensemble runs, simply calls ./case.submit unless --no_submit.
Error Handling
runcmd() Function (lines 49–77)
Every shell command in runcase.py is executed via runcmd(cmd, echo=True, check=True, tag=...). This function:
Logs the command to
--options_log_json(if provided) via_write_cmd().Runs the command with
subprocess.run(..., shell=True, check=check, text=True, capture_output=True).CIME quirk trap: CIME’s
case.submitconverts Python exceptions in PBS submission to warnings, soruncmd()explicitly checks stderr for"Exception from "and exits if found (lines 75–76):if check == True and "Exception from " in result.stderr: sys.exit(f"Error in run command {cmd}")
This prevents silent failures when PBS/SLURM submission fails.
Options Logging (--options_log_json)
Lines 16–46. If --options_log_json is provided, runcase.py writes a JSON array of command records, each with:
i: sequence numbertag: script name (runcase.pyor child script tag)lineno: source line number (viainspect.stack())cmd: raw command string or parsed dict (forcreate_newcase,.pyscripts)
This provides a complete audit trail of OLMT syscalls for reproducibility and debugging.
Relationship to Parent Scripts
site_fullrun.py / global_fullrun.py → runcase.py
First site (or single global run): parent constructs a
runcase.pyshell-out for each of the three phases (ad_spinup, final spinup, transient), passing:--ad_spinupfor phase 1--finidat_case(pointing to phase 1 output) for phase 2--finidat_case(pointing to phase 2 output) and--compsetwith20TRfor phase 3Common flags:
--model_root,--ccsm_input,--site,--sitegroup,--tempdir,--cruncep/--gswp3/--era5, etc.
Additional sites: instead of calling
runcase.py, parent callscase_copy.pyto clone the first site’s case directory and patch it with new site lat/lon/surface data. This is much faster than rebuilding.
runcase.py → makepointdata.py
Lines 1403–1464. If not --nopointdata, runcase.py shells out to makepointdata.py with:
--ccsm_input,--mysimyr,--model,--tempdir--site,--sitegroup(for site runs) or--res,--point_list(for global/multi-point runs)--metdir(if user-provided),--makemetdata,--surfdata_grid,--include_nonveg,--nopftdyn--mask,--lai,--pft,--crop,--marsh,--humhol
makepointdata.py generates domain.nc, surfdata.nc, surfdata.pftdyn.nc in <tempdir>/, which runcase.py copies to the run directory after build (lines 3327–3334).
Examples
Example 1: Single-Site Final Spinup
Called by site_fullrun.py after ad_spinup completes:
python runcase.py \
--model_root /path/to/E3SM \
--ccsm_input /path/to/inputdata \
--runroot /path/to/cases \
--site US-Brw \
--sitegroup NGEEArctic \
--compset I1850CNPRDCTCBC \
--finidat_case US-Brw_I1850CNPRDCTCBC_ad_spinup \
--finidat_year 251 \
--run_units nyears \
--run_n 200 \
--machine docker \
--mpilib mpi-serial \
--gswp3 \
--tempdir /tmp/olmt_run_12345_67890 \
--no_submit
This will:
Skip
makepointdata.py(already run during ad_spinup).Create case
US-Brw_I1850CNPRDCTCBCin<runroot>/.Set
finidatto<runroot>/US-Brw_I1850CNPRDCTCBC_ad_spinup/run/US-Brw_I1850CNPRDCTCBC_ad_spinup.elm.r.0251-01-01-00000.nc.Build ELM with
mpi-serial.Skip submission (
--no_submit).
Example 2: Regional Transient with ERA5 + Daymet4 + Source Mods
python runcase.py \
--model_root /path/to/E3SM \
--ccsm_input /path/to/inputdata \
--runroot /path/to/cases \
--res ELM_USRDAT \
--lat_bounds 65.0,70.0 \
--lon_bounds -165.0,-150.0 \
--compset I20TRCNPRDCTCBC \
--finidat_case my_region_I1850CNPRDCTCBC \
--finidat_year 1850 \
--run_units nyears \
--run_n 170 \
--machine cades \
--np 32 \
--era5 \
--daymet4 \
--metdir /path/to/era5_daymet4_forcing/ \
--srcmods_loc srcmods_era5cb/ \
--walltime 12 \
--project CLI185 \
--options_log_json /path/to/olmt_log.json
This will:
Call
makepointdata.pyto extract domain/surface/landuse for 65–70°N, 165–150°W.Create case with
I20TRCNPRDCTCBC(transient BGC) compset.Set
finidatto final spinup restart from 1850.Set
metdata_type = 'era5_daymet4'andmetdata_bypass = '/path/to/era5_daymet4_forcing/'.Copy source mods from
srcmods_era5cb/toSourceMods/.Build on 32 cores (CADES SLURM).
Submit via
sbatchwith 12-hour walltime.Log all commands to
/path/to/olmt_log.json.
Example 3: Monte Carlo Ensemble (100 samples)
python runcase.py \
--model_root /path/to/E3SM \
--ccsm_input /path/to/inputdata \
--runroot /path/to/cases \
--site US-Brw \
--sitegroup NGEEArctic \
--compset I1850CNPRDCTCBC \
--machine compy \
--np 1 \
--ng 64 \
--gswp3 \
--mc_ensemble 100 \
--parm_list examples/parm_list_example \
--walltime 6 \
--no_submit
This will:
Read parameter names/ranges from
examples/parm_list_example.Generate 100 random samples via Latin hypercube (or uniform random).
Write samples to
mcsamples_US-Brw_I1850CNPRDCTCBC.txt.Build case
US-Brw_I1850CNPRDCTCBCwithmpi-serial.Generate
scripts/ensemble_run_US-Brw_I1850CNPRDCTCBC.pbswith 64 groups (--ng 64), total 64 MPI ranks.Skip submission (
--no_submit); user can inspect and submit manually.
Summary
runcase.py is the workhorse of OLMT’s CIME integration, handling:
Data generation (via
makepointdata.py)Case creation (
create_newcase)XML configuration (
xmlchange)Namelist generation (
user_nl_elm,user_nl_datm)Parameter file modification (
ncap2commands for custom physics)Source modifications (
--srcmods_loc)Build (
./case.build)Submission (
./case.submitor ensemble PBS/SLURM scripts)
It is not user-facing — site_fullrun.py and global_fullrun.py construct the appropriate runcase.py invocations for each spinup/transient phase. For debugging, the --options_log_json flag provides a complete audit trail of all CIME commands issued.