Experiment Management#
The Experiment object in notata is designed to organize and track multiple related runs using Logbook. It simplifies the process of sweeping parameters, aggregating metrics, and building an index of all results.
Quickstart#
from notata import Experiment
exp = Experiment("oscillator_sweep")
for omega in [1.0, 2.0]:
for dt in [1e-3, 2e-3]:
log = exp.add(omega=omega, dt=dt, steps=10_000, skip_existing=True)
if log is None:
continue # skip if this run already exists
with log:
# Your simulation code here
...
log.json("metrics", {"final_energy": 0.993})
# Exiting the context manager automatically marks the run as complete.
Manual Logging (without context manager)#
You can also explicitly call mark_complete() after your run logic:
log = exp.add(omega=3.0, dt=1e-3, steps=5000)
try:
# run your simulation
...
log.json("metrics", {"final_energy": 0.998})
log.mark_complete() # explicitly mark success
except Exception as e:
log.mark_failed(str(e))
What it does#
The Experiment handles:
Constructing unique log directories per parameter set.
Attaching a callback so that calling
log.mark_complete()orlog.mark_failed()auto-updates anindex.csv.Persisting parameters and user-defined metrics for each run.
Directory Layout#
outputs/oscillator_sweep/
index.csv
runs/
log_oscillator_sweep_dt_0.001_omega_1.0/
log_oscillator_sweep_dt_0.002_omega_1.0/
log_oscillator_sweep_dt_0.001_omega_2.0/
log_oscillator_sweep_dt_0.002_omega_2.0/
Each run gets its own Logbook with full logging, metadata, and artifacts.
Inspecting Results#
You can convert the index to a pandas dataframe and filter completed runs:
df = exp.to_dataframe()
complete = df[df["status"] == "complete"]
print(complete[["omega", "dt", "final_energy"]])
Example index after running one log:
run_id |
omega |
dt |
steps |
status |
final_energy |
|---|---|---|---|---|---|
oscillator_sweep_dt_0.001_omega_1.0 |
1.0 |
0.001 |
10000 |
complete |
0.993 |
Convenience#
The key benefit of Experiment is that it removes the need for manual bookkeeping across many runs. Just:
Use
exp.add(...)instead of manually constructing directories.Store metrics in
artifacts/metrics.json.Use
log.mark_complete()orwith log: ....
The index is built incrementally and is ready for downstream analysis or re-running filtered subsets.