A SQLModel/SQLAlchemy persistence layer for computational chemistry workflow data, built on top of automol. It stores molecular geometries, chemical identities, trajectories, stationary points, calculation results (energies, gradients, Hessians), and the calculations/reaction steps that connect them, as a graph of related rows in a SQLite database.
Row models extend automol's core data models directly rather than wrapping them — GeometryRow extends automol.Geometry, IdentityRow extends automol.Identity — so any data already expressed in automol types can be persisted with no conversion step.
Install as a Pixi dependency:
[dependencies]
autostorage = ">=0.0.10"Or with uv/pip from PyPI:
uv add autostorageRequires Python ≥3.12.
import numpy as np
from autostorage import (
CalcType,
CalculationGeometryLink,
CalculationRow,
Database,
EnergyRow,
GeometryRow,
ModelRow,
Role,
)
# Open (or create) a SQLite database; ":memory:" also works for scratch use.
db = Database("workflow.db")
# `find_or_create` dedups on (program, program_version, method, basis).
model = ModelRow.find_or_create(db, program="orca", method="b3lyp", basis="def2-svp")
calc = CalculationRow(model=model, calc_type=CalcType.ENERGY)
geo = GeometryRow(
symbols=["H", "O", "H"],
coordinates=np.array([[0, 0, 0.8], [0, 0, 0], [0.8, 0, 0]]),
charge=0,
spin=0,
)
link = CalculationGeometryLink.create(calc, geo, role=Role.INPUT)
db.add_all([model, calc, geo, link])
db.commit()
# Attach a result to the geometry/calculation pair.
energy = EnergyRow(geometry=geo, calculation=calc, value=-76.02)
db.add(energy)
db.commit()
# Look the result back up by geometry, model, and input provenance.
found = EnergyRow.query(db, geo=geo, model=model)
assert found is not None
print(found.value)
db.close()Database also supports the with statement, which rolls back on an unhandled exception and closes the connection on exit:
with Database("workflow.db") as db:
...Two databases can be combined with Database.merge_from(), which copies every row from one into the other, remapping ids/foreign keys and deduplicating content-unique rows (models, non-auto-managed identities) against the target's existing data:
with Database("combined.db") as target, Database("other.db") as other:
report = target.merge_from(other)
print(report.copied, report.reused) # per-table row countsFor a full worked example covering geometries, trajectories, results, and identities, see examples/stationary_point.py. Reaction networks (StageRow/StepRow) can be exported as MESS input via autostorage.utils.export_mess_input(), or rendered as a potential energy surface diagram via autostorage.utils.plot_pes().
See CLAUDE.md for the full module map and architecture notes.
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the MIT License.