icon_sc.icon.presets — validated composition presets

Validated ICON composition presets (architecture §4.2/§5.1; S09+).

A preset is a builder: it assembles components, coupling operators and the tendency-bus wiring into one composition object plus a matching initial state, so run scripts stay legible and diff-clean against the preset (S14 adds the plan-hash regression enforcing that). S09 ships the single-column (SCM) preset; the full NWP preset arrives with the dycore lane.

The single-column (SCM) preset: SUS fast physics + slow-tendency bus (SPEC S09).

The first scientifically meaningful ICON-sc composition — the architecture-§5.1 loop shape at column scale, running under T0:

  • fast suite: SequentialUpdateSplitting over SCM_FAST_ORDER = ("satad", "mphys", "satad") — the SCM subset of ICON’s fast-physics calling sequence (tutorial §3.7.2 / mo_nh_interface_nwp.f90, REFERENCES.lock icon-tutorial-2025 + icon-fortran-nwp-interface: saturation adjustment before, and again after, microphysics “to ensure that vapor and liquid phase are in equilibrium before entering the slow physics parameterizations”);

  • slow suite: a CallingFrequency-wrapped PrescribedCooling inside a ConcurrentCoupling, publishing a piecewise-constant tendency to the icon:ddt_temperature_slow bus slot at cadence slow_timestep (tutorial §3.7.2: slow tendencies are “kept constant between two successive calls”);

  • consumer: ApplySlowTendencies standing in for the dycore’s slow-tendency port; the SlowTendencyBus single-consumer check runs at build time, so a preset without the consumer refuses to build.

The tutorial’s ordering prose is carried as machine-checkable constraints (SCM_COUPLING_CONSTRAINTS, applied to the built instances): swapping sections against them raises CouplingConstraintError at composition time (acceptance 4).

Initial column (PLAN item 3, provenance): the S06 moist_test_column() "reference_moist" profile — T/p from the ICON decaying-isothermal reference atmosphere (mo_vertical_grid.f90) with an exponentially decaying water-vapor profile — made convectively/condensationally unstable by scaling the humidity (qv_scale, default 2: the lower troposphere starts supersaturated, so satad condenses immediately and graupel precipitates), plus the cloud droplet number concentration icon:qnc the graupel scheme consumes (ICON default cloud_num = 200e6 m⁻³, gscp_data.f90, REFERENCES.lock icon-fortran-graupel).

icon_sc.icon.presets.scm.SCM_COUPLING_CONSTRAINTS: Final[Mapping[str, CouplingConstraints]] = {'mphys': CouplingConstraints(must_follow=('satad',), must_precede=('satad',), admissible_operators=('sequential_update_splitting',))}

Tutorial-§3.7.2 ordering semantics as machine-checkable constraints, keyed by the SCM_FAST_ORDER section names and applied to the built instances (the S07/S08 classes declare only admissible_operators — an ordering constraint against satad cannot live on the Graupel class without outlawing the bare satad → graupel compositions the S08 suite validates): microphysics must come after a saturation adjustment and be followed by one.

icon_sc.icon.presets.scm.SCM_FAST_ORDER: Final[tuple[str, str, str]] = ('satad', 'mphys', 'satad')

the satad → microphysics → satad subset of ICON’s NWP fast-physics order (tutorial §3.7.2; the full NWP_FAST_ORDER arrives with the P3 schemes).

Type:

The SCM fast-physics calling sequence (frozen interface, SPEC S09)

class icon_sc.icon.presets.scm.SCMComposition(slow, cooling, core, fast, bus, order)

The built SCM composition: §5.1 loop pieces + one step to drive them.

step is the loop body of the canonical run script at column scale (architecture §5.1): slow-tendency publication into the bus slots, the consumer (dycore stand-in), then the fast SUS suite. It matches the icon_sc.core.driver.timeloop() StepFn shape.

Parameters:
slow: ConcurrentCoupling

ConcurrentCoupling of CallingFrequency-wrapped processes.

Type:

The slow suite

cooling: CallingFrequency

The CallingFrequency wrapper around the cooling (cadence/phase accessors).

core: ApplySlowTendencies

The bus consumer (dycore stand-in for the slow-tendency port).

fast: SequentialUpdateSplitting

The fast-physics SequentialUpdateSplitting federation.

bus: SlowTendencyBus

The composition-time bus bookkeeping (checked by the builder).

order: tuple[str, ...]

The fast-suite section order the federation was built with.

step(state, timestep)

One Δt of the SCM loop body; returns the advanced state (T0 semantics).

Parameters:
Return type:

dict[str, Any]

visit(plan_builder)

S14 plan-compiler hook: compile exactly the step() sequence.

The loop body has no single S04 operator (S09 STATUS deviation) — the walk dispatches its three pieces in step order: the slow suite as a top-level publishing coupling (tendencies land in their bus-slot state cells, cadence masks preserved), then the consumer, then the fast federation.

Parameters:

plan_builder (Any)

Return type:

None

class icon_sc.icon.presets.scm.SCMConfig(nlev=65, n_cell=1, dtime=datetime.timedelta(seconds=30), slow_timestep=datetime.timedelta(seconds=300), qv_scale=2.0, qnc=200000000.0, start_time=<factory>, cooling=<factory>, satad=<factory>, microphysics=<factory>)

Configuration of the SCM preset (architecture §5.3 style: typed, frozen).

