https://github.com/alonfnt/notata
A lightweight Python library for saving simulation or experiment results in a standardized, reproducible format. Designed for scientists and researchers running simulations.
https://github.com/alonfnt/notata
logging python scientific-computing
Last synced: 11 months ago
JSON representation
A lightweight Python library for saving simulation or experiment results in a standardized, reproducible format. Designed for scientists and researchers running simulations.
- Host: GitHub
- URL: https://github.com/alonfnt/notata
- Owner: alonfnt
- Created: 2025-07-19T08:07:18.000Z (12 months ago)
- Default Branch: main
- Last Pushed: 2025-07-19T10:32:18.000Z (12 months ago)
- Last Synced: 2025-07-19T13:15:25.119Z (12 months ago)
- Topics: logging, python, scientific-computing
- Language: Python
- Homepage:
- Size: 12.7 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# notata
[](https://github.com/alonfnt/notata/actions/workflows/pytest.yml)
[](https://pypi.org/project/notata/)
`notata` is a minimal library for **structured filesystem logging of scientific runs**.
One `Logbook` -> one run directory: parameters, arrays, plots, artifacts, metadata, timestamped log. Explicit. Reproducible. Grep‑friendly.
## Installation
```bash
pip install notata
```
## Quick Start
### Context Manager
```python
from notata import Logbook
import numpy as np
with Logbook("oscillator_dt1e-3", params={"omega": 2.0, "dt": 1e-3, "steps": 10_000}) as log:
omega = 2.0
dt = 1e-3
steps = 10_000
x, v = 1.0, 0.0
xs = np.empty(steps)
vs = np.empty(steps)
E = np.empty(steps)
for n in range(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], vs[n] = x, v
E[n] = 0.5*(v**2 + (omega*x)**2)
if (n+1) % 2000 == 0:
log.info(f"step={n+1} x={x:.4f} v={v:.4f} E={E[n]:.6f}")
log.save_arrays("trajectory", x=xs, v=vs)
log.save_numpy("energy", E)
log.save_json("final_state", {"x": float(x), "v": float(v), "E": float(E[-1])})
```
### Manual Lifecycle
```python
from notata import Logbook
import numpy as np
log = Logbook("heat_manual", params={"Nx": 64, "Ny": 64, "kappa": 0.01, "steps": 500})
Nx = Ny = 64
kappa = 0.01
dx = 1.0
dt = 0.2 * dx*dx / kappa
X, Y = np.meshgrid(np.linspace(-1,1,Nx), np.linspace(-1,1,Ny), indexing="ij")
T = np.exp(-6*(X**2 + Y**2))
snap_every = 100
for step in range(500):
lap = (np.roll(T,1,0)+np.roll(T,-1,0)+np.roll(T,1,1)+np.roll(T,-1,1)-4*T)
T += kappa * dt * lap
if (step+1) % snap_every == 0:
log.save_numpy(f"T_step{step+1}", T, category="data/intermediate")
log.info(f"step={step+1} maxT={T.max():.4f}")
log.save_json("final_stats", {"max": float(T.max()), "mean": float(T.mean())})
log.mark_complete()
```
### Failure capture
```python
from notata import Logbook
import numpy as np
log = Logbook("unstable_run", params={"dt": 0.5})
try:
dt = 0.5 # too large for stability
x, v, w = 1.0, 0.0, 5.0
for step in range(1000):
a = -w**2 * x
v += a * dt
x += v * dt
if not np.isfinite(x):
raise RuntimeError("Diverged")
log.mark_complete()
except Exception as e:
log.mark_failed(str(e))
```
## Output format
Data is stored as following:
```bash
log_/
log.txt
metadata.json
params.yaml
data/
plots/
artifacts/
```
where the files follow:
| Path / Pattern | Purpose / Format |
|------------------------------|--------------------------------------------------------------------------------------------------------|
| `log.txt` | Plain text log; lines: `[YYYY-MM-DDTHH:MM:SS] LEVEL message` |
| `metadata.json` | Run metadata: `status`, `start_time`, optional `end_time`, `runtime_sec`, optional `failure_reason`, `run_id` |
| `params.yaml` / `params.json`| Parameter snapshot (latest saved form) |
| `data/*.npz` | Array archives; single array → key `data`; multi-array save → keys = argument names |
| `data/**/` | Additional numeric outputs (via `category="data/..."`) |
| `plots/*.png|pdf|svg` | Saved figures (`save_plot`) |
| `artifacts/*.txt` | Text artifacts (`save_text`) |
| `artifacts/*.json` | JSON artifacts (`save_json`) |
| `artifacts/*.pkl` | Pickled objects (`save_pickle`) |
| `artifacts/*` (other) | Raw bytes (`save_bytes`) |
| `artifacts/**/` | Nested artifact categories (e.g. `category="artifacts/logs"`) |
## Citation
You don't have to, but if you use `notata` in your research and need to reference it, please cite it as follows:
```
@software{notata_2025,
author = {Albert Alonso},
title = {notata: Structured Filesystem Logging for Scientific Runs},
url = {https://github.com/alonfnt/notata},
version = {0.1.0},
year = {2025}
}
```
## License
MIT License