Skip to content

Model configuration

VVMex reads runtime settings from one JSON file. Start by copying a runnable case from rundata/input_configs/default_cases/, then use this page as a reference while editing it. Writing a complete case from scratch is rarely the fastest route.

submit.py passes the selected file to VVMex. Direct invocations may instead provide the JSON path as the first non-option argument.

How to read this page

Default column Meaning
required The key must be present. The run stops at startup with Configuration error: Key '<path>' not found.
a value The key is optional and this is what the code uses when it is absent.

Four things about how the file is parsed are worth knowing before you edit one:

  • Keys are looked up by dotted path, not validated as a schema. A key the model does not know is simply never read.
  • A misspelled optional key is therefore silent. "enable_p3" written as "enable_P3" leaves P3 off and prints no warning. When a setting appears to have no effect, check the spelling and nesting against this page first.
  • The one exception is output.bp5, which rejects unknown keys and invalid values outright, and cross-checks every resolved setting across all compute ranks before opening the dataset.
  • Keys starting with __ or _ are inline comments for humans and are never read.

Types are int, real (double, or float in a single-precision build), bool, string, list, or object.

Command-line options

Argument Meaning
path/to/config.json Optional. If present as the first non-flag argument, selects the configuration file. Flags such as --io-tasks are skipped when resolving this path.
--io-tasks N Reserve N MPI ranks for asynchronous I/O. Only meaningful with output.engine = "SST"; see Output.

Example:

cd $VVM_ROOT
./submit.py -c /path/to/my_run.json --compute 1 --local

# Advanced direct MPI only
mpirun -np 1 ./build/vvm /path/to/my_run.json

The full submit.py option list is in Job submission.

How to edit a run

Most experiments follow the same editing order:

  1. Set the grid and time controls (grid, simulation).
  2. Choose the sounding profile and spatial NetCDF inputs (initial_conditions, netcdf_reader).
  3. Choose restart behavior, if any (restart).
  4. Choose output engine, fields, and subdomain (output).
  5. Enable dynamics forcings and tendency terms (dynamics).
  6. Enable physics packages and their call frequencies (physics).
  7. Tune acceleration options (optimization) only after the run is physically configured.

Keep JSON paths relative to the directory where submit.py starts the model, normally the project root.

Copy-and-edit defaults

Start every new experiment by copying a complete, runnable case. This is the fastest and safest way to obtain all required values and a consistent set of fields:

cp rundata/input_configs/default_cases/advection_u.json my_case.json

Then replace the top-level blocks below in my_case.json as needed. Each block is valid JSON and can be copied directly; it uses documented defaults wherever a default exists. Required settings have no model default, so the starter values for those keys are intentionally small and should be changed for the experiment.

The reference tables remain the complete source for every supported key, constraint, and engine-specific behavior.

Default-case inputs

Use the default cases when you want a known sample setup before designing your own experiment:

./submit.py --local --preset <your_preset_name> -c ./rundata/input_configs/default_cases/advection_u.json --compute 1

The three default-case directories are:

Directory Purpose
rundata/input_configs/default_cases/ Runnable JSON files such as advection_u.json, 2dbubble.json, rcemip.json, sea_grass_mountain.json, and taiwanvvm_2048.json.
rundata/initial_conditions/profiles/default_cases/ Sounding/profile text files used by those JSON files.
rundata/initial_conditions/spatial/default_cases/ Spatial NetCDF inputs for topography, surface, and land fields. These can be generated with tools/generate_init_nc.py.

For the complete case list and generation notes, see Default cases.

grid

Global mesh, halo width, horizontal boundary behavior, and vertical coordinate construction.

Key Type Default Meaning
nx, ny, nz int required Global domain size in x, y, and z. MPI decomposes this domain across compute ranks.
n_halo_cells int required Halo width used by stencil operations and MPI halo exchange. 2 suits every scheme except weno5, whose flux stencil reaches three cells past the last interior cell. This is one grid-wide setting, so a single tracer using weno5 forces 3 for the whole run, whatever the other tracers use. A run that gets this wrong stops at startup with Tracer '<name>': weno5 halo width is insufficient; configured 2, required 3.
dx, dy real required Horizontal grid spacing in meters. Uniform.
dz real required Nominal vertical spacing in meters.
dz1 real required Spacing of the stretched lower layers. With dz1 < dz the vertical grid is stretched from dz1 near the surface toward dz aloft; dz1 == dz gives a uniform column.
boundary_condition.x string "periodic" Lateral boundary type in x: periodic or zero_gradient. Anything other than zero_gradient is treated as periodic, so a typo silently gives you a periodic boundary.
boundary_condition.y string "periodic" Same, in y.
fix_lonlat bool false Fixed longitude/latitude handling for Taiwan-oriented real-case inputs.
vertical_coordinate_type string "default" default, taiwanvvm, or rcemip. Selects how z_up/z_mid are built, how the profile is interpolated, and the output coordinate convention.
rcemip_grid_data_path string ./rundata/initial_conditions/profiles/snd_rcemip_anal300_v3.txt Profile the rcemip coordinate is built from. Read only when vertical_coordinate_type is rcemip.

Use taiwanvvm when you need the TaiwanVVM-style vertical coordinate and output coordinate handling. Use default for ordinary idealized or simple real-case tests unless the case explicitly requires another coordinate.

Copy and edit this starter grid:

{
  "grid": {
    "nx": 32,
    "ny": 32,
    "nz": 33,
    "n_halo_cells": 2,
    "dx": 100.0,
    "dy": 100.0,
    "dz": 500.0,
    "dz1": 100.0,
    "boundary_condition": { "x": "periodic", "y": "periodic" },
    "fix_lonlat": false,
    "vertical_coordinate_type": "default",
    "rcemip_grid_data_path": "./rundata/initial_conditions/profiles/snd_rcemip_anal300_v3.txt"
  }
}

simulation

Key Type Default Meaning
total_time_s real required Total simulated time in seconds.
dt_s real required Model time step in seconds. Several physics frequencies must be divisible by this value.
output_interval_s real required Output cadence in simulated seconds. With dt_s: 1.0 and output_interval_s: 600.0 you get one output every 600 model steps.
idealized_test string "none" Built-in dynamics test: none, advection_u, advection_v, advection_w, stretching, twisting, or 2dbubble.

Setting idealized_test to anything but none replaces normal initialization with the test's analytic state and disables the spatial NetCDF read. For production-like runs, keep it none.

Copy and edit these small-run values:

{
  "simulation": {
    "total_time_s": 1500.0,
    "dt_s": 1.0,
    "output_interval_s": 50.0,
    "idealized_test": "none"
  }
}

initial_conditions

The one-dimensional sounding/profile and optional initial perturbations.

A run with simulation.idealized_test: "none" — that is, any real case — must supply initial_conditions.format (which must be txt), initial_conditions.source_file, and netcdf_reader.source_file; the run stops at startup otherwise. Built-in idealized tests build their own state and may omit all three.

Key Type Default Meaning
format string required unless idealized txt or netcdf; any other value is rejected. txt reads a sounding through TxtReader.
source_file string required unless idealized Path to the profile used to initialize pressure, thermodynamics, and winds. Required whenever format is txt.
perturbation string "none" Initial perturbation preset: none, 2dbubble, or 3dbubble. Skipped entirely when restart.enable is true.
constant_upper_wind.enable bool false Hold winds above pressure_threshold_Pa constant while reading the text profile.
constant_upper_wind.pressure_threshold_Pa real 25000.0 Pressure threshold for that handling.
reapply_spatial_initial_conditions bool false Re-read netcdf_reader.source_file after the base state is assigned, so spatial fields overwrite anything the profile/topography path derived. Applied before restart loading.
rcemip_consistent_reference_state bool false Correct two reference-state errors on the rcemip vertical coordinate. Ignored on every other coordinate. See below.

!!! warning "rcemip_consistent_reference_state changes results"

Only meaningful when `grid.vertical_coordinate_type` is `rcemip`. With it
off — the default — the reference state is built the way v1.0.0 built it:
the Exner function uses a hardcoded exponent of `2/7` instead of
`constants.Rd / constants.Cp`, and the density is `p/(Rd*T)` rather than
`p/(Rd*Tv)`. Both are wrong, and the second is the larger error: omitting
the virtual-temperature correction makes the initial density about 0.9 %
too high for a moist RCEMIP sounding.

The default is `false` because `tests/references/rcemip.json` encodes the
v1.0.0 numbers. Turning it on shifts `Tbar` by 0.043 K, `pibar` by 5.9e-5,
`rhobar` and `rhobar_up` by 0.37 % in the mean, and the surface fluxes by
0.9 %, so `Verify_physics_rcemip` fails until the reference is regenerated
with `tests/scripts/check_output.py --update --digest-dtype float32`.

!!! note "pressure_threshold_Pa has two different fallbacks"

The profile reader falls back to `25000.0` Pa, but the area-mean nudging
forcing (`dynamics.forcings.areamn`) falls back to `3000.0` Pa for the same
key. If you enable both `constant_upper_wind` and `areamn`, set the key
explicitly so the two agree.

Default-case profiles live under rundata/initial_conditions/profiles/default_cases/. The profile must be consistent with the vertical coordinate choice and the physics you enable.

For an ordinary, non-idealized run, copy this input block and replace the profile path:

{
  "initial_conditions": {
    "format": "txt",
    "source_file": "./rundata/initial_conditions/profiles/default_cases/profile_dry.txt",
    "perturbation": "none",
    "constant_upper_wind": {
      "enable": false,
      "pressure_threshold_Pa": 25000.0
    },
    "reapply_spatial_initial_conditions": false,
    "rcemip_consistent_reference_state": false
  }
}

netcdf_reader

Spatial two-dimensional fields such as longitude, latitude, topography, land mask, vegetation, soil, and surface parameters.

Key Type Default Meaning
source_file string required unless idealized Spatial NetCDF file, usually under rundata/initial_conditions/spatial/. When absent, no spatial read happens at all.
Tg_source string "atmosphere" atmosphere derives ground temperature from the atmospheric state at the topography level; netcdf keeps the Tg field read from the file. Any other value keeps existing values and warns.
variables_to_read.1d list (empty) 1-D variables to read from the file.
variables_to_read.2d list (empty) 2-D variables to read. Typically lon, lat, topo, sea_land_ice_mask, vegtype, soiltype, slopetype, Tg, albedo, gvf, lai, shdmax, shdmin.
variables_to_read.3d list (empty) 3-D variables to read. Enabled tracers and their _source fields are always appended to this list, whether or not it is given.

