neu_morpho.metrics_db

Per-body metrics database (SQLite).

One row per body, progressively enriched: the index scan fills bbox / voxel_count / volume; meshing and skeletonization update their columns. Bbox is in full-resolution voxels; consumers convert to their own scale.

Each block’s contribution and its “done” mark land in one transaction, so a crash cannot double-count a summed metric on resume. The driver is the sole writer.

Classes

MetricsDB

Open the metrics DB. read_only opens it WITHOUT writing to it.

Module Contents

class neu_morpho.metrics_db.MetricsDB(path: str, *, read_only: bool = False, busy_timeout_ms: int = 30000)

Open the metrics DB. read_only opens it WITHOUT writing to it.

A reader must not take a write lock: the default open runs DDL, which locks the DB and can kill a running sweep with database is locked. Read-only tools pass read_only=True, which skips the DDL and opens with mode=ro.

A writer waits rather than fails: busy_timeout turns contention with a concurrent reader into a pause.

apply_compartment_block(block_key: str, counts) → None

Merge one block’s {(body_id, label): voxels} and mark it done, atomically.

apply_counts_block(block_key: str, counts: Mapping[int, int], voxel_volume_nm3: float) → None

Merge one block’s {body_id: voxel_count} and mark it done, atomically.

The bbox-free counterpart of apply_index_block(), for the morphometry sweep, about 10x cheaper per dense block. Rows created here have NULL bbox and skeleton columns: this pass did not measure them.

apply_index_block(block_key: str, partials: Mapping[int, tuple], voxel_volume_nm3: float) → None

Merge one block’s {body_id: (z0,y0,x0,z1,y1,x1,count)} and mark it done, atomically.

bbox merges by min/max; voxel_count and volume accumulate. No-op if the block was already applied. A pre-existing row may have a NULL bbox (another stage created it), and SQLite’s min(NULL, 5) is NULL, hence the explicit NULL check.

apply_skel_batch(rows) → None

Apply one batch of (body_id, status, detail, columns) atomically.

bodies_by_size(min_voxels: int = 0, limit: int | None = None) → list[int]
close() → None
commit() → None
compartment_counts() → dict[int, int]

Total voxels per semantic label, across bodies.

crop_at_scale(body_id: int, factor_zyx: Sequence[int], *, margin_vox: int = 0, clip_shape: Sequence[int] | None = None) → tuple | None

A body’s bbox at a read scale, as (z0,y0,x0,z1,y1,x1) voxels (+ margin).

factor_zyx = full-res voxels per read-scale voxel.

done_blocks() → set[str]
done_compartment_blocks() → set[str]
done_skel_bodies(*, include_failed: bool = False) → set[int]

Bodies not worth attempting again.

Status is filtered, not tested for presence, so a recorded failed is retried. absent is terminal: a body with no published skeleton will not grow one.

done_sweep_blocks() → set[str]
get_bbox(body_id: int) → tuple | None
read_stage_meta() → dict[str, dict]
record_stage_meta(stage: str, *, total: int, block_shape=None, level: int | None = None, voxel_size=None, n_keep: int | None = None) → None

Record a stage’s task total BEFORE dispatch. See the table comment.

reset_compartments() → set[str]
reset_index() → None
reset_skel() → set[int]
reset_sweep() → set[str]
skel_counts() → dict[str, int]
stage_counts() → dict[str, int]

Blocks completed per block-mapped stage.

to_csv(path: str) → None
update_bodies(rows: Iterable[tuple[int, Mapping]]) → int

Upsert many bodies in one transaction with one commit.

update_body commits per call; in a pipeline that is one fsync per body in the driver, the sole writer, while workers sit idle.

update_body(body_id: int, **cols) → None

Set enrichment columns for a body, inserting the row if it is new.

The values go in the INSERT as well as the DO UPDATE, so a body the index scan never saw is inserted with them.

write_allowlist(path: str, min_voxels: int = 0, limit: int | None = None) → int
BLOCK_STAGES
con
read_only = False