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=...)—backendis an opaque string (embedded/gtfn_cpu/gtfn_gpu) or, since S07, aBackendobject; whenallocatoris not given it is derived from the backend (aBackendcontributes its own allocator; a name string selects cupy for GPU-flavoured backends, numpy otherwise).strictis the §2.4 strict-mode flag consumed by the dynamic checkers on every component call.tierselects the execution tier oftimeloop()(§8.3): T0"interpret"(default) or T1"plan".timestepis the loop Δt the §8.2 plan compiler binds against;timeloop()stamps it, so it is usually leftNoneat construction.deviceis the DLPack device tuple of the allocator’s buffers, probed once at construction; it is the device expectation handed to theDynamicChecker.- Parameters:
- timeloop(state, composition, *, timestep, n_steps=None, until=None, monitors=(), debug_renegotiate_every=None)¶
Run
compositionforn_steps(oruntil) under this tier.compositionis 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,timemoves bytimestep, 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 isplan.run_step(vault, i)on the frozen plan — anddebug_renegotiate_every=Nre-runs the negotiation every N steps, diffing against the bound plan (raisesPlanDriftErroron drift). Undertier="interpret"the same composition runs with full T0 per-call semantics (the reference the SPEC’s T0≡T1 equivalence is stated against).
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.
- class icon_sc.core.registry.MetaFactory(name, bases, namespace, **kwargs)¶
Metaclass performing register-on-import for
Factoryhierarchies.
- 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).
- 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, …;elapsedis time since composition start (non-negative).
- icon_sc.core.time.phase(offset, period)¶
offsetmoduloperiod, normalized into[0, period)(exact).
- 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).
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__invokesvalidate(), so invalid configurations cannot be constructed. Per-fieldmetadata={"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
- 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_sha256when a config is given, plus anyextrakey/values the caller stamps (grid UUIDs, git SHAs, experiment ids).