Every listed variable must exist in the file — a missing one is an error, not a warning. The default spatial NetCDF files can be generated with tools/generate_init_nc.py. For Taiwan-style cases, generate or prepare the file before submission; see TaiwanVVM example.

For the small default cases, this is the matching spatial-input block. Remove fields from the list when the file does not contain them:

{
  "netcdf_reader": {
    "source_file": "./rundata/initial_conditions/spatial/default_cases/init_regression_test.nc",
    "Tg_source": "atmosphere",
    "variables_to_read": {
      "1d": [],
      "2d": ["lon", "lat", "topo", "sea_land_ice_mask"],
      "3d": []
    }
  }
}

restart

Whether the model initializes prognostic fields from an existing output file.

Key Type Default Meaning
enable bool false Enables restart loading.
source_file string required when enabled Restart source. .h5 goes through the HDF5 restart reader, .bp through the BP5 restart reader, .nc through the PnetCDF reader; any other extension is an error.
legacy_time_s real (none) Elapsed simulation seconds to resume from, for a file that stores no clock of its own. Explicit opt-in; warns when used.
allow_filename_time_fallback bool false Restores the old behaviour of deriving the restart time from the digits in the file name (index * file_interval_s). Warns loudly when enabled.
file_interval_s real 3600.0 Seconds represented by one numbered output index. Consulted only when allow_filename_time_fallback is true.
ignore_stored_step bool false Discard the model_step stored in the file and re-derive the step from simulation.dt_s. Use when dt was deliberately changed on restart.
step_index int -1 BP5 only. Which ADIOS2 step of the .bp dataset to resume from; -1 is the last one written. An .h5 file holds a single time, so this key has no meaning there.
variables_to_read.1d list (none) Explicit 1-D restart variable list.
variables_to_read.2d list (none) Explicit 2-D restart variable list.
variables_to_read.3d list inferred Explicit 3-D restart variable list. See below for how it is inferred.

If no explicit restart.variables_to_read.3d is supplied, the reader (HDF5 or BP5 — they share this selection) selects prognostic variables from dynamics.prognostic_variables and filters them through output.fields_to_output. That means fields needed after restart should either be listed explicitly under restart.variables_to_read or be included in output.fields_to_output.

When restart is enabled, the restart state replaces the normal perturbation initialization.

How the restart time and step are recovered

The simulation clock comes from metadata stored inside the restart file, never from its name. Renaming a restart file does not change the time it resumes from. Output files carry two scalars for this:

Variable Meaning
model_time_s Elapsed simulation time in seconds (double).
model_step Exact integration-step count (64-bit integer).

The model tries, in order:

  1. Stored time and stored step. They are cross-checked against simulation.dt_s; if time and step * dt disagree by more than a serialization tolerance the run stops and prints both values, the configured dt, the expected time and the source file. Neither value is silently preferred.
  2. Stored time alone, with step = round(time / dt).
  3. restart.legacy_time_s, for files predating the metadata. Prints a rank-0 warning.
  4. The digits in the file name, only when restart.allow_filename_time_fallback is true. Prints a prominent rank-0 warning, because the file name then is the clock.

Without one of these the run stops rather than guessing. The recovered values are broadcast from rank 0, so every rank resumes from an identical time and step, and rank 0 reports them:

[Initializer] Restart metadata: time=7200 s, step=3600 (source: file model_time_s + model_step)

NetCDF restart sources are written outside this model, so only unambiguous metadata is accepted: model_time_s / model_step as scalar variables or as global attributes, or a time variable whose units attribute says plain seconds. A calendar time ("hours since ...") is deliberately not read as an elapsed time — such a file needs restart.legacy_time_s.

Restart files are ordinary output files; there is no separate restart output path. What each engine leaves behind to restart from:

output.engine Restart source it produces Read by
HDF5 <prefix>_NNNNNN.h5, one per output time Hdf5RestartReader
SST the same .h5 files, written by the I/O server rather than the compute ranks Hdf5RestartReader — SST is a transport, not a restart format
BP5 <prefix>.bp, one dataset holding every output time Bp5RestartReader, which also needs step_index

The keys above are the same for all three; only step_index is engine-specific, because only BP5 stores more than one time per source. Field selection and clock recovery are shared code, so the same run resumes identically whichever of the three wrote its source.

Copy-ready restart configurations

Copy the example matching the desired output behavior and merge its top-level blocks into the case file. These examples resume at t = 3600 s and run until t = 7200 s.

HDF5 restart into a new output directory

This also applies to an .h5 restart file produced by SST.

{
  "simulation": {
    "total_time_s": 7200.0,
    "dt_s": 1.0,
    "output_interval_s": 600.0
  },
  "restart": {
    "enable": true,
    "source_file": "./output/my_case/vvm_output_000006.h5"
  },
  "output": {
    "engine": "HDF5",
    "output_dir": "./output/my_case_resumed",
    "output_filename_prefix": "vvm_output",
    "output_initial_step": true,
    "precision": "native",
    "fields_to_output": [
      "thbar", "rhobar", "topo", "u", "v", "w",
      "th", "qv", "xi", "eta", "zeta"
    ]
  }
}

BP5 restart into a new dataset

Use this when the original history should remain unchanged and the resumed run should create ./output/my_case_resumed/vvm_output.bp.

