Skip to content

feat: add multiscale OME-Zarr output#96

Open
LDeakin wants to merge 23 commits into
mainfrom
ld/feat/multiscale_zarr
Open

feat: add multiscale OME-Zarr output#96
LDeakin wants to merge 23 commits into
mainfrom
ld/feat/multiscale_zarr

Conversation

@LDeakin

@LDeakin LDeakin commented Jun 23, 2026

Copy link
Copy Markdown
Member

This is quick multiscale output, no rechunking. Each input chunk generates all downsampled chunks. Subchunks can be a bit suboptimal due to zarr-developers/zarr-specs#370

CLI

Input: tomoHiRes_nc
  shape:      (21624, 2914, 2914)
  dtype:      uint16
  size:       342.0 GiB
  chunks:     (32, 2914, 2914)  —  518.3 MiB each
  num chunks: 676
Resolved OME-Zarr level 0 layout: chunks=(32, 2944, 2944), subchunks=(32, 32, 32), rechunk_before_store=False
Created OME-Zarr array: path=tomoHiRes_norechunk2_multiscale2.zarr/0, shape=(21624, 2914, 2914), dtype=uint16, chunks=(32, 32, 32), shards=(32, 2944, 2944), dimension_names=('z', 'y', 'x')
Created OME-Zarr array: path=tomoHiRes_norechunk2_multiscale2.zarr/1, shape=(10812, 1457, 1457), dtype=uint16, chunks=(16, 46, 46), shards=(16, 1472, 1472), dimension_names=('z', 'y', 'x')
Created OME-Zarr array: path=tomoHiRes_norechunk2_multiscale2.zarr/2, shape=(5406, 729, 729), dtype=uint16, chunks=(8, 46, 46), shards=(8, 736, 736), dimension_names=('z', 'y', 'x')
Created OME-Zarr array: path=tomoHiRes_norechunk2_multiscale2.zarr/3, shape=(2703, 365, 365), dtype=uint16, chunks=(4, 73, 73), shards=(4, 365, 365), dimension_names=('z', 'y', 'x')
Created OME-Zarr array: path=tomoHiRes_norechunk2_multiscale2.zarr/4, shape=(1352, 183, 183), dtype=uint16, chunks=(2, 61, 61), shards=(2, 183, 183), dimension_names=('z', 'y', 'x')
Created OME-Zarr array: path=tomoHiRes_norechunk2_multiscale2.zarr/5, shape=(676, 92, 92), dtype=uint16, chunks=(1, 92, 92), shards=None, dimension_names=('z', 'y', 'x')

Base automatically changed from ld/feat/input_aligned_chunks to main June 23, 2026 04:33
@LDeakin
LDeakin force-pushed the ld/feat/multiscale_zarr branch from 6f7a653 to 30f80f5 Compare June 23, 2026 04:34
@LDeakin
LDeakin requested a review from Copilot June 23, 2026 04:42
@LDeakin
LDeakin marked this pull request as ready for review June 23, 2026 04:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds multiscale OME-Zarr pyramid writing to the Zarr writer (without rechunking), with new CLI control to disable pyramid output and an expanded test suite covering multiscale behavior, metadata, and updated layout selection expectations.

Changes:

  • Implement multiscale OME-Zarr pyramid output (multiple levels + OME multiscales metadata) with selectable downsampling methods.
  • Update chunk/subchunk auto-selection/scoring for input-aligned layouts and add additional coverage cases.
  • Add --no-multiscale CLI option to disable pyramid generation for Zarr outputs.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/anu_ctlab_io/zarr/_writer.py Implements multiscale pyramid creation/writing, downsampling utilities, and updated layout/encoding handling for OME-Zarr writes.
tests/test_zarr_write.py Adds extensive multiscale tests (level stopping rules, metadata transforms, odd chunk behavior, downsample methods) and updates expectations for revised layout scoring.
cli/src/anu_ctlab_io_cli/_cli.py Adds --no-multiscale to disable multiscale pyramid output when writing Zarr.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/anu_ctlab_io/zarr/_writer.py Outdated
Comment on lines +901 to +905
counts = np.zeros_like(values, dtype=np.uint8)
for index in range(values.shape[0]):
counts[index] = np.sum((values == sorted_values[index]) & valid, axis=0)
counts = np.take_along_axis(counts, order, axis=0)
counts[~sorted_valid] = 0
Comment thread src/anu_ctlab_io/zarr/_writer.py
LDeakin added 12 commits June 23, 2026 17:06
  - Uses block-local downsampling while all non-final chunks divide cleanly by 2.
  - Rechunks only when the current chunk grid would shift global downsample positions.
  - Level 0 storage layout is now independent of multiscale
- Direct task -> zarr writing for /2 downsampling
- Output chunk parallelism on subsequent scales, reading Zarr inputs directly (no dask, direct unaligned zarr pythobn reads)

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.

Comment thread pyproject.toml
Comment thread src/anu_ctlab_io/zarr/_multiscale.py
Comment thread src/anu_ctlab_io/zarr/_multiscale.py Outdated
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.

2 participants