slow_timestep defaults to exactly 10 · dtime (SPEC acceptance 3); any positive value is legal — a non-multiple is rounded to the nearest multiple of the loop timestep by the frozen S03 CallingFrequency rule (the tutorial §3.7.1 rounds up; see STATUS S09).

Parameters:
nlev: int = 65

Vertical levels of the S06 default (flat-terrain) ICON grid.

n_cell: int = 1

Horizontal extent (independent columns; the preset is single-column).

dtime: timedelta = datetime.timedelta(seconds=30)

Fast-physics / loop timestep Δt.

slow_timestep: timedelta = datetime.timedelta(seconds=300)

Slow-physics cadence (default 10·Δt).

qv_scale: float = 2.0

Humidity scaling of the reference_moist profile (module docstring).

qnc: float = 200000000.0

Cloud droplet number concentration [m-3] (ICON default cloud_num).

start_time: Any

Initial model time.

cooling: PrescribedCoolingConfig

Newtonian-cooling (slow forcing) parameters.

satad: SaturationAdjustmentConfig

Saturation-adjustment configuration (both SUS occurrences share it).

microphysics: GraupelConfig

Microphysics (graupel scheme) configuration.

icon_sc.icon.presets.scm.build_scm(cfg=None, *, ctx=None, fast_order=None, consume_slow=True)

Build the SCM preset: (composition, initial_state, cfg) (SPEC S09).

ctx defaults to the embedded (debug) backend. fast_order and consume_slow are experiment/test knobs off the validated preset: a fast_order violating SCM_COUPLING_CONSTRAINTS raises CouplingConstraintError at composition (acceptance 4), and consume_slow=False (the consumer removed) is rejected by the bus single-consumer check with BusError (acceptance 3) — experimental knobs never inherit the validated-preset label (architecture §4.2).

Parameters:
Return type:

tuple[SCMComposition, dict[str, Any], SCMConfig]

The Jablonowski-Williamson dry-model preset: dycore + diffusion (SPEC S13).

build_jw(JWConfig(...)) assembles the composed dry model of architecture §5.1 minus physics/transport — the S12 NonhydroSolver followed by the S13 HorizontalDiffusion, exactly the per-step order of the icon4py driver (_do_dyn_substepping then diffusion.run then swap; REFERENCES.lock icon4py-driver-jw) — on the icon4py JW datatest experiment (exclaim_nh35_tri_jws, global R02B04, 35 levels).

Data/provenance: everything comes from the pinned icon4py datatest archive — the serialized grid savepoint (ICON-pre-padded connectivity tables; the savepoint grid every S12 parity test hosts on), the metrics/interpolation savepoints (static state, zero conversion), and the archive’s own ICON namelist for all config values (the PLAN “config congruence” pitfall: the same provenance feeds the reference trajectory generator in validation/L4_idealized/make_reference.py, and the L4 test asserts config equality before comparing trajectories). Requires the icon-sc-icon[datatest] extra; the archive (~14 GB unpacked) downloads once into the shared cache.

The preset also carries the checkpoint diagnostics both the reference run and the ICON-sc run must compute identically (numpy, deterministic): surface pressure (icon4py diagnose_surface_pressure formula — REFERENCES.lock icon4py-diagnostics-stencils), vn norms, and the 850 hPa relative-vorticity proxy (vertex curl via geofac_rot, the level fixed at build time from the initial pressure profile).

class icon_sc.icon.presets.jw.JWConfig(perturbation_amplitude=1.0, backend='gtfn_cpu')

JW preset knobs. Everything not listed here comes from the archive namelist.

Parameters:
  • perturbation_amplitude (float)

  • backend (str)

perturbation_amplitude: float = 1.0

1.0 = the classic baroclinic wave (JW06 §4); 0.0 = the zonally symmetric steady state (the archive’s own configuration).

Type:

ICON nh_test_nml:jw_up [m/s]

class icon_sc.icon.presets.jw.JWModel(dycore, diffusion, composition, state, dtime, provenance, level_850, step, checkpoint)

The composed dry model + initial state + checkpoint diagnostics.

S14 additive extension (declared in the S14 STATUS): composition is the dycore→diffusion sequence as one bindable SequentialUpdateSplitting — the tree ExecutionPlan.bind compiles and ctx.timeloop runs under either tier; step remains the equivalent T0 closure (the L4 runner’s entry). state now carries the slow-tendency bus slots explicitly as zero fields: under tier="plan" the __call__ zero-fill convenience is bypassed (S12 STATUS follow-up — decision: the plan compiler does not synthesize default slots; the bound state is explicit), and under T0 the dycore sees the same zeros it would have synthesized, bitwise.

Parameters:
provenance: Mapping[str, Any]

archive-derived run provenance (asserted against the reference’s in L4).

level_850: int

model level used for the 850 hPa vorticity proxy (fixed at build time).

step: Callable[[Mapping[str, Any], timedelta], dict[str, Any]]

step(state, dt) -> new state (dycore then diffusion, driver order).

checkpoint: Callable[[Mapping[str, Any]], dict[str, ndarray]]

checkpoint diagnostics on a state dict (numpy; identical for both runs).

icon_sc.icon.presets.jw.build_jw(cfg=None)

Assemble the JW dry model on the pinned icon4py JW datatest experiment.

Parameters:

cfg (JWConfig | None)

Return type:

JWModel