{
  "simulation": {
    "total_time_s": 7200.0,
    "dt_s": 1.0,
    "output_interval_s": 600.0
  },
  "restart": {
    "enable": true,
    "source_file": "./output/my_case/vvm_output.bp",
    "step_index": -1
  },
  "output": {
    "engine": "BP5",
    "output_dir": "./output/my_case_resumed",
    "output_filename_prefix": "vvm_output",
    "output_initial_step": true,
    "precision": "native",
    "fields_to_output": [
      "thbar", "rhobar", "topo", "u", "v", "w",
      "th", "qv", "xi", "eta", "zeta"
    ],
    "bp5": {
      "num_subfiles": 2,
      "existing_dataset": "error"
    }
  }
}

BP5 restart and append to the same dataset

Use this to preserve the old steps and add new steps to ./output/my_case/vvm_output.bp.

{
  "simulation": {
    "total_time_s": 7200.0,
    "dt_s": 1.0,
    "output_interval_s": 600.0
  },
  "restart": {
    "enable": true,
    "source_file": "./output/my_case/vvm_output.bp",
    "step_index": -1
  },
  "output": {
    "engine": "BP5",
    "output_dir": "./output/my_case",
    "output_filename_prefix": "vvm_output",
    "output_initial_step": false,
    "precision": "native",
    "fields_to_output": [
      "thbar", "rhobar", "topo", "u", "v", "w",
      "th", "qv", "xi", "eta", "zeta"
    ],
    "bp5": {
      "num_subfiles": 2,
      "existing_dataset": "append"
    }
  }
}

The append safeguards are intentional: the source and destination must resolve to the same .bp dataset, step_index must be -1, and output_initial_step must be false. This prevents truncating later history or writing the restart step twice.

For every restart:

  • total_time_s is the absolute end time, not time to add after restarting.
  • Required restart fields must exist in the source. Keep them in output.fields_to_output, or set restart.variables_to_read explicitly.
  • The first step uses first-order history initialization because AB2 tendency history is not stored, so a restart is not bit-for-bit identical to an uninterrupted run.

output

ADIOS2 output, field selection, and optional subsetting. Engine trade-offs and sizing guidance are in Output.

Key Type Default Meaning
output_dir string required Destination directory. submit.py creates it before launching.
output_filename_prefix string required Base name for the files, the .bp dataset, or the SST stream.
engine string "HDF5" HDF5 (one file per output time), SST (streams to dedicated I/O ranks), or BP5 (one multi-step .bp dataset written directly by compute ranks).
fields_to_output list required Ordered list of state fields to write. A name the run never registered is skipped with a message; on HDF5 and SST a name that is not a known optional field either is an error, so typos are still caught. Must be non-empty and duplicate-free for BP5.
precision string "native" On-disk float type for field data only, on every engine: native (follows VVM::Real), float32/float/single, or float64/double. Case-insensitive. Clocks and coordinates always stay VVM::Real. Narrowing output narrows what a later restart recovers, on whichever engine produced the restart source.
output_initial_step bool true Write step 0 before the first model step.
output_grid.x_start, .y_start, .z_start int 0 Inclusive lower index bound per direction.
output_grid.x_end, .y_end, .z_end int -1 Inclusive upper index bound; -1 means "to the end". Halo cells are never written.

For normal HDF5 history, copy this block and set the output directory and field list. hdf5_collective_mpio is included at its default so it is easy to change when a parallel filesystem benefits from collective I/O.

{
  "output": {
    "output_dir": "./output/my_run",
    "output_filename_prefix": "vvm_output",
    "engine": "HDF5",
    "fields_to_output": ["u", "v", "w", "th", "qv"],
    "precision": "native",
    "output_initial_step": true,
    "output_grid": {
      "x_start": 0, "x_end": -1,
      "y_start": 0, "y_end": -1,
      "z_start": 0, "z_end": -1
    },
    "hdf5_collective_mpio": false
  }
}

output — HDF5 only

Key Type Default Meaning
hdf5_collective_mpio bool false Use collective MPI-IO in the HDF5 engine instead of independent writes.

output — SST only

Key Type Default Meaning
queue_limit int 1 ADIOS2 SST queue depth. The queue-full policy is Block, so a small value keeps the writers close to the readers.
data_transport string "WAN" SST data plane: WAN (sockets), RDMA, or empty/AUTO to let ADIOS2 choose. Case-insensitive.
control_transport string "sockets" SST control plane.

For SST, replace the HDF5 output block with this one and launch with submit.py --io <number-of-io-ranks>:

{
  "output": {
    "output_dir": "./output/my_run",
    "output_filename_prefix": "vvm_output",
    "engine": "SST",
    "fields_to_output": ["u", "v", "w", "th", "qv"],
    "precision": "native",
    "output_initial_step": true,
    "output_grid": {
      "x_start": 0, "x_end": -1,
      "y_start": 0, "y_end": -1,
      "z_start": 0, "z_end": -1
    },
    "queue_limit": 1,
    "data_transport": "WAN",
    "control_transport": "sockets"
  }
}

output.bp5

Read only when engine is BP5. Unknown keys and invalid values are errors, and every resolved setting is compared across compute ranks before opening the dataset.

For a normal run, copy this block and change the directory, prefix, fields, and subfile count:

{
  "output": {
    "engine": "BP5",
    "output_dir": "./output/my_run",
    "output_filename_prefix": "vvm_output",
    "output_initial_step": true,
    "precision": "native",
    "fields_to_output": ["u", "v", "w", "th", "qv"],
    "bp5": {
      "aggregation_type": "TwoLevelShm",
      "num_subfiles": 10,
      "stats_level": 0,
      "async_write": false,
      "buffer_mode": "direct",
      "existing_dataset": "error"
    }
  }
}

