Skip to content

Port the out-of-core zarr map-reduce engine - #32

Merged
eagmon merged 1 commit into
mainfrom
feat/zarr-mapreduce
Aug 21, 2026
Merged

Port the out-of-core zarr map-reduce engine#32
eagmon merged 1 commit into
mainfrom
feat/zarr-mapreduce

Conversation

@eagmon

@eagmon eagmon commented Aug 21, 2026

Copy link
Copy Markdown
Member

Brings the reusable map-reduce engine from vEcoli PR #414 commit 5ec59d33 into viva-emitters, so any downstream that emits the viva zarr layout can run out-of-core analyses over it. The concrete moving-average pipeline (Altair/CLI) stays downstream in the consuming app (v2ecoli, PR-D).

New modules (viva_emitters/xarray_emitter/)

  • mapreduce.py — generic map-reduce algebra (pool_dict/async_dict contexts, Reducer ABC + ReducerList/Mapping/Distribute, MinMax/Chain/Unique). Pure stdlib + numpy + bottleneck. Verbatim.
  • zarr_mapreduce.py — the ZarrMapReduce ABC driver that walks the emitter's workflow → substore → partition → variable hierarchy, combining multiprocessing across substores with zarr's async API within each. Imports rewritten viva-relative.
  • zarr_utils.pyread-side helpers only (get_async_array/get_async_group, parse_codecs, get_ndarray, get_rectilinear_ndarray). The consolidation functions are not duplicated — viva keeps those in zarr_writer.py. All zarr-internal symbols verified present on the locked zarr 3.1.6.

storage.py additions

EXPERIMENT/VARIANT/LINEAGE_PREFIX constants; module functions var_name()/coo_path() + VariablePath; WorkflowConfig / WorkflowPaths / Substore; and XarrayStoragePartition.{from_substore, independent_path_glob, get_variant, get_lineage, is_time_coo_name, __hash__}. Reconciled against viva's diverged partition (which already had independent_path/cast).

Key adaptation — no app dependency

WorkflowConfig.build/.load take an injectable variant_parser (default None) instead of from runscripts.create_variants import parse_variants. The library must not depend on app runscripts; v2ecoli injects its real parser. fsspec is imported lazily (remote stores only).

Verification

tests/test_zarr_mapreduce_engine.py builds a real viva-emitted workflow store (1 variant × 2 lineages × 2 generations), then asserts WorkflowPaths.locate discovers both substores, XarrayStoragePartition.from_substore round-trips, and zarr_utils.get_async_group reads the generation=2 array back. Full suite: 110 passed, 4 skipped. (The full ZarrMapReduce driver — ~12 abstract hooks — is exercised by the downstream moving-average pipeline.)

Part of the PR #414 reconciliation (follows #29, #30, #31).

🤖 Generated with Claude Code

Brings the reusable map-reduce ENGINE from vEcoli PR #414 commit 5ec59d33 into
viva-emitters, so any downstream that emits the viva zarr layout can run
out-of-core analyses over it. The concrete moving-average pipeline (Altair/CLI)
stays downstream in the consuming app (v2ecoli).

New modules (viva_emitters/xarray_emitter/):
- mapreduce.py    — generic map-reduce algebra (pool_dict/async_dict contexts,
                    Reducer ABC + ReducerList/Mapping/Distribute, MinMax/Chain/
                    Unique). Pure stdlib + numpy + bottleneck. Copied verbatim.
- zarr_mapreduce.py — the ZarrMapReduce ABC driver that walks the emitter's
                    workflow -> substore -> partition -> variable hierarchy,
                    combining multiprocessing across substores with zarr's async
                    API within each. Imports rewritten to viva-relative.
- zarr_utils.py   — READ-side helpers only (get_async_array/get_async_group,
                    parse_codecs, get_ndarray, get_rectilinear_ndarray). The
                    consolidation functions are NOT duplicated here — viva keeps
                    those in zarr_writer.py. All zarr-internal symbols verified
                    present on the locked zarr 3.1.6.

storage.py additions: EXPERIMENT/VARIANT/LINEAGE_PREFIX constants; module
functions var_name()/coo_path() + VariablePath; WorkflowConfig / WorkflowPaths /
Substore; and XarrayStoragePartition.{from_substore, independent_path_glob,
get_variant, get_lineage, is_time_coo_name, __hash__}. Reconciled against viva's
diverged partition (which already had independent_path/cast).

Key adaptation: WorkflowConfig.build/.load take an injectable
`variant_parser` (default None) instead of importing
runscripts.create_variants — the library must not depend on app runscripts.
v2ecoli injects its real parser. fsspec is imported lazily (remote stores only).

Deps: bottleneck (+ fsspec) added to the [xarray] extra.

Verification (tests/test_zarr_mapreduce_engine.py): a real viva-emitted
workflow store (1 variant x 2 lineages x 2 generations) is discovered by
WorkflowPaths.locate, XarrayStoragePartition.from_substore round-trips, and
zarr_utils.get_async_group reads the generation=2 array back. Full suite: 110
passed, 4 skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@eagmon
eagmon merged commit e791021 into main Aug 21, 2026
1 check passed
@eagmon
eagmon deleted the feat/zarr-mapreduce branch August 21, 2026 07:07
eagmon added a commit that referenced this pull request Aug 21, 2026
#32 added bottleneck/fsspec to the [xarray] extra but did not re-lock, and #31
re-locked before those deps existed, so main's uv.lock was missing them
(`uv lock --check` failed). Re-lock to restore consistency.

Verified: `uv lock --check` passes; full suite 121 passed, 4 skipped.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant