Saving and loading#
croak.save persists retrievals to HDF5 and session options to TOML.
Results → HDF5#
save_result() writes a retrieval — and, optionally, its
processed form and the measured trace — to a single .h5
file:
pr = croak.process_result(result, measured=td.trace)
croak.save_result(result, "retrieval.h5", processed=pr, measured=td.trace)
Pass force=True to overwrite an existing file. When the trace came from the
synthetic or simulated workflow, pass the truth= keyword (a
TruthPulse) to also store the known ground-truth
temporal intensity (t_truth, It_truth, fwhm_truth_fs) and spectrum
(lam_truth, Ilam_truth). A complex truth additionally stores its temporal and
spectral display phases (phit_truth, phiw_truth) and original complex spectrum
(omega_truth, Ew_truth), so a truth-seeded forward-model diagnostic remains
reproducible. Read it back with croak.save.load_result():
from croak.save import load_result
data = load_result("retrieval.h5")
HDF5 is portable and self-describing, so saved retrievals are easy to share or re-plot later without re-running the solver.
Several results in one file#
A parameter study — a thickness series, a solver comparison, a noise sweep —
produces many retrievals that belong together. Pass group= to write the same
flat schema into a named group instead of the file root. The file is appended to
rather than truncated, so each call adds one run and leaves the others alone:
for i, thickness_um in enumerate(thicknesses):
result, pr = run_one(thickness_um) # your sweep step
croak.save_result(
result, "sweep.h5", processed=pr, measured=td.trace,
group=f"full/z{i:02d}", force=True,
)
A slash-separated name nests, so full/z00 and naive/z00 keep two model
variants of the same point side by side. force=True replaces only the named
group; without it an existing group raises FileExistsError. Root-level datasets
and attributes you write yourself (the swept values, provenance) survive
untouched — useful for recording what the groups mean:
import h5py
with h5py.File("sweep.h5", "a") as f:
f["thickness_um"] = thicknesses
load_result() recurses into subgroups, so the whole sweep reads
back as a nested dict and each entry is still a complete, standard result:
data = load_result("sweep.h5")
fwhm = [data["full"][k]["fwhm_retr_fs"] for k in sorted(data["full"])]
Rebuilding a result without re-running the solver#
result_from_saved() reconstructs a
RetrievalResult straight from a load_result()
dict — the retrieved spectrum, trace, error history and fitted extras — so a saved
retrieval can be reloaded (and re-processed/plotted) without invoking the solver:
from croak.save import load_result, result_from_saved
result = result_from_saved(load_result("retrieval.h5"))
The GUI’s Load previous retrieval uses exactly this: it replays the cheap
load + preprocess steps and then rehydrates the saved result.h5 onto the matching
grid, only re-running the solver if the file is absent or the grid no longer
matches.
Session options → TOML#
The GUI (and your own scripts) can persist the parameters of a session —
preprocessing choices, the chosen algorithm and its options — as a small TOML
file with croak.save.save_options() / croak.save.load_options():
from croak.save import save_options, load_options
save_options({"algorithm": "copra", "maxiters": 300, "lam_min": 730e-9}, "session.toml")
opts = load_options("session.toml")
This stores the recipe, not the data: handy for reproducing a retrieval or
seeding the GUI with known-good settings. A complete session that the
GUI and croak replay can run is a SessionOptions,
written with its to_toml method.
What the options file contains#
A session written by the GUI (or by to_toml())
starts with a small header and then one table per stage:
croak_version = "0.1.0"
options_version = 2
entry = "simulated"
[load] # the measured-trace loader (files, datasets, units, backgrounds)
[simulated] # the numerically simulated loader (scan file, window, band, …)
[preproc]
[retrieve]
[dispersion]
[uncertainty]
entry names the stage-1 loader the trace came from — "experimental",
"simulated" or "synthetic" — and so which of [load] / [simulated] is the
live one; the other is written at its defaults. Without it a simulated session
would be indistinguishable from an experimental one with an empty file path, and
its provenance (which scansave file, which trace window, which thickness slice,
which loaded band) would be lost. croak.session.engine.run_session(), croak replay and
croak script all dispatch on it, so a simulated session replays headlessly like
a measured one. Files written before options_version = 2 have no entry and
read back as experimental.
The "synthetic" entry is recorded but cannot be replayed: the generator’s
settings live only in its GUI controls and are not yet serialised, so reloading
such a session reopens the generator instead of pretending to restore it.
Note
TOML has no null, so options whose value is None (such as an unset
z_thickness_um) are omitted rather than written; reading them back restores
the None default.
What to keep#
The result
.h5is the authoritative output: it contains the retrieved spectrum, the carrier, the trace error and (if you passed them) the processed profiles and measured trace.The options
.tomlrecords how you got there, so the run is reproducible.The input files the options point to (trace, spectrum, backgrounds, calibration curves) and any custom material or mirror data: the options file references them by path and does not embed them.
A saved experimental or simulated session reruns headlessly, or exports as an editable Python script:
croak replay options.toml --seed 0 # writes result.h5
croak script options.toml -o retrieval.py --seed 0
The session file does not record a random seed, so pass --seed when the run
must repeat exactly. croak replay --base-dir DIR reruns the same settings
against another dataset folder. See the workflow example
and croak.scripting for the library interface.