Choose how an existing target is handled:

existing_dataset Behavior
"error" Safe default. Stop if <output_dir>/<prefix>.bp already exists.
"replace" Delete and recreate an existing dataset. Use only when its history is disposable; it cannot replace the active restart source.
"append" Continue the same BP5 restart dataset. Use the complete in-place append example.

Most runs only need num_subfiles and existing_dataset. The remaining keys are optional performance controls:

Key Default Meaning
aggregation_type "TwoLevelShm" Currently the only accepted value.
num_subfiles 10 Positive requested data subfile count. ADIOS2 caps it at the compute-rank count.
stats_level 0 0 minimises statistics work; 1 enables BP5 statistics. Other values are rejected.
async_write false Enables ADIOS2 background writing.
buffer_mode "direct" direct uses CPU memory selection when compatible; pack uses staging buffers. CUDA and precision conversion automatically resolve to packed staging.

Do not use output.bp5.overwrite or output.bp5.precision in new cases. They remain accepted only for compatibility: overwrite: false/true maps to existing_dataset: "error"/"replace", while BP5-scoped precision overrides the engine-neutral output.precision. A configuration cannot contain both overwrite and existing_dataset.

!!! note "num_subfiles can only ever reduce the file count"

ADIOS2 writes one subfile per aggregator and cannot have more aggregators
than ranks, so the value is clamped. Measured on a 2-step case:

| ranks \ requested | 1 | 2 | 4 | 10 |
| --- | --- | --- | --- | --- |
| 1 | 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 2 | 2 |
| 4 | 1 | 2 | 4 | 4 |

The default of `10` therefore means "one per rank" for any run below 10
ranks — a 4-rank run writes 4 subfiles whatever you ask for. The knob is
only useful downwards: lower it to concentrate output into fewer, larger
files when a filesystem dislikes many concurrent writers.

Use fields_to_output deliberately. A large list is convenient for diagnostics but increases file size and I/O cost. Common field groups are:

Field group Examples
Base state thbar, pibar, rhobar, rhobar_up
Dynamics u, v, w, th, xi, eta, zeta
Moisture/P3 qv, qc, qr, qi, qm, nc, nr, ni, bm
Radiation sw_heating, lw_heating, swdn, lwdn, lwup, swup_toa, swdn_toa, lwup_toa, lwdn_toa, swup_sfc, swdn_sfc, lwup_sfc, lwdn_sfc
Surface/land Tg, sfc_flux_th, sfc_flux_qv, sfc_flux_u, sfc_flux_v, le, hfx, st1, st2, st3, st4, gfx, topo

dynamics

dynamics.solver

Key Type Default Meaning
w_solver_method string required Vertical velocity solver: tridiagonal for the original method, jacobi for the 3D-parallel iteration path.
iteration int required Fixed iteration count for the iterative solver path.
WRXMU real required Relaxation/control parameter used by the wind solver.

The solver settings are required. This is the small-case starting point used by the shipped examples:

{
  "dynamics": {
    "solver": {
      "w_solver_method": "tridiagonal",
      "iteration": 200,
      "WRXMU": 2.5e-7
    }
  }
}

dynamics.forcings.sponge_layer

Damps selected fields above sponge_layer_base.

Key Type Default Meaning
enable bool false Turns sponge-layer forcing on.
damp_thermo bool true Damp thermodynamic variables.
damp_vort bool true Damp vorticity variables.
sponge_layer_base real -1 Height in meters where damping begins.
inv_CRAD real -1.0 Inverse damping timescale used to build the damping coefficient.

dynamics.forcings.random_perturbation

Useful for triggering convection in otherwise smooth initial states.

Key Type Default Meaning
enable bool false Turns random forcing on.
time_s real 50.0 Apply perturbations until this simulated time.
amplitude real 1.0 Perturbation magnitude.
z_start_m, z_end_m real 0 Vertical layer where perturbations are applied.
random_seed int 12345 Seed for deterministic perturbations. A seed, timestep, and global cell coordinate always produce the same value, independent of scheduling and MPI decomposition.

Copy this block to make the perturbation settings explicit. Leave enable false for the model default, or turn it on and adjust only the layer, duration, amplitude, and seed.

{
  "dynamics": {
    "forcings": {
      "random_perturbation": {
        "enable": false,
        "time_s": 50.0,
        "amplitude": 1.0,
        "z_start_m": 0.0,
        "z_end_m": 0.0,
        "random_seed": 12345
      }
    }
  }
}

dynamics.forcings.lateral_boundary_nudging

Relaxes selected variables toward large-scale forcing near selected boundaries.

Key Type Default Meaning
enable bool false Turns nudging on.
boundaries.west, .east, .south, .north bool false Which boundaries are nudged.
tau_b real 300.0 Nudging timescale in seconds.
offset real 2500.0 Distance from the boundary at which the nudging zone starts, in meters.
width real 600.0 Width of the nudging zone, in meters.
radius real 2500.0 Corner-taper radius, in meters.
target_vars list ["th", "qv"] Variables to nudge.
forcing_data.time_varying bool false Select forcing files by time using file_prefix and update_interval_s instead of using one fixed file.
forcing_data.directory string "../rundata/LS_forcings/" Directory containing large-scale forcing files.
forcing_data.file_name_for_not_varying string "ls_forcing_constant.nc" File used when forcing is constant in time.
forcing_data.file_prefix string "ls_forcing_" Prefix for time-varying forcing files.
forcing_data.update_interval_s real 3600.0 Time spacing between time-varying forcing files.

