icon_sc.core — top level

The execution context, the component registry, time handling, and configuration/provenance.

ComputeContext with the S05 execution-tier surface (architecture §5.2, §8.2).

The one object threaded through component construction. It carries the backend — an opaque name string, or (since S07, the first real gt4py component) a Backend object bundling the gt4py program processor and allocator — the strict-mode flag (§2.4), an allocator choosing numpy or cupy, and — since S05 — the execution tier ("interpret" = T0 reference dispatch, "plan" = the §8.2 bind + T1 interpreter) plus the bound loop timestep the plan compiler treats as a bind-time constant.

ctx.timeloop(state, composition, ...) is the canonical entry of §5.1’s run script: under tier="interpret" it is the plain T0 loop over the composed step; under tier="plan" it performs the bind (negotiation happens exactly once) and interprets the frozen plan — nothing sympl-shaped executes per step.

Components allocate their private and output fields through the context; nothing else in ICON-sc touches devices directly (§5.2).

class icon_sc.core.context.Allocator(*args, **kwargs)

Minimal allocator protocol: uninitialized device buffers by shape/dtype.

class icon_sc.core.context.ComputeContext(backend, strict=True, allocator=None, tier='interpret', timestep=None)

Compute context (frozen interface, SPEC S03; S05 adds tier/timestep).

ComputeContext(backend, strict=True, allocator=..., tier=..., timestep=...) — backend is an opaque string (embedded/gtfn_cpu/gtfn_gpu) or, since S07, a Backend object; when allocator is not given it is derived from the backend (a Backend contributes its own allocator; a name string selects cupy for GPU-flavoured backends, numpy otherwise). strict is the §2.4 strict-mode flag consumed by the dynamic checkers on every component call.

tier selects the execution tier of timeloop() (§8.3): T0 "interpret" (default) or T1 "plan". timestep is the loop Δt the §8.2 plan compiler binds against; timeloop() stamps it, so it is usually left None at construction.

device is the DLPack device tuple of the allocator’s buffers, probed once at construction; it is the device expectation handed to the DynamicChecker.

Parameters:
property backend_name: str

The backend name string (backend itself on the opaque-string path).

property require_allocator: Allocator

The resolved allocator (never None after construction).

timeloop(state, composition, *, timestep, n_steps=None, until=None, monitors=(), debug_renegotiate_every=None)

Run composition for n_steps (or until) under this tier.

composition is any Stepper-shaped component — (state, timestep, *, out=None) -> (diagnostics, new_state) — including federations, wrappers and dynamical cores. Per step the state is advanced by the composition, time moves by timestep, then monitors store the advanced state; the final state (diagnostics included) is returned as a plain dict.

Under tier="plan" the bind (§8.2 negotiation) happens once at entry — the loop body is plan.run_step(vault, i) on the frozen plan — and debug_renegotiate_every=N re-runs the negotiation every N steps, diffing against the bound plan (raises PlanDriftError on drift). Under tier="interpret" the same composition runs with full T0 per-call semantics (the reference the SPEC’s T0≡T1 equivalence is stated against).

Parameters:
  • state (Mapping[str, Any])

  • composition (Any)

  • timestep (timedelta)

  • n_steps (int | None)

  • until (timedelta | None)

  • monitors (Iterable[Monitor])

  • debug_renegotiate_every (int | None)

Return type:

dict[str, Any]

Name-keyed Factory/MetaFactory registries (architecture §4.2 ← Ubbiali).

Semantics ported from the stubbiali/sympl oop fork (sympl/_core/factory.py, thesis Fig. 3.5), not the code: subclasses self-register at class-creation time (i.e. on import), keyed by their name class attribute; duplicate names are rejected; Factory.factory(name) resolves a configuration string to a class and instantiates it, raising KeyError listing the known names when the string is unknown.

Usage: a registry root subclasses Factory directly and gets a fresh registry; concrete implementations subclass the root and set name. Intermediate classes that set no name of their own stay unregistered.

class icon_sc.core.registry.Factory

Base for name-keyed registries; see module docstring for the usage pattern.

classmethod factory(name, *args, **kwargs)

Instantiate the class registered under name (KeyError if unknown).

Parameters:
Return type:

_F

