observed_field
Stable function · Simulation
Tier: stable · Kind: function · Topic: Simulation
| Julia | TypeScript | Python | Rust | Go |
|---|---|---|---|---|
observed_field | outside profile | observed_field | observed_field | outside profile |
Julia
observed_field(prob::EsmProblem, name::AbstractString; u, t)
observed_field(prob::EsmProblem, name; u = nothing, t = nothing) -> Vector{Float64}
The observed name of the problem, as a flat vector in row-major cell order
(last index fastest; one element for a scalar observed).
With no u, it is the field the BUILD defines: a state-free observed evaluated
with the parameters the problem was built with, at t = 0 unless t is given.
With u — a state vector laid out like prob.u0, such as sol.u[k] — it is
the observed at that state and time t (default 0), which is how a
STATE-DEPENDENT observed is read; t is sol.t[k] for a saved solution point.
A read at a state or time binds the problem’s own parameters prob.p, so on a
remake(prob; p = …) it answers with the substituted values.
Under compiler = :native the value comes from a program compiled once per
problem and name — the same array cascade as the right-hand side, run over the
state — so a read costs one pass over the field whatever u and t are. Under
compiler = :interpreter it is the build-time cellwise evaluator, the oracle the
compiled program agrees with bit for bit. The first read of a name files an
:observed row in compiler_report
naming the route
(:output_compiled, or :output_compiled_once / :output_percell for the
cellwise evaluator); an observed native cannot compile is refused by name.
Two arguments (API_SPEC §5.8): the problem owns its own
BuildInspection
, so none is passed here. Pass your own via
esm_problem(...; inspect = insp) if you also want to read the sink directly.
u and t are keywords, not arguments: the result has the rank of the field
whatever they are, which API_SPEC §5.8 lets a binding that can overload spell
this way.
Resolution is the cross-binding rule of API_SPEC §5.8, in precedence order:
- Exact hit —
nameis a flattened observed name ("ISRM.deathsK"). - Bare name —
namecarries no., and the document has exactly ONE component; it then resolves to the unique observed with that tail ("deathsK").
A bare name against a MULTI-component document is refused, with every qualified candidate named, rather than bound to an arbitrary one.
Throws a SimulateError when name is not an evaluable observed (an unsized
axis, or not an observed at all), or when it reads the state and no u was
given.
Example (simulate)
prob = esm_problem(joinpath(FIXTURES, "decay.esm"), (0.0, 10.0))
@assert prob isa EsmProblem
λ = 0.1
sol = solve(prob, Tsit5(); saveat = [0.0, log(2) / λ, 10.0], reltol = 1e-8)
@assert sol.retcode == ReturnCode.Success
# A solution is indexed by the flattened variable name, as a Symbol.
N = sol[Symbol("Decay.N")]
@assert N[1] == 100.0
@assert isapprox(N[2], 50.0; rtol = 1e-5) # half left after one half-life
# Observed variables are read off the problem. half_life is a scalar field.
half_life = only(observed_field(prob, "half_life"))
@assert half_life ≈ log(2) / λ
From docs/api/examples/julia/simulate.jl
Example (esm_problem_parameters)
# Override a parameter's default at construction.
faster = esm_problem(joinpath(FIXTURES, "decay.esm"), (0.0, 10.0);
p = Dict("lambda" => 0.2))
@assert only(observed_field(faster, "half_life")) ≈ log(2) / 0.2
TypeScript
Not available in TypeScript. TypeScript is outside the simulation capability profile (Julia, Python, Rust): build an RHS and integrate it; TypeScript and Go are deliberately non-simulating.
Python
observed_field(prob: EsmProblem, name: str)
Evaluate/read the state-free observed name at BUILD time through the
EsmProblem’s own graph — the const-geometry hoist already materialized it; this
resolves the name against those products. Raises SimulationError
when name is not a build-time-evaluable observed of the EsmProblem.
Resolution is the cross-binding rule of API_SPEC §5.8, in precedence order:
- Exact hit —
nameis a flattened field name (Sites.North.u). - Bare name —
namecarries no., and the problem has exactly ONE component; it then resolves to the unique field with that tail.
A bare name against a MULTI-component problem is refused, with every qualified candidate named, rather than bound to an arbitrary one.
Two arguments in every binding (API_SPEC §5.8): build observability moved to a construction-time seam, so no caller has to thread a BuildInspection through to read a field back.
Example (observed_field)
# What the build computed for an observed that does not depend on the state.
assert math.isclose(earthsci_ast.observed_field(prob, "half_life"), half_life)
Rust
pub fn observed_field(prob: &EsmProblem, name: &str) -> Result<ArrayD<f64>, SimulateError>
The build-time field named name, from prob’s construction.
Resolution is the cross-binding rule of API_SPEC §5.8
(resolve_observed_key), in precedence order:
- Exact hit —
nameis a stored key. - Component-qualified hit —
nameis a stored key’squalifyd spelling (ISRM.E_PM25for the pipeline’sE_PM25). - Bare name —
namecarries no., and the problem has exactly ONE component; it then resolves to the unique field with that tail.
A bare name against a MULTI-component problem is refused rather than bound
to an arbitrary candidate. Reads the build pipeline’s fields, the state-free
static evaluation’s fields, and — when ProblemOptions::inspect was set —
the array runtime’s materialized setup arrays. One arity, (prob, name),
in every binding.
Go
Not available in Go. Go is outside the simulation capability profile (Julia, Python, Rust): build an RHS and integrate it; TypeScript and Go are deliberately non-simulating.