Product documentation — installation, licensing, and integration guides.
SolvSRK
Examples
05 Diagnostics

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 ± band

Act-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).

FieldValueNotes
knob_sourceSolvScout tuned (solvsrk, high)

Act 2 — Did it finish?

survived + failure_mode + t_reached are the go/no-go trio.

FieldValueNotes
survivedTrue
failure_modeok
failure_msg(none)
t_reached40
rc0failure_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.

FieldValueNotes
ek_steps0
ek_n_rhs0
ek_wall_s0
ek_noise_detectedFalse
cvode_steps613
cvode_n_rhs795
cvode_n_jac11
cvode_wall_s0.002688
t_handoff0
confidence0
total_wall_s0.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.

FieldValueNotes
t_shape(615,)
y_shape(3, 615)
n_history615
nfev795
njev11
nsteps613
truncatedFalse
telemetry_csvpython\robertson_telemetry.csv
csv_rows615

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.

FieldValueNotes
license_has_uqTrue

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.

FieldValueNotes
y_final('0.715827', '9.18553e-06', '0.284164')
uq_sigma('5e-09', '2.00599e-09', '2.00599e-09')
uq_t_handoff0
noise_sigma0.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.

FieldValueNotes
trace_n_steps0

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.py

Run 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.py

What comes next

Journey 06 covers RK45 comparison, linear routing, and honest refusals.

Navigation

← Journey 04 — Configuration and SolvScout hand-off · Journey 06 — Limits →