class icon_sc.core.registry.MetaFactory(name, bases, namespace, **kwargs)

Metaclass performing register-on-import for Factory hierarchies.

Parameters:
exception icon_sc.core.registry.RegistrationError

A class could not be registered (duplicate name or missing registry root).

cftime-aware datetime handling and cadence arithmetic (SPEC S02).

The calendar-keyed datetime() factory ports upstream sympl’s semantics (sympl/_core/time.py, see REFERENCES.lock): proleptic_gregorian yields a stdlib datetime.datetime; every other CF calendar yields the matching cftime class (timezones are a stdlib-only feature).

Cadence arithmetic backs the §8.2 cadence masks: the distinct step signatures of a composition follow from the lcm of the component cadences and each cadence’s phase. All arithmetic is exact, over integer microseconds (timedelta resolution).

icon_sc.core.time.CALENDARS: dict[str, type] = {'360_day': <class 'cftime._cftime.Datetime360Day'>, '365_day': <class 'cftime._cftime.DatetimeNoLeap'>, '366_day': <class 'cftime._cftime.DatetimeAllLeap'>, 'all_leap': <class 'cftime._cftime.DatetimeAllLeap'>, 'gregorian': <class 'cftime._cftime.DatetimeGregorian'>, 'julian': <class 'cftime._cftime.DatetimeJulian'>, 'no_leap': <class 'cftime._cftime.DatetimeNoLeap'>, 'noleap': <class 'cftime._cftime.DatetimeNoLeap'>, 'standard': <class 'cftime._cftime.DatetimeGregorian'>}

CF calendar name → cftime datetime class (upstream sympl’s calendar keying).

icon_sc.core.time.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, calendar='proleptic_gregorian')

Datetime-like object for the requested CF calendar (sympl semantics).

Parameters:
Return type:

datetime | datetime

icon_sc.core.time.is_due(elapsed, period, cadence_phase=datetime.timedelta(0))

True when a cadence with the given period/phase fires at elapsed.

A cadence fires at phase, phase + period, phase + 2*period, …; elapsed is time since composition start (non-negative).

Parameters:
Return type:

bool

icon_sc.core.time.phase(offset, period)

offset modulo period, normalized into [0, period) (exact).

Parameters:
Return type:

timedelta

class icon_sc.core.time.timedelta

Difference between two datetime values.

timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)

All arguments are optional and default to 0. Arguments may be integers or floats, and may be positive or negative.

total_seconds()

Total seconds in the duration.

days

Number of days.

seconds

Number of seconds (>= 0 and less than 1 day).

microseconds

Number of microseconds (>= 0 and less than 1 second).

icon_sc.core.time.timedelta_lcm(*deltas)

Least common multiple of positive timedeltas (exact, integer microseconds).

The lcm of the component cadences (Δt, dt_conv, dt_rad, …) is the period of the step-signature pattern the plan compiler precomputes (§8.2).

Parameters:

deltas (timedelta)

Return type:

timedelta

Configuration base and provenance stamping (architecture §5.3).

Typed, layered, Pythonic: components declare frozen dataclasses subclassing Config; validation happens at construction via the Config.validate() hook (ranges, cross-field constraints). provenance_stamp() produces the reproducibility record (config content hash + package versions + timestamp) that monitors stamp into every output artifact.

class icon_sc.core.config.Config

Frozen-dataclass config base: subclass with @dataclass(frozen=True).

__post_init__ invokes validate(), so invalid configurations cannot be constructed. Per-field metadata={"icon_namelist_origin": ...} documents the ICON namelist variable an option corresponds to (§5.3).

validate()

Override to enforce ranges and cross-field constraints; raise ValueError.

Return type:

None

replace(**changes)

A modified copy (re-validated on construction).

Parameters:
  • self (_C)

  • changes (Any)

Return type:

_C

to_dict()

Nested plain-dict form (stable field order).

Return type:

dict[str, Any]

icon_sc.core.config.provenance_stamp(config=None, **extra)

Provenance record for an output artifact (§5.3).

Keys: created_at (UTC ISO), python, packages (name → version), config (nested dict) + config_sha256 when a config is given, plus any extra key/values the caller stamps (grid UUIDs, git SHAs, experiment ids).

Parameters:
Return type:

dict[str, Any]