dynamics.forcings.areamn

Stores and relaxes area-mean vorticity/wind reference quantities.

Key Type Default Meaning
enable bool false Turns area-mean nudging on.
uvtau real 0.0 Relaxation timescale/control value.
nudge_start_m real 0.0 Height in meters where nudging starts.
target_source string "initial" Where the nudging target comes from: initial holds the initial-state area means, netcdf reads them from the forcing files. Any other value is an error.
forcing_data.directory string required when target_source is netcdf Directory containing the forcing files.
forcing_data.file_prefix string "ls_forcing_" Prefix for the forcing files.
forcing_data.update_interval_s real 3600.0 Time spacing between forcing files. Must be positive.

Copy this complete default forcing block when you want every forcing setting to be explicit. All forcings remain off until their individual enable key is set to true.

{
  "dynamics": {
    "forcings": {
      "sponge_layer": {
        "enable": false,
        "damp_thermo": true,
        "damp_vort": true,
        "sponge_layer_base": -1.0,
        "inv_CRAD": -1.0
      },
      "random_perturbation": {
        "enable": false,
        "time_s": 50.0,
        "amplitude": 1.0,
        "z_start_m": 0.0,
        "z_end_m": 0.0,
        "random_seed": 12345
      },
      "lateral_boundary_nudging": {
        "enable": false,
        "boundaries": {
          "west": false, "east": false, "south": false, "north": false
        },
        "tau_b": 300.0,
        "offset": 2500.0,
        "width": 600.0,
        "radius": 2500.0,
        "target_vars": ["th", "qv"],
        "forcing_data": {
          "time_varying": false,
          "directory": "../rundata/LS_forcings/",
          "file_name_for_not_varying": "ls_forcing_constant.nc",
          "file_prefix": "ls_forcing_",
          "update_interval_s": 3600.0
        }
      },
      "areamn": {
        "enable": false,
        "uvtau": 0.0,
        "nudge_start_m": 0.0,
        "target_source": "initial"
      }
    }
  }
}

dynamics.prognostic_variables

An object whose keys are field names. Each names the tendency terms that advance it and the schemes each term uses.

{
  "dynamics": {
    "prognostic_variables": {
      "th": {
        "tendency_terms": {
          "advection": {
            "enable": true,
            "temporal_scheme": "AdamsBashforth2",
            "spatial_scheme": "Takacs"
          }
        }
      }
    }
  }
}
Key Type Default Meaning
<var>.tendency_terms object (none) Terms to apply. Term names: advection, buoyancy, stretching, twisting, coriolis. An unknown name is an error.
<var>.tendency_terms.<term>.enable bool true Skip the term when false. A disabled term is reported as [Disabled] at startup.
<var>.tendency_terms.<term>.spatial_scheme string required Takacs, MUSCL, or weno5.
<var>.tendency_terms.<term>.temporal_scheme string "AdamsBashforth2" AdamsBashforth2, ForwardEuler, or SSPRK2.
<var>.tendency_terms.<term>.scheme_options object (none) Scheme-specific options; see below.

Fields listed here are allocated whether or not they exist by default, so a typo creates a new, unused field rather than failing. Common prognostic variables are th, xi, eta, zeta, qv, qc, qr, qi, qm, nc, nr, ni, and bm. P3-related fields should be present when P3 is enabled.

Coriolis is a special case: it is enabled only when all three of xi, eta, and zeta set tendency_terms.coriolis.enable to true. Enabling it on one or two of them leaves it off.

Scheme pairing rules

Rejected combinations stop the run at startup rather than silently degrading:

Spatial scheme Requires Allowed on
Takacs any prognostic field and term
MUSCL temporal_scheme: SSPRK2 advection of a thermodynamic scalar or configured tracer
weno5 temporal_scheme: SSPRK2, grid.n_halo_cells >= 3, and advection as the field's only enabled term advection of a configured passive tracer

SSPRK2 is only available with MUSCL or weno5.

scheme_options for MUSCL

Key Type Default Meaning
limiter string "vanLeer" The only supported limiter.
lower_bound real 0.0 Nonnegative floor applied by the limiter.
max_cfl real 0.9 CFL cap; must be greater than zero.

Use MUSCL only for the advection of one thermodynamic scalar or configured tracer. Its temporal scheme must be SSPRK2, and that field cannot have any other enabled tendency. Merge this into a copied case; the grid block shows the minimum halo requirement and must retain the case's other grid keys.

{
  "grid": {
    "n_halo_cells": 2
  },
  "dynamics": {
    "prognostic_variables": {
      "th": {
        "tendency_terms": {
          "advection": {
            "enable": true,
            "temporal_scheme": "SSPRK2",
            "spatial_scheme": "MUSCL",
            "scheme_options": {
              "limiter": "vanLeer",
              "lower_bound": 0.0,
              "max_cfl": 0.9
            }
          }
        }
      }
    }
  }
}

scheme_options for WENO5

Key Type Default Meaning
epsilon real 1.0e-6 Nonlinear-weight epsilon; must be finite and positive. No other key is accepted here.

