Data models and writers¶
Beamtime data models, catalog, schema, and writers for SQLite and Zarr storage.
- class resonance.api.data.models.SampleMetadata(name: str, formula: str | None = None, serial: str | None = None, tags: list[str] = <factory>, beamline_pos: str | None = None, extra: dict[str, ~typing.Any]=<factory>, id: int | None = None)[source]¶
Bases:
objectIn-memory representation of a sample row from the samples table.
- Parameters:
name (str) – Human-readable sample name, used as the primary display identifier.
formula (str | None) – Chemical formula string, e.g. “C8H8”. None if not recorded.
serial (str | None) – Physical identifier stamped on the sample or its holder, e.g. “S1234”.
tags (list[str]) – Arbitrary string tags for grouping or filtering, e.g. [“polymer”, “reference”].
beamline_pos (str | None) – Stage slot or carousel position where the sample was mounted.
extra (dict[str, Any]) – Arbitrary metadata that does not fit the fixed schema.
id (int | None) – Database primary key assigned on insertion. None before the row is written.
- tags¶
Arbitrary string tags for grouping or filtering, e.g. [“polymer”, “reference”].
- class resonance.api.data.models.BeamtimeInfo(id: int, researcher_name: str, label: str, db_path: str, time_start: float | None = None, time_stop: float | None = None)[source]¶
Bases:
objectRepresents a beamtime entry as stored in the master index database.
Each beamtime corresponds to a single experimental session and owns its own SQLite database file. The master index holds one row per beamtime so that multiple sessions can be cataloged from a single entry point.
- label¶
Human-readable label for the beamtime, typically an ISO date string such as “2026-03-05”.
- Type:
- class resonance.api.data.models.RunSummary(uid: str, plan_name: str, time_start: float, sample_name: str | None = None, time_stop: float | None = None, exit_status: str | None = None)[source]¶
Bases:
objectLightweight summary of a single run, used for catalog listing operations.
This is a denormalized projection built from joining the runs and samples tables. It is intended for display and filtering, not for full data retrieval.
- sample_name¶
Sample name denormalized from the samples join. None if no sample was associated with the run or if the join produced no match.
- Type:
str | None
- class resonance.api.data.writer.RunWriter(db_path: Path, sample: SampleMetadata)[source]¶
Bases:
objectManages a SQLite connection to a beamtime database and writes scan data.
- Parameters:
db_path (Path) – Path to the beamtime SQLite database file. Created on first open if it does not exist.
sample (SampleMetadata) – Sample to associate with runs written through this writer. If
sample.idis None, the sample is upserted onopen.
- _db_path¶
Resolved path to the SQLite file.
- Type:
Path
- _sample¶
Sample metadata, with
idpopulated afteropen.- Type:
- _conn¶
Active database connection, or None when closed.
- Type:
sqlite3.Connection or None
- _zarr_store¶
Open Zarr group for image storage, or None when closed.
- Type:
zarr.Group or None
- __enter__() RunWriter[source]¶
Open the writer and return self.
- Returns:
The opened writer instance.
- Return type:
- __exit__(exc_type: type[BaseException] | None, exc: BaseException | None, tb: object) None[source]¶
Close the run and connection, propagating any exception.
- Parameters:
exc_type (type[BaseException] or None) – Exception type if an exception occurred, otherwise None.
exc (BaseException or None) – Exception instance if an exception occurred, otherwise None.
tb (object) – Traceback object if an exception occurred, otherwise None.
- close() None[source]¶
Commit any remaining work and close the database connection.
- Raises:
RuntimeError – If the writer is not open.
- close_run(*, exit_status: str = 'success') None[source]¶
Finalize the current run and commit all pending events.
- Parameters:
exit_status (str, optional) – Final status string. Expected values are “success”, “aborted”, or “failed”. Defaults to “success”.
- Raises:
RuntimeError – If the writer is not open or no run has been opened.
- open() None[source]¶
Open the database connection and upsert the sample.
Creates the beamtime schema if the database does not yet exist. If
self._sample.idis None, the sample is looked up by name; if a matching row exists its id is loaded, otherwise a new row is inserted. A Zarr store is opened (or created) alongside the.dbfile at{db_path.stem}.zarr/.- Raises:
RuntimeError – If the writer is already open (
self._connis not None).sqlite3.DatabaseError – If the database file is corrupt or unreadable.
- open_run(plan_name: str, *, metadata: dict[str, Any] | None = None) str[source]¶
Insert a new run row and return its UID.
- Parameters:
- Returns:
Hex UUID of the newly created run.
- Return type:
- Raises:
RuntimeError – If the writer is not open.
- open_stream(name: str, data_keys: dict[str, Any]) str[source]¶
Insert a new stream row and return its UID.
- Parameters:
- Returns:
Hex UUID of the newly created stream.
- Return type:
- Raises:
RuntimeError – If the writer is not open or no run has been opened.
- write_event(data: dict[str, float | int | str | bool], timestamps: dict[str, float] | None = None) str[source]¶
Insert an event row and return its UID.
Events are not committed individually; the commit is deferred to
close_runfor performance.- Parameters:
- Returns:
Hex UUID of the newly inserted event.
- Return type:
- Raises:
RuntimeError – If the writer is not open, no run has been opened, or no stream has been opened.
- write_image(event_uid: str, field_name: str, image: np.ndarray) None[source]¶
Append a 2-D image frame to the Zarr store and record a reference in SQLite.
- Parameters:
- Raises:
RuntimeError – If the writer is not open (
self._connis None).RuntimeError – If no run has been opened (
self._run_uidis empty).RuntimeError – If no stream has been opened (
self._stream_uidis empty).
Notes
The Zarr store lives at
{db_path.stem}.zarr/alongside the.dbfile. Frames are appended to the array atruns/{run_uid}/{field_name}inside the store. Each call grows the array by one frame along axis 0. Theimage_refsrow stores the zarr group path and the zero-based frame index so the frame can be retrieved without scanning the full array.compression_codecis recorded as"blosc"to document the Zarr default; actual compression is controlled by zarr’s compressor setting.
- class resonance.api.data.writer.IndexWriter(index_db_path: Path)[source]¶
Bases:
objectWriter for the master index database aggregating cross-beamtime metadata.
- Parameters:
index_db_path (Path) – Path to the master index SQLite database file.
Notes
This class is a skeleton. All methods raise
NotImplementedErroruntil the master index feature is implemented.- ensure_schema() None[source]¶
Create the index schema if it does not already exist.
- Raises:
NotImplementedError – Always; not yet implemented.
- index_run(uid: str, researcher_id: int, beamtime_id: int, plan_name: str, *, sample_name: str | None = None, time_start: float | None = None, tags: list[str] | None = None) None[source]¶
Insert a run summary row into the master index.
- Parameters:
uid (str) – Hex UUID of the run, matching the per-beamtime
runs.uid.researcher_id (int) – Foreign key into the
researcherstable.beamtime_id (int) – Foreign key into the
beamtimestable.plan_name (str) – Name of the scan plan.
sample_name (str or None, optional) – Sample name denormalized from the per-beamtime database.
time_start (float or None, optional) – Unix timestamp for the start of the run.
tags (list[str] or None, optional) – Arbitrary string tags for filtering.
- Raises:
NotImplementedError – Always; not yet implemented.
- register_beamtime(researcher_id: int, label: str, db_path: str, *, time_start: float | None = None) int[source]¶
Insert or retrieve a beamtime row and return its id.
- Parameters:
- Returns:
Primary key of the beamtime row.
- Return type:
- Raises:
NotImplementedError – Always; not yet implemented.
- register_researcher(name: str, root_path: str, *, email: str | None = None, orcid: str | None = None, affiliation: str | None = None) int[source]¶
Insert or retrieve a researcher row and return its id.
- Parameters:
- Returns:
Primary key of the researcher row.
- Return type:
- Raises:
NotImplementedError – Always; not yet implemented.
- class resonance.api.data.catalog.Catalog(db_path: Path)[source]¶
Bases:
objectRead-only catalog over a per-beamtime SQLite database.
The catalog reads from a
.dbSQLite file and an adjacent.zarrdirectory store that holds detector image arrays.- Parameters:
db_path (Path) – Path to the beamtime SQLite database file. The Zarr store is expected at
db_path.with_suffix(".zarr").
- _conn¶
Read-only connection to the database.
- Type:
- _db_path¶
Resolved path passed at construction time.
- Type:
Path
- _zarr_path¶
Path to the adjacent Zarr store directory.
- Type:
Path
- by_sample(name: str) list[RunSummary][source]¶
Return all runs associated with a sample by name.
- Parameters:
name (str) – Exact sample name as stored in the
samplestable.- Returns:
Run summaries for the given sample, ordered newest-first.
- Return type:
- class resonance.api.data.catalog.Run(conn: Connection, row: dict[str, Any], zarr_path: Path)[source]¶
Bases:
objectFull accessor for a single run, including scalar event data and sample metadata.
- Parameters:
conn (sqlite3.Connection) – Active connection to the beamtime database.
row (dict[str, Any]) – Deserialized row from the
runstable.zarr_path (Path) – Path to the adjacent Zarr store directory.
- _conn¶
Shared database connection from the parent Catalog.
- Type:
- _zarr_path¶
Path to the Zarr store for detector images.
- Type:
Path
- images(field: str = 'detector_image') LazyImageSequence[source]¶
Return a lazy accessor for detector images in this run.
Images are not loaded until explicitly indexed. Each frame is stored as a slice of a Zarr array on the filesystem.
- Parameters:
field (str, optional) – The image field name to load (default: “detector_image”).
- Returns:
Lazy accessor with length equal to the number of images in this run.
- Return type:
Notes
Returns an empty LazyImageSequence if no images are stored for the given field or if the Zarr store does not exist.
- property sample: SampleMetadata | None¶
Return the associated sample metadata, or None if not set.
- Returns:
Populated from the
samplestable row, withtagsandextradeserialized from JSON. Returns None ifsample_idis null or the referenced row does not exist.- Return type:
SampleMetadata or None
- table(stream: str = 'primary') DataFrame[source]¶
Load scalar event data from a named stream as a DataFrame.
- Parameters:
stream (str, optional) – Name of the stream to load. Defaults to “primary”.
- Returns:
Columns are
seq_num,time, followed by all scalar fields present in the eventdataJSON. Returns an empty DataFrame with columns["seq_num", "time"]if the stream has no events.- Return type:
pd.DataFrame
- class resonance.api.data.catalog.LazyImageSequence(conn: Connection, refs: list[dict[str, Any]], zarr_store_path: Path)[source]¶
Bases:
objectLazy accessor for detector images referenced via Zarr.
Images are not loaded until explicitly indexed. Each image is stored as a frame in a Zarr array on the filesystem; this class holds the reference metadata and defers loading.
- Parameters:
conn (sqlite3.Connection) – Active connection to the beamtime database.
refs (list[dict[str, Any]]) – List of deserialized rows from the
image_refstable.zarr_store_path (Path) – Path to the Zarr store directory containing detector arrays.
- _conn¶
Shared database connection from the parent Catalog.
- Type:
- _zarr_store_path¶
Path to the Zarr store directory.
- Type:
Path
- __getitem__(idx: int | slice) ndarray[source]¶
Load one or more detector images from the Zarr store.
- Parameters:
- Returns:
A single (shape_x, shape_y) array for int index, or a stacked (n, shape_x, shape_y) array for slice index.
- Return type:
np.ndarray
- Raises:
IndexError – If idx is out of range.
TypeError – If idx is not int or slice.
Schema helpers:
- resonance.api.data.schema.create_beamtime_schema(conn: sqlite3.Connection) None[source]¶
Create all per-beamtime tables, indexes, and pragmas.
- Parameters:
conn (sqlite3.Connection) – Open connection to the beamtime SQLite database file.
- Raises:
sqlite3.DatabaseError – If DDL execution fails due to a malformed database or I/O error.
Notes
Each beamtime session is stored in its own SQLite .db file alongside a Zarr store directory. The image_refs table holds references into the Zarr array (group path and frame index) rather than binary BLOBs, keeping the SQLite file small and enabling memory-mapped array access. Foreign keys are enforced on every connection via
PRAGMA foreign_keys = ON, which must be re-applied per connection because SQLite resets it on open.
- resonance.api.data.schema.create_index_schema(conn: sqlite3.Connection) None[source]¶
Create master index tables, indexes, and pragmas.
- Parameters:
conn (sqlite3.Connection) – Open connection to the master index SQLite database file.
- Raises:
sqlite3.DatabaseError – If DDL execution fails due to a malformed database or I/O error.
Notes
The master index database aggregates metadata from all per-beamtime databases into three tables:
researchers,beamtimes, andruns_index. This allows cross-beamtime queries without opening individual session databases. Theruns_indextable mirrors key fields from the per-beamtimerunstable, identified by the sameuid. Foreign keys are enforced viaPRAGMA foreign_keys = ON, which must be re-applied per connection.
- resonance.api.data.schema.migrate_beamtime_schema(conn: sqlite3.Connection, target_version: int = 2) None[source]¶
Apply pending schema migrations up to target_version.
- Parameters:
conn (sqlite3.Connection) – Open connection to the beamtime SQLite database file.
target_version (int, optional) – Schema version to migrate to. Defaults to BEAMTIME_SCHEMA_VERSION.
- Raises:
RuntimeError – If target_version is less than the current schema version (downgrade not supported).
- resonance.api.data.schema.migrate_index_schema(conn: sqlite3.Connection, target_version: int = 1) None[source]¶
Apply pending index schema migrations up to target_version.
- Parameters:
conn (sqlite3.Connection) – Open connection to the master index SQLite database file.
target_version (int, optional) – Schema version to migrate to. Defaults to
INDEX_SCHEMA_VERSION.
- Raises:
RuntimeError – If the database’s current
user_versionis greater thantarget_version, indicating a downgrade attempt or a database written by a newer version of this software.NotImplementedError – If migrations are required (current_version < target_version) but no migration path has been implemented yet.
Notes
Migration steps are applied sequentially from current_version + 1 up to target_version. Version 1 is the initial schema; future versions will add individual
ALTER TABLEor data-transform statements here.