Journey 05 — Diagnostics
Read the full integration receipt, export trajectory history to CSV, and enable terminal UQ envelopes when licensed.
Prerequisites: Journey 04 — tuned Robertson run works. Scenario: Every field in the result dict, plus UQ (Robertson)
Key APIs
result['failure_mode']result['ek_n_rhs']solvsrk.run(..., emit_history=True)solvsrk.run(..., emit_uq=True)solvsrk.license_has_uq()solvsrk.uq_ek_handoff_trace()
Concepts to internalize
- failure_mode — ok, max_steps, blowup, timeout, bad_arg, license — branch on these in production.
- emit_history — off by default; enable for monitoring or SciPy-style t/y export.
- UQ (SolvSRK-UQ) — single-pass terminal envelope y(T) ± σ(T); trials include it, purchased base does not.
- uq_ek_handoff_trace — audit tape for how the early-phase noise window was integrated.
Important code
The guided tour script wraps this pattern. Copy the production shape into your pipeline:
result = solvsrk.run(cfg, 3, t0, t_end, y0, rhs, jac_fn=jac,
emit_history=True)
# result['t'], result['y'] — SciPy-style arrays
if solvsrk.license_has_uq():
uq = solvsrk.run(cfg, 3, t0, t_end, y0, rhs, jac_fn=jac,
emit_uq=True, noise_sigma=1e-3)
print(uq['y_final'], uq['uq_sigma']) # terminal estimate ± bandAct-by-act walkthrough
Act 1 — Why diagnostics matter
In production you do not watch a solver run — you read its receipt. SolvSRK returns a dict you can log, assert on, and alert against. We use tuned Robertson knobs (SolvScout token or bundled preset).
| Field | Value | Notes |
|---|---|---|
knob_source | SolvScout tuned (solvsrk, high) |
Act 2 — Did it finish?
survived + failure_mode + t_reached are the go/no-go trio.
| Field | Value | Notes |
|---|---|---|
survived | True | |
failure_mode | ok | |
failure_msg | (none) | |
t_reached | 40 | |
rc | 0 | failure_mode is a string: ok, max_steps, blowup, timeout, bad_arg, license, ... |
Act 3 — Where did the work go?
SolvSRK reports front-phase and stiff-tail cost counters in the result dict, plus the handoff time between them. Use those fields for timing and support — not as a recipe to reimplement the solver.
| Field | Value | Notes |
|---|---|---|
ek_steps | 0 | |
ek_n_rhs | 0 | |
ek_wall_s | 0 | |
ek_noise_detected | False | |
cvode_steps | 613 | |
cvode_n_rhs | 795 | |
cvode_n_jac | 11 | |
cvode_wall_s | 0.002688 | |
t_handoff | 0 | |
confidence | 0 | |
total_wall_s | 0.002693 |
Act 4 — Full successful-step telemetry (emit_history)
Trajectory storage is off by default. Enable it when you need SciPy-style t/y arrays, phase labels, or live-monitoring samples. This act also writes the sampled steps to a CSV you can open in Excel or pipe into your own monitoring stack.
| Field | Value | Notes |
|---|---|---|
t_shape | (615,) | |
y_shape | (3, 615) | |
n_history | 615 | |
nfev | 795 | |
njev | 11 | |
nsteps | 613 | |
truncated | False | |
telemetry_csv | python\robertson_telemetry.csv | |
csv_rows | 615 |
Act 5 — Uncertainty quantification (UQ) — what it is
A normal solve returns one final state y_final — a single number per species. In the real world your inputs are noisy (sensor error, batch variation, model mismatch). UQ asks: if the early part of the integration saw noise at scale noise_sigma, how wide might y_final be at the end?
-
Turn it on with emit_uq=True and pass noise_sigma (how big you think the input noise is). The receipt adds uq_sigma — one uncertainty width per state component at t_end. Think of y_final as the best estimate and uq_sigma as a ± band around it for go/no-go decisions, not a full Monte Carlo cloud.
-
UQ is a licensed add-on (SolvSRK-UQ or Edge). Trials include it; purchased base SolvSRK refuses emit_uq with failure_mode=license. Check solvsrk.license_has_uq() before you call it.
| Field | Value | Notes |
|---|---|---|
license_has_uq | True |
Act 6 — Run with UQ on Robertson
We integrate Robertson with emit_uq=True and noise_sigma=1e-3 (input noise scale — tune to your instrument or model). Compare y_final to uq_sigma: small sigma means the answer is tight; large sigma means the noisy early window could have moved the endpoint a lot.
| Field | Value | Notes |
|---|---|---|
y_final | ('0.715827', '9.18553e-06', '0.284164') | |
uq_sigma | ('5e-09', '2.00599e-09', '2.00599e-09') | |
uq_t_handoff | 0 | |
noise_sigma | 0.001 |
Act 7 — Early-phase step trace (how UQ is built)
uq_ek_handoff_trace returns the (t, h, y, sigma) samples from the noisy early integration window — the steps the solver actually took before handoff. Use it to audit why uq_sigma came out large or small; it is a diagnostic tape, not a second integration.
| Field | Value | Notes |
|---|---|---|
trace_n_steps | 0 |
Guided tour output
Verified console capture from 05_diagnostics.py:
Every field in the result dict, plus UQ (Robertson)
-- Act 1 - Why diagnostics matter --
-> In production you do not watch a solver run — you read its receipt. SolvSRK returns a dict you can log, assert on, and alert against. We use tuned Robertson knobs (SolvScout token or bundled preset).
knob_source: SolvScout tuned (solvsrk, high)
-- Act 2 - Did it finish? --
-> survived + failure_mode + t_reached are the go/no-go trio.
survived: True
failure_mode: ok
failure_msg: (none)
t_reached: 40
rc: 0
-> failure_mode is a string: ok, max_steps, blowup, timeout, bad_arg, license, ...
-- Act 3 - Where did the work go? --
-> SolvSRK reports front-phase and stiff-tail cost counters in the result dict, plus the handoff time between them. Use those fields for timing and support — not as a recipe to reimplement the solver.
ek_steps: 0
ek_n_rhs: 0
ek_wall_s: 0
ek_noise_detected: False
cvode_steps: 613
cvode_n_rhs: 795
cvode_n_jac: 11
cvode_wall_s: 0.002688
t_handoff: 0
confidence: 0
total_wall_s: 0.002693
-- Act 4 - Full successful-step telemetry (emit_history) --
-> Trajectory storage is off by default. Enable it when you need SciPy-style t/y arrays, phase labels, or live-monitoring samples. This act also writes the sampled steps to a CSV you can open in Excel or pipe into your own monitoring stack.
t_shape: (615,)
y_shape: (3, 615)
n_history: 615
nfev: 795
njev: 11
nsteps: 613
truncated: False
telemetry_csv: python\robertson_telemetry.csv
csv_rows: 615
-- Act 5 - Uncertainty quantification (UQ) — what it is --
-> A normal solve returns one final state y_final — a single number per species. In the real world your inputs are noisy (sensor error, batch variation, model mismatch). UQ asks: if the early part of the integration saw noise at scale noise_sigma, how wide might y_final be at the end?
log: Turn it on with emit_uq=True and pass noise_sigma (how big you think the input noise is). The receipt adds uq_sigma — one uncertainty width per state component at t_end. Think of y_final as the best estimate and uq_sigma as a ± band around it for go/no-go decisions, not a full Monte Carlo cloud.
log: UQ is a licensed add-on (SolvSRK-UQ or Edge). Trials include it; purchased base SolvSRK refuses emit_uq with failure_mode=license. Check solvsrk.license_has_uq() before you call it.
license_has_uq: True
-- Act 6 - Run with UQ on Robertson --
-> We integrate Robertson with emit_uq=True and noise_sigma=1e-3 (input noise scale — tune to your instrument or model). Compare y_final to uq_sigma: small sigma means the answer is tight; large sigma means the noisy early window could have moved the endpoint a lot.
y_final: ('0.715827', '9.18553e-06', '0.284164')
uq_sigma: ('5e-09', '2.00599e-09', '2.00599e-09')
uq_t_handoff: 0
noise_sigma: 0.001
-- Act 7 - Early-phase step trace (how UQ is built) --
-> uq_ek_handoff_trace returns the (t, h, y, sigma) samples from the noisy early integration window — the steps the solver actually took before handoff. Use it to audit why uq_sigma came out large or small; it is a diagnostic tape, not a second integration.
trace_n_steps: 0
-- Run complete --
next_journey: 06_limits.pyRun it
cd python
# Guided tour — narrated scenario walkthrough (recommended first run):
python examples/journeys/05_diagnostics.py
# Production one-liner — same API call you ship:
python examples/journeys/05_diagnostics.pyWhat comes next
Journey 06 covers RK45 comparison, linear routing, and honest refusals.
Navigation
← Journey 04 — Configuration and SolvScout hand-off · Journey 06 — Limits →