WENO5 is only for passive-tracer advection. It requires SSPRK2, no other enabled tendency for that tracer, and at least three halo cells. Each MPI rank also needs at least three physical x and y cells when those directions have more than one global cell.

{
  "grid": {
    "n_halo_cells": 3
  },
  "dynamics": {
    "tracers": {
      "tracer1": {
        "enable": true,
        "tendency_terms": {
          "advection": {
            "enable": true,
            "temporal_scheme": "SSPRK2",
            "spatial_scheme": "weno5",
            "scheme_options": {
              "epsilon": 1.0e-6
            }
          }
        }
      }
    }
  }
}

The WENO5 coefficients assume uniform spacing, so only the uniform horizontal x and y directions use WENO reconstruction. Vertical tracer transport retains the existing Takacs scheme, including its stretched-grid metric and boundary handling. The default epsilon is the reference value used for regression testing; because it is dimensional, simulations with very different tracer magnitudes or floating-point precision may need to configure it. WENO5 is not available for vorticity or other dynamical-core advection.

dynamics.tracers

An object of passive tracers, each allocated as a 3-D field and advanced by the advection configuration given under the same key.

Key Type Default Meaning
<name>.enable bool true Skip the tracer entirely when false.
<name>.source.enable bool true when source is present Allocate a companion <name>_source tendency field, read from the spatial NetCDF file alongside the tracer itself.
<name>.tendency_terms object (none) Same shape as a prognostic variable, but advection is the only supported term.

Tracer names are validated against every field VVMex allocates and every name reserved by the initial-condition and output formats, and against internal suffixes (d_*, fe_tendency_*, *_m, *_ls). A collision is an error at startup, not a silent overwrite.

physics

Copy this default physics block, then enable only the packages needed by the case. column_chunk_size is deliberately omitted: its default is every column on the rank, so no fixed number is correct for all runs.

physics.p3

Key Type Default Meaning
enable_p3 bool false Enables P3 microphysics.
make_lookup_table bool false Generate the P3 lookup table instead of reading the shipped one.
do_predict_nc bool true Predict cloud droplet number concentration.
do_prescribed_ccn bool false Use prescribed CCN.
max_total_ni real 2000.0e3 Cap on total ice number concentration.

physics.turbulence

Key Type Default Meaning
enable_turbulence bool false Enables the subgrid turbulence scheme, which produces RKM/RKH.

physics.surface_process

Key Type Default Meaning
enable bool false Enables the surface process wrapper.
frequency_s real 1 Surface/land/ocean call frequency in seconds. Should divide evenly by simulation.dt_s.
land_scheme string "none" none or noahlsm. noahlsm calls the Fortran Noah land model on land points.
ocean_scheme string "none" none, sflux_2d, sflux_tc_2d, or tco_ocean.

Choosing sflux_2d or sflux_tc_2d uses the C++ surface-flux implementation for ocean points and disables the ocean part inside the land process. grid.vertical_coordinate_type: rcemip also relaxes the surface wind-speed floor from 1e-3 to 1.

physics.rrtmgp

Key Type Default Meaning
enable_rrtmgp bool false Enables RRTMGP radiation. When on, th additionally integrates a forward-Euler radiative tendency.
rad_frequency_s real 1.0 Radiation call frequency in seconds. Should divide evenly by simulation.dt_s.
column_chunk_size int all columns on the rank Columns processed per chunk. Larger is usually faster but uses more memory; tune with domain size and rank count.
pool_size_multiplier real 1.0 Scales the radiation memory pool.
active_gases list ["h2o","co2","o3","n2o","co","ch4","o2","n2"] Gases passed to RRTMGP.
do_aerosol_rad bool false Include aerosol optics.
extra_clnsky_diag bool false Extra clean-sky diagnostics.
extra_clnclrsky_diag bool false Extra clean-clear-sky diagnostics.

Prescribed gas volume mixing ratios

Surface values, mol/mol. Used for any gas in active_gases that the model does not carry itself.

Key Default Key Default
co2vmr 355.03e-6 o2vmr 0.209
n2ovmr 320e-9 n2vmr 0.7906
ch4vmr 1700e-9 f11vmr 0.0
covmr 1.0e-7 f12vmr 0.0
o3vmr 0.3017e-7

Sun and calendar

Key Type Default Meaning
time.year, .month, .day, .hour, .minute, .second int -9999 Calendar start time driving the solar cycle. -9999 leaves the component unset. Note time.hour is also read by the output layer (defaulting to 16 there) to derive the GrADS start hour as (hour + 8) % 24.
orbital_eccentricity real -9999.0 Override Earth's orbital eccentricity. Values below zero mean "use the default orbit".
orbital_obliquity real -9999.0 Override the obliquity.
orbital_mvelp real -9999.0 Override the moving vernal equinox longitude of perihelion.
fixed_total_solar_irradiance real -9999.0 When positive, prescribes an invariant TOA solar constant (W m⁻²) instead of the orbital one. For idealized experiments such as RCE.
fixed_solar_zenith_angle real -9999.0 When positive, this value is used directly as the cosine of the solar zenith angle for every column, bypassing the orbital calculation.
{
  "physics": {
    "p3": {
      "enable_p3": false,
      "make_lookup_table": false,
      "do_predict_nc": true,
      "do_prescribed_ccn": false,
      "max_total_ni": 2000000.0
    },
    "turbulence": { "enable_turbulence": false },
    "surface_process": {
      "enable": false,
      "frequency_s": 1.0,
      "land_scheme": "none",
      "ocean_scheme": "none"
    },
    "rrtmgp": {
      "enable_rrtmgp": false,
      "rad_frequency_s": 1.0,
      "pool_size_multiplier": 1.0,
      "active_gases": ["h2o", "co2", "o3", "n2o", "co", "ch4", "o2", "n2"],
      "co2vmr": 0.00035503,
      "o2vmr": 0.209,
      "n2ovmr": 3.2e-7,
      "n2vmr": 0.7906,
      "ch4vmr": 1.7e-6,
      "f11vmr": 0.0,
      "f12vmr": 0.0,
      "covmr": 1.0e-7,
      "o3vmr": 3.017e-8,
      "time": {
        "year": -9999, "month": -9999, "day": -9999,
        "hour": -9999, "minute": -9999, "second": -9999
      },
      "orbital_eccentricity": -9999.0,
      "orbital_obliquity": -9999.0,
      "orbital_mvelp": -9999.0,
      "fixed_total_solar_irradiance": -9999.0,
      "fixed_solar_zenith_angle": -9999.0
    }
  }
}

