An open API service indexing awesome lists of open source software.

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.

Awesome Lists containing this project

README

          

# notata

[![tests](https://github.com/alonfnt/notata/actions/workflows/pytest.yml/badge.svg)](https://github.com/alonfnt/notata/actions/workflows/pytest.yml)
[![PyPI](https://img.shields.io/pypi/v/notata.svg)](https://pypi.org/project/notata/)


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