Models API
The Models module contains the runtime stepper — TransportModel, DrivenSimulation, the IC pipeline, and the recipe builders that turn a TOML config into a fully-wired runtime object.
AtmosTransport.Models.DrivenSimulation Type
DrivenSimulationLow-level window-driven runtime for custom driver/model wiring.
Most TOML-based runs should go through run_driven_simulation, which builds and validates this object for you. Construct DrivenSimulation directly only when you need a custom met driver, callback loop, or model assembly.
A DrivenSimulation keeps transport-window timing and forcing in the driver, while the model retains ownership of prognostic tracer and air-mass state. The runtime interpolates forcing within each met window and advances the model with the same step!(model, Δt) entry point used by the fixed-flux smoke harness.
For experienced users, the constructor is meant to be assembled from the same pieces used by run_driven_simulation: a met driver, a basis-compatible state, empty flux storage owned by the model, and a runtime physics recipe. A minimal LL/RG manual setup looks like this:
using TOML, AtmosTransport
using AtmosTransport.MetDrivers: air_mass_basis, driver_grid, flux_kind
# First run examples/generate_synthetic_quickstart.jl from the terminal.
cfg = TOML.parsefile("config/examples/minimal_template.toml")
paths = expand_binary_paths(cfg["input"])
FT = Float64
driver = TransportBinaryDriver(first(paths); FT = FT, arch = CPU())
recipe = build_runtime_physics_recipe(cfg, driver, FT)
validate_runtime_physics_recipe(recipe, driver)
grid = driver_grid(driver)
window1 = load_transport_window(driver, 1)
Basis = air_mass_basis(driver) === :dry ? DryBasis : MoistBasis
air = copy(window1.air_mass)
vmr = build_initial_mixing_ratio(
air, grid, Dict("kind" => "uniform", "background" => 400e-6);
surface_pressure = window1.surface_pressure,
)
co2 = pack_initial_tracer_mass(grid, air, vmr; mass_basis = Basis())
state = CellState(Basis, air; CO2 = co2)
fluxes = allocate_face_fluxes(grid.horizontal, nlevels(grid);
FT = FT, basis = Basis)
model = TransportModel(state, fluxes, grid, recipe.advection;
diffusion = recipe.diffusion,
convection = recipe.convection)
sim = DrivenSimulation(model, driver;
stop_window = min(total_windows(driver), 24),
chemistry = recipe.chemistry)
run_window!(sim)The full runner adds the practical edges around this skeleton: resolving many daily binaries, GPU adaptation, surface-flux source construction, snapshot output, progress reporting, and capability checks against every file.
SurfaceFluxSource lives with the surface-flux operator in src/Operators/SurfaceFlux/.
AtmosTransport.Models.DrivenSimulation Method
DrivenSimulation(model, driver; kwargs...)Construct a window-driven src runtime.
Keyword arguments:
start_window=1stop_window=total_windows(driver)initialize_air_mass=trueuse_midpoint_forcing=trueinterpolate_fluxes_within_window=nothing(derive from driver)air_mass_reset_mode=:preserve_tracer_mass— one of:none,:preserve_vmr, or:preserve_tracer_mass. When non-:none, each newly loaded window replaces prognostic air mass using the selected tracer invariant. For binary-scheduled runs, the same endpoint reset is applied before the once-per-window convection/chemistry block so physics sees the binary's authoritative window-end mass.surface_sources=()chemistry=NoChemistry()— applied after advection + surface sources each stepcallbacks=NamedTuple()start_time=0— simulation clock origin [s]. Multi-binary runners MUST pass the accumulated run time here when rebuilding the sim per binary:sim.timefeedscurrent_time(meteo), which time-varying surface-flux sources use to select their emission slice (seconds since the RUN start, not the binary start). Restarting the clock at 0 each day silently replays day-1 fluxes — the December-2021 co2_natural +1 Pg/month surplus (plan 45 Stage-4 A/B experiment attributed the leak to exactly this).
AtmosTransport.Models.Simulation Type
SimulationLow-level fixed-step harness for custom in-memory experiments.
Most users should call run_driven_simulation with a run config. Use Simulation only when you already constructed a TransportModel and want to drive it with a custom time loop.
AtmosTransport.Models.TransportModel Type
TransportModel(state, fluxes, grid, advection; kwargs...)Minimal Oceanigans-style model object for standalone src transport runs.
Carries advection, chemistry, vertical diffusion, surface emissions, and convection operators. The step composition is: transport_block(dt) → convection_block(dt) → chemistry_block(dt)
where transport_block runs the full palindrome with diffusion and emissions at the center:
X → Y → Z → V(dt/2) → S(dt) → V(dt/2) → Z → Y → X (emissions active)
X → Y → Z → S(dt) → V(dt) → Z → Y → X (diffusive boundary coupling)
X → Y → Z → V(dt) → Z → Y → X (no emissions)step!(model, dt) executes the full runtime composition: transport block → convection block → chemistry block.
Defaults chemistry = NoChemistry(), diffusion = NoDiffusion(), emissions = NoSurfaceFlux(), and convection = NoConvection() make the inactive operator slots compile to no-op dispatches.
Convection fields
convection :: ConvT— operator type, defaults toNoConvection(). Concrete subtypes areCMFMCConvectionandTM5Convection.NoConvectionis a compile-time dead branch instep!.convection_forcing :: CF— per-step forcing container. Defaults toConvectionForcing()(all-nothing placeholder).DrivenSimulationconstruction allocates real buffers viaallocate_convection_forcing_like;_refresh_forcing!populates them fromsim.window.convectioneach substep.
Helpers with_convection(model, op) and with_convection_forcing(model, forcing) parallel with_chemistry / with_diffusion / with_emissions.
AtmosTransport.Models.advection_spec Method
advection_spec(section) -> AbstractAdvectionSpecParse an [advection] section into a typed spec. ppm_order is only meaningful for scheme = "linrood"; pairing it with scheme = "ppm" is rejected (the split PPM path takes no order knob). An omitted selector defaults to upwind; an omitted Lin–Rood ppm_order defaults to 5.
AtmosTransport.Models.build_runtime_chemistry Method
build_runtime_chemistry(cfg, ::Type{FT}) -> AbstractChemistryOperatorRead the optional [chemistry] TOML section and produce the corresponding chemistry operator.
Supported kind values:
"none"(default) —NoChemistry()."decay"—ExponentialDecay(FT; ...). Half-lives are read from thehalf_lives_secondstable:[chemistry] kind = "decay" [chemistry.half_lives_seconds] rn222 = 330350.4 # 3.8235 daysThe keyword name must match the corresponding
[tracers.<name>]symbol that the run is carrying (case-insensitive — the builder symbolizes the key as-is andExponentialDecay.apply!resolves it againststate.tracer_namesat call time).
Thin wrapper: parse the [chemistry] section into a typed AbstractChemistrySpec once (validated), then materialize at run precision FT. Spec types + parser live in RuntimePhysicsSpecs.jl.
AtmosTransport.Models.build_runtime_physics_recipe Method
build_runtime_physics_recipe(cfg, context, FT; halo_width=nothing)Parse typed advection, diffusion, convection, and chemistry specifications from cfg, materialize them for context and floating-point type FT, then run the complete runtime compatibility validation.
sourceAtmosTransport.Models.chemistry_spec Method
chemistry_spec(section) -> AbstractChemistrySpecParse a [chemistry] section into a typed spec. kind = "decay" with an empty (or absent) half_lives_seconds table reduces to NoChemistrySpec. Each half-life must be numeric, non-Boolean, and positive. Values are stored as Float64 seconds and converted to tracer precision during materialization.
AtmosTransport.Models.convection_chemistry_step! Method
convection_chemistry_step!(model::TransportModel, dt; meteo = nothing)Advance the non-transport physics blocks once: convection block → chemistry block.
sourceAtmosTransport.Models.convection_spec Method
convection_spec(section) -> AbstractConvectionSpecParse a [convection] TOML section into a typed spec, validating at the boundary.
Nondefault lmax_conv/n_merge require use_collab_lu = true; otherwise parsing throws an ArgumentError. They affect the workgroup-collaborative solver only. Eligibility is checked against the backend, tracer precision, and state depth at execution time. The legacy fallback uses the full column without aggregation.
AtmosTransport.Models.diffusion_spec Method
diffusion_spec(section) -> AbstractDiffusionSpecParse a [diffusion] section into a typed spec, validating at the boundary. An empty/absent section or kind = "none" is explicit "no diffusion". The legacy type = "..." schema is rejected (it used to silently fall through to NoDiffusion, hiding configs that expected diffusion to run); a present section with no kind is rejected too.
AtmosTransport.Models.run! Method
run!(simulation)Advance a Simulation or DrivenSimulation until its configured stop condition. Returns the mutated simulation.
sourceAtmosTransport.Models.run_window! Method
run_window!(sim::DrivenSimulation)Advance exactly the current meteorological window and return sim. If sim is positioned at a completed non-final window, the next window is loaded first.
sourceAtmosTransport.Models.step! Method
step!(model::TransportModel, dt; meteo = nothing)Advance model.state by one full runtime step: transport block (advection with vertical diffusion at the palindrome center, surface emissions wrapped by the two V half-steps when active) → convection block → chemistry block.
With defaults diffusion = NoDiffusion(), emissions = NoSurfaceFlux(), chemistry = NoChemistry(), convection = NoConvection(), every live component is a dead branch and the call is bit-exact equivalent to the advection-only path.
meteo is optional and defaults to nothing; pass a real meteorology object (AbstractMetDriver) or a DrivenSimulation to thread current_time(meteo) through operators that consume time-varying fields.
AtmosTransport.Models.transport_step! Method
transport_step!(model::TransportModel, dt; meteo = nothing)Advance model.state by one transport step: advection with vertical diffusion at the palindrome center and surface emissions. The diffusion operator's coupling policy selects either V(dt/2) -> S(dt) -> V(dt/2) or S(dt) -> V(dt) when both diffusion and a surface source are active.
Binary-scheduled driven runs use this block at the per-window advection substep cadence stored in the transport binary. Convection and chemistry are separate physics blocks and can run at the met-window cadence via convection_chemistry_step!.
AtmosTransport.Models.validate_runtime_physics_recipe Method
validate_runtime_physics_recipe(recipe, context; halo_width=nothing)Validate topology support, binary capabilities, and halo requirements for a materialized RuntimePhysicsRecipe. Returns recipe or throws ArgumentError before model allocation.
sourceAtmosTransport.Models.with_chemistry Method
with_chemistry(model::TransportModel, chemistry)Return a copy of model with its chemistry operator replaced. All other fields share storage with the original. Chemistry is installed into the model rather than held at the sim level, so this helper is primarily useful for tests that want to swap chemistry on a constructed model.
AtmosTransport.Models.with_convection Method
with_convection(model::TransportModel, convection)Return a copy of model with its convection operator replaced. All other fields — including convection_forcing — share storage with the original.
Note: with_convection does NOT allocate convection-forcing buffers. The model-side ConvectionForcing() placeholder stays as-is. DrivenSimulation construction is responsible for allocating real buffers via allocate_convection_forcing_like after the first window loads. For tests that bypass the sim layer, use with_convection_forcing(model, forcing) to inject allocated buffers directly. The model workspace is re-wrapped as needed so concrete operators can carry their own scratch storage without disturbing the advection workspace.
AtmosTransport.Models.with_convection_forcing Method
with_convection_forcing(model::TransportModel, forcing::ConvectionForcing)Return a copy of model with its per-step convection-forcing container replaced. All other fields — including the convection operator — share storage with the original.
Used by DrivenSimulation construction to install the allocated forcing buffers after the first window loads. Also useful for tests that inject forcing directly without going through the sim's _refresh_forcing! path.
AtmosTransport.Models.with_diffusion Method
with_diffusion(model::TransportModel, diffusion)Return a copy of model with its diffusion operator replaced. All other fields share storage with the original. Parallel to with_chemistry; useful for installing a diffusion operator into a model that was constructed with the default NoDiffusion().
AtmosTransport.Models.with_emissions Method
with_emissions(model::TransportModel, emissions)Return a copy of model with its surface-emissions operator replaced. All other fields share storage with the original. Parallel to with_chemistry and with_diffusion; used by DrivenSimulation to install the sim-level surface_sources tuple as a SurfaceFluxOperator inside the wrapped model, so the palindrome's S slot runs at the right place in the transport block without sim-level post-step hacks.
AtmosTransport.Models.InitialConditionIO Module
InitialConditionIOSingle owner of initial-condition I/O, vertical remap, and topology-dispatched VMR builders for the unified runtime.
Public API (exported via Models → AtmosTransport)
build_initial_mixing_ratio— topology-dispatched builder returning dry VMR on interior cells. Acceptskind = uniform | latitude_step | gaussian_blob | file | netcdf | file_field | catrine_co2for LL/RG meshes, plusbl_enhancedon LL. CS supports those shared kinds pluspressure_layerand signedcs_nativefields.pack_initial_tracer_mass— basis-aware VMR → conservative model storage conversion. Dispatches onmass_basis::AbstractMassBasis:DryBasis(default per CLAUDE.md invariant 14):rm = vmr .* air_mass.MoistBasis:rm = vmr .* air_mass .* (1 .- qv)per CLAUDE.md invariant 9;qvmust be supplied.
FileInitialConditionSource— container for a loaded IC NetCDF (3D VMR + hybrid coefficients + surface pressure).
Contents
LL/RG and CS
build_initial_mixing_ratiofor the kinds above. CSpressure_layerselects a level per column from the stored surface pressure and normalizes its dry VMR to the configured global molecule count.Basis-aware
pack_initial_tracer_mass(DryBasis + MoistBasis); CS output is halo-padded with the halo zeroed._build_source_latlon_meshhelper for LL→CS conservative regridding.Surface-flux NetCDF loader (13 helpers +
FileSurfaceFluxFieldstruct) and LL/RGbuild_surface_flux_sourcemethods; CSbuild_surface_flux_sourceconservatively LL→CS-regrids the flux (the regridder'sdst_areas× regridded density already yields kg/s per cell) and unpacks toNTuple{6, Matrix{FT}}— satisfying the per-cell kg/s contract atsrc/Operators/SurfaceFlux/sources.jl:12.
Private helpers (underscore-prefixed) stay unexported and are accessed by callers (including the canonical driven runtime) via AtmosTransport.Models.InitialConditionIO.<name> if needed.
AtmosTransport.Models.InitialConditionIO.FileInitialConditionSource Type
FileInitialConditionSource{FT}Container for a file-based initial condition (e.g. Catrine startCO2).
Fields
raw— 3D mixing ratio field(nlon_src, nlat_src, nlevel_src). Level ordering follows the source file (Catrine: k=1 is SURFACE, k=end is TOA — verify viaap[1]+bp[1]*ps ≈ ps).lon,lat— source coordinate vectors [degrees]. May be in [-180,180) or [0,360); the bilinear sampler wraps to [0,360) internally viawrapped_longitude_360.ap,bp— hybrid half-level coefficients(nlevel_src + 1):p_half[k] = ap[k] + bp[k] × ps_src. Units:ap[Pa],bp[dimensionless].psurf— surface pressure(nlon_src, nlat_src)[Pa].needs_vinterp—trueif source levels ≠ target levels (triggers log-pressure vertical interpolation in_interpolate_log_pressure_profile!).
AtmosTransport.Models.InitialConditionIO.FileSurfaceFluxField Type
FileSurfaceFluxField{FT}2-D flux density (Nx_src, Ny_src) loaded from a NetCDF emission file. Units are kg/m²/s after _load_file_surface_flux_field has normalised the native units. native_total_mass_rate is the pre-regrid global integral, preserved for the bilinear path's renormalisation (the conservative path does not need it).
AtmosTransport.Models.InitialConditionIO.TimeVaryingFileSurfaceFluxField Type
TimeVaryingFileSurfaceFluxField{FT}A stack of 2-D flux-density slices (Nx_src, Ny_src, ntime) loaded from a NetCDF emission file, keeping every time slice (no monthly averaging). Units are kg/m²/s after _load_timevarying_surface_flux_field has normalised the native units, identically per slice. times_sec holds the slice times in seconds since the run reference_time, ascending.
AtmosTransport.Models.InitialConditionIO.build_initial_mixing_ratio Method
build_initial_mixing_ratio(air_mass, mesh, cfg)
build_initial_mixing_ratio(air_mass, grid::AtmosGrid, cfg; surface_pressure=nothing)Construct the initial dry-air volume mixing ratio described by cfg on the horizontal topology and vertical layout of air_mass.
Bare lat-lon and reduced-Gaussian meshes support the analytic uniform, latitude_step, and gaussian_blob modes; bl_enhanced is lat-lon only. Passing an AtmosGrid additionally enables file-backed modes (file, netcdf, file_field, and catrine_co2) with topology-aware horizontal mapping and log-pressure vertical interpolation. Cubed-sphere construction requires an AtmosGrid and also supports pressure_layer and cs_native. File-backed and pressure-layer construction require the transport window's surface_pressure where indicated by the selected mode. Each public call owns fresh output arrays. The driven cubed-sphere runner separately reuses private interior buffers between analytic initializers before copying each tracer into its independent packed state slot.
Returns an array shaped like air_mass for lat-lon and reduced-Gaussian grids, or an NTuple{6} of interior (Nc, Nc, Nz) arrays for cubed-sphere grids.
AtmosTransport.Models.InitialConditionIO.build_surface_flux_source Method
build_surface_flux_source(grid::AtmosGrid{<:CubedSphereMesh},
tracer_name, cfg, ::Type{FT})CS surface-flux builder. Conservatively LL→CS regrids the 2-D flux density (kg/m²/s) onto the 6 CS panel cell centres, multiplies by each panel's cell area to yield per-cell kg species/s, then converts that physical rate to the model storage basis. Returns a SurfaceFluxSource whose cell_mass_rate is an NTuple{6, Matrix{FT}} of interior-only (Nc, Nc) panels.
cfg must set kind (non-none); any of the file-based surface-flux kinds _load_file_surface_flux_field understands work (gridfed_fossil_co2 or user-supplied file + variable). Conservative regridding is enforced — CS bilinear is not supported.
If cfg["time_varying"] = true and the kind supports a 3-D (lon,lat,time) series (currently :lmdz_co2), the builder keeps every time slice, builds the LL→CS regridder ONCE, applies it per slice, and returns a TimeVaryingSurfaceFluxSource whose cell_mass_rate_series is an NTuple{6} of (Nc, Nc, ntime) panels plus a times vector (seconds since reference_time). The default (time_varying absent/false) path is byte-identical to before.
AtmosTransport.Models.InitialConditionIO.build_surface_flux_sources Method
build_surface_flux_sources(grid, tracer_specs, ::Type{FT}; reference_time=nothing)Build surface-flux source instances for every tracer spec that requests one. Returns a tuple (possibly empty) suitable for the surface_sources = (…,) kwarg on DrivenSimulation.
reference_time (the run start DateTime) is threaded to each per-tracer builder so the time-varying CS path can align its slice times to the simulation clock. It is ignored by static sources.
AtmosTransport.Models.InitialConditionIO.pack_initial_tracer_mass Method
pack_initial_tracer_mass(grid, air_mass, vmr_dry; mass_basis::AbstractMassBasis,
qv = nothing)Convert dry volume mixing ratio vmr_dry to conservative model storage matching the binary's mass-basis contract. On DryBasis that storage is vmr_dry × dry_air_mass; it is not physical kg species. Returns new storage with the same shape as air_mass. On cubed-sphere grids this is a six-tuple of halo-padded panels, with the halos set to zero.
Dispatch
mass_basis::DryBasis—air_massism_dryper CLAUDE.md invariant 14. Result:vmr_dry .* air_mass.qvis ignored.mass_basis::MoistBasis—air_massism_moistper CLAUDE.md invariant 9. Result:vmr_dry .* air_mass .* (1 .- qv).qvmust be supplied from the first transport window; missingqverrors.
CS dispatch handles per-panel halo packing.
Arguments
grid—AtmosGridwith a lat-lon, reduced-Gaussian, or cubed-sphere mesh.air_mass— storage-shaped air mass from the transport window; a six-tuple of halo-padded 3D panels on cubed-sphere grids.vmr_dry— dry volume mixing ratio. On cubed-sphere grids, a six-tuple of interior 3D panels; otherwise the same shape asair_mass.mass_basis—DryBasis()orMoistBasis().qv— specific humidity, same shape asair_mass; required iffmass_basis isa MoistBasis.
AtmosTransport.Models.BinaryPathExpander Module
BinaryPathExpanderExpand an [input] TOML block into transport-binary file paths. Explicit lists retain the supplied order; folder/date selection sorts by date and checks continuity.
Accepted TOML shapes
# Shape A: explicit list, consumed in the supplied order
[input]
binary_paths = ["...a.bin", "...b.bin"]
# Shape B: folder + inclusive date range
[input]
folder = "~/data/.../cs_c48/.../"
start_date = "2021-12-01"
end_date = "2021-12-10"
file_pattern = "era5_transport_{YYYYMMDD}_merged1000Pa_float32.bin" # optionalShapes A and B are mutually exclusive.
Folder scanning
When folder is supplied:
readdir(folder)→ candidate filenames.Each filename is parsed for an 8-digit
YYYYMMDDtoken. Iffile_patternis supplied, the{YYYYMMDD}placeholder marks where the date lives, and the surrounding text is matched literally (as a regex). Withoutfile_pattern, any\d{8}run anywhere in the filename is used.Files parseable as dates within
[start_date, end_date]are kept; files outside the range or not matching the pattern are ignored.The resulting sorted list is verified for continuity: every date in the closed interval must be present. Missing days list in the error message.
Returns
Vector{String} with home/environment-variable expansion. Explicit paths retain their order and may remain relative to the working directory; their dates are not checked here. Folder selection sorts chronologically by parsed date and rejects missing or duplicate dates.
AtmosTransport.Models.BinaryPathExpander.expand_binary_paths Method
expand_binary_paths(input_cfg::AbstractDict) -> Vector{String}See module docstring for the accepted TOML shapes. Throws ArgumentError on mutual exclusion, missing folder, date parse failure, or gaps in the date range.
AtmosTransport.Models.InputStaging.InputStager Type
InputStagerRolling local-disk stager for the daily transport binary list. Construct from the resolved NAS binary_paths and the [input.staging] config sub-table; call staged_path_for! at each day's driver-open site and cleanup_staging! at run end.
All mutable bookkeeping (staged, tasks, failed) is touched only by the main loop thread — background tasks are pure (copy + return the path or throw), so there is no shared-state race.
AtmosTransport.Models.InputStaging.InputStager Method
InputStager(binary_paths, staging_cfg)Parse the [input.staging] sub-table and build the stager. Keys (all optional):
enabled: Bool (defaultfalse⇒ no staging, NAS paths used)dir: String (REQUIRED when enabled) — local NVMe directorylookahead_days: Int (default2)keep_behind_days: Int (default0)cleanup_on_exit: Bool (defaulttrue)
One run owns the staging directory at a time. If ownership or directory creation fails, use the original source paths. Retained copies are reused only when their recorded source metadata agrees; forcing files must stay immutable during a run.
sourceAtmosTransport.Models.InputStaging.cleanup_staging! Method
cleanup_staging!(mgr)Wait for any in-flight copies and remove all remaining staged files (when cleanup_on_exit). Safe to call unconditionally at run end.
AtmosTransport.Models.InputStaging.staged_path_for! Method
staged_path_for!(mgr, idx) -> StringReturn the path the day-idx driver should open. With staging enabled this ensures day idx is on local NVMe (blocking only if its copy is still in flight), kicks off async copies for the look-ahead window, and evicts processed days. Falls back to the NAS path if the copy failed. With staging disabled it returns the original NAS path unchanged.
AtmosTransport.Models.DrivenRunner Module
DrivenRunnerLibrary-level entry point for the driven transport runtime.
The canonical CLI, scripts/run_transport.jl, is a thin wrapper over run_driven_simulation(cfg). The library function handles LL/RG and CS runtime flows with dispatch driven by the first binary's header (inspect_binary(first_path).grid_type). Historical runner names live under scripts/deprecated/ only for reference.
Ownership boundary
Binary header (
grid_type,mass_basis,payload_sections, panel convention) — authoritative for topology and capability. Accessed here viabinary_capabilities(driver.reader)andair_mass_basis(driver).TOML
[input]— either an explicitbinary_paths = [...]list (Shape A) or afolder + start_date + end_date (+ file_pattern)block (Shape B).expand_binary_pathspreserves explicit list order and sorts folder selections by date, checking gaps and duplicates.TOML physics (
[advection]/[diffusion]/[convection]) — validated against binary capabilities byvalidate_runtime_physics_recipe/build_runtime_physics_recipebefore the loop.TOML
[tracers.*]— tracer specs consumed viabuild_initial_mixing_ratio+pack_initial_tracer_mass(basis-aware perfeedback_vmr_to_mass_basis_aware) andbuild_surface_flux_sources.
Where the physics actually runs
DrivenRunner is the orchestration layer, not the kernel layer. It opens transport binaries, builds initial state, chooses output cadence, and installs the TOML-selected operators on a TransportModel. The live physics call chain is:
build_runtime_physics_recipereads[advection],[diffusion],[convection],[chemistry], and tracer surface-flux settings and returns the operator objects._make_structured_modelor the CS model constructor installs those operators onTransportModel(state, fluxes, grid, recipe.advection; ...).DrivenSimulation(model, driver; ...)loads the current met window and wraps chemistry and surface sources into the model withwith_chemistryandwith_emissions.The runtime loop below calls
run_window!(sim)for LL/RG orstep!(sim)for CS. Those functions live inDrivenSimulation.jl.DrivenSimulation.step!refreshes time-varying forcing from the driver, then callsTransportModel.step!or, for binary-scheduled substeps,transport_step!plus an end-of-windowconvection_chemistry_step!.TransportModel.jlis where advection, surface emissions, diffusion, convection, and chemistry are applied to the state.
So, when following a run as a scientist: start here to understand data and configuration flow, then jump to DrivenSimulation.step! and TransportModel.step! to see the actual physics ordering.
GPU residency (feedback_verify_gpu_runs_on_gpu)
When [architecture].use_gpu = true or backend selects a GPU, the runner asserts that state.air_mass lives on the selected backend after model construction and prints a [gpu verified] … line. A silent CPU fallback aborts the run with a precise error message.
AtmosTransport.Models.DrivenRunner.TransportTracerSpec Type
TransportTracerSpecValidated runtime tracer configuration: tracer name, initial-condition configuration, and optional surface-flux configuration.
sourceAtmosTransport.Models.DrivenRunner.run_driven_simulation Method
run_driven_simulation(cfg::AbstractDict) -> TransportModelCanonical high-level entry point for scientists running an AtmosTransport TOML. Use this unless you are writing a custom time loop. It resolves [input] to a sorted binary list, prints a one-line summary for each binary, dispatches on the first binary's grid_type, validates physics-vs-capability, runs the loop, optionally writes topology-native snapshots, and returns the terminal TransportModel.
This function does not call the advection/diffusion/convection kernels directly. The handoff to physics happens inside the structured loop at run_window!(sim) and inside the CS loop at step!(sim). Both routes enter DrivenSimulation.step!, which refreshes forcing and then calls TransportModel.step! / transport_step! / convection_chemistry_step!.
AtmosTransport.Models.DrivenRunner.validate_config Method
validate_config(cfg::AbstractDict) -> (ok::Bool, errors::Vector{String})Check a driven runtime config and return errors without opening binary readers or allocating model state. Checks cover runtime table shapes (including input.staging, tracer init and surface_flux subtables), resolved binary paths, numeric type, backend/float compatibility, and integer run-window bounds. Shape errors are reported before value checks. Window indices accept integers, not Booleans or floating-point values.
This is not a complete physics or binary validation. Topology and payload capability checks run when run_driven_simulation inspects the first binary. GPU backend auto-detection can load and probe optional runtime packages.