optimization

Key Type Default Meaning
cuda_graph_halo_exchange list (none) Fields whose halo exchange is captured into a CUDA graph, e.g. ["u", "w", "xi", "eta", "zeta", "th"] plus hydrometeors. Ignored on CPU builds.

Only include fields that exist in the current state and are exercised by the run. If you disable a physics package, remove its fields from the list unless the code still allocates them for your case.

performance.timing

Controls the built-in timing instrumentation. All optional.

Key Type Default Meaning
enable bool true Collect timers at all.
warmup_steps int 0 Skip this many steps before any timer records, so JIT, first-touch allocation and graph capture do not land in the averages.
fence_gpu bool false Fence the device around each timed region. Gives correct per-region GPU times at the cost of removing asynchrony — use it for attribution, not for headline throughput numbers.
print_interval_steps int 0 Print the timing report every N steps. 0 prints only at the end of the run.
reset_after_interval_print bool false Zero the accumulators after each interval print, so each report covers only the interval rather than the run so far.

Copy this block when you need explicit timing controls:

{
  "performance": {
    "timing": {
      "enable": true,
      "warmup_steps": 0,
      "fence_gpu": false,
      "print_interval_steps": 0,
      "reset_after_interval_print": false
    }
  }
}

constants

Key Type Default Meaning
gravity real required Gravitational acceleration.
Rd real required Dry-air gas constant.
Cp real required Heat capacity at constant pressure.
Lv real required Latent heat of vaporization.
P0 real required Reference pressure.
PI real required Pi.
OMEGA real 7.292e-5 Earth rotation rate, used by the default latitude-dependent Coriolis parameter.

Coriolis on an f- or beta-plane

Present constants.coriolis_parameter and the latitude-dependent formula is replaced by a plane approximation, f = f0 + beta * (y - y_ref). Absent, the sphere formula using OMEGA is used, so existing configurations are unchanged.

Key Type Default Meaning
coriolis_parameter real (absent) f0. Its presence is what switches on the plane approximation.
coriolis_beta real 0.0 Meridional gradient of f. Left at zero this is an f-plane.
coriolis_reference_y_m real domain centre y_ref, in meters.

Change constants only for controlled sensitivity experiments.

These are the required constants and the default Earth rotation rate. Copy the block only when creating a case from scratch; ordinary cases should retain the values already supplied by the chosen default case.

{
  "constants": {
    "gravity": 9.806,
    "Rd": 287.04,
    "Cp": 1004.5,
    "Lv": 2500000.0,
    "P0": 100000.0,
    "PI": 3.14159265,
    "OMEGA": 7.292e-5
  }
}

Keys that look real but are not read

These appear in some shipped sample configurations and have no effect. They are listed so you do not spend time tuning them:

Key Status
output.enable_netcdf Never read. Output engine selection is output.engine alone.
optimization.cuda_graph_solver Never read. Only optimization.cuda_graph_halo_exchange exists.
constants.PSFC Never read. A PSFC parameter view is allocated but nothing assigns it from the configuration. Surface pressure comes from the sounding profile.

Consistency checklist

Before submitting a long run, check:

  • physics.rrtmgp.rad_frequency_s, physics.surface_process.frequency_s, and simulation.output_interval_s are sensible multiples of simulation.dt_s.
  • Every output.fields_to_output name is allocated by the selected dynamics/physics configuration.
  • If output.engine is SST, submit with submit.py --io N. If it is HDF5 or BP5, omit --io.
  • grid.n_halo_cells is 3 if any tracer uses weno5.
  • If restart.enable is true, the restart file stores model_time_s/model_step (or an elapsed-seconds time); otherwise set restart.legacy_time_s explicitly. The file name no longer affects the restart time.
  • The NetCDF variables listed in netcdf_reader.variables_to_read.2d exist in netcdf_reader.source_file.
  • P3 hydrometeor variables are present in dynamics.prognostic_variables when physics.p3.enable_p3 is true.
  • CUDA graph field lists match the fields actually allocated in the run.
  • Optional keys you added are spelled exactly as in this page — a typo is silently ignored.

CMake and environment

Library paths and compilers are not set in this JSON file. Use CMakePresets.json and CMake cache variables for HDF5, NetCDF, PnetCDF, NVHPC, Kokkos, and MPI (see Quick Start).