Parameter Sweeps#
notata is well-suited for automated parameter sweeps, such as varying hyperparameters, initial conditions, or simulation settings.
Each run is isolated in its own directory, with its own log, outputs, and metadata.
Basic Sweep Loop#
Here’s how to structure a sweep over multiple parameter combinations:
from notata import Logbook
import numpy as np
import itertools
omegas = [1.0, 2.0, 3.0]
dts = [1e-2, 1e-3]
for omega, dt in itertools.product(omegas, dts):
run_id = f"omega{omega}_dt{dt}"
params = {"omega": omega, "dt": dt, "steps": 1000}
with Logbook(run_id, params=params) as log:
x, v = 1.0, 0.0
xs = np.empty(params["steps"])
for n in range(params["steps"]):
a = -omega**2 * x
x += v*dt + 0.5*a*dt*dt
a_new = -omega**2 * x
v += 0.5*(a + a_new)*dt
xs[n] = x
log.array("x", xs)
log.json("final_state", {"x": float(x), "v": float(v)})
Organizing Sweep Outputs#
Each run creates a directory like:
outputs/
log_omega1.0_dt0.01/
log_omega1.0_dt0.001/
log_omega2.0_dt0.01/
...
You can then grep, tabulate, or plot sweep results directly from the filesystem.
Saving Results in Structured Form#
To compare sweep results later, save a final summary metric for each run:
energy = 0.5 * (v**2 + (omega * x)**2)
log.json("final_metrics", {"E": float(energy)})
Then collect across runs:
jq '.E' outputs/log_*/artifacts/final_metrics.json
Tips for Large Sweeps#
Use compact, informative `run_id`s (avoid slashes or long floats)
Set overwrite=True if re-running a sweep with the same IDs
Track failures with status in metadata.json or via log.status
Example: Resuming only failed runs#
import json
from pathlib import Path
for path in Path("outputs").glob("log_*"):
meta = path / "metadata.json"
if not meta.exists():
continue
status = json.loads(meta.read_text()).get("status")
if status != "complete":
print(f"Will re-run: {path.name}")