Skip to content

fix(spatial): accept [time, 1, lat, lon] singleton-depth arrays in polygon reader - #19

Merged
npillar merged 2 commits into
mainfrom
fix/polygon-singleton-depth
Jul 14, 2026
Merged

npillar merged 2 commits into
mainfrom
fix/polygon-singleton-depth

Conversation

@npillar

@npillar npillar commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Accept arrays with degenerate size-1 "middle" dims between the time axis and the
trailing spatial dims in the polygon reader — e.g. [time, 1, lat, lon].

  • assertArrayRank now accepts rank = expected + k when the k middle dims
    are all size 1, and returns k. A non-singleton middle dim (a genuine
    multi-level axis, e.g. a depth profile) still throws SliceError, now with a
    message stating the size-1 rule.
  • readPolygon selects index 0 for each singleton middle dim in the per-step
    read, collapsing the dim. The block stays C-order over [rows, cols], so the
    mask gather (values[localR * rowStride + localC]) is untouched.
  • Mirrors the point-read path's existing rank-4 singleton handling
    (i4sea-aurora-ui#768). npoints (rank 2) and plain rank-3 behavior unchanged.

Motivation

Closes #18. Hydrodynamic current fields (current_vel, current_dir) from
hidro/Delft3D datasets carry a degenerate depth dim of size 1 — shape
[time, 1, lat, lon]. The polygon reader asserted an exact rank match
(2d/1d ⇒ rank 3), so these fields could not stream through it at all and were
skipped-with-warn consumer-side. That meant WATER_FLOW area meteograms served
water_level but lost the current speed + direction pair
— a product-visible
gap, since direction-over-speed is a headline of that feature (i4sea-aurora-ui
spec 058 / #1049).

Index-0 selection of a size-1 dim is deterministic (one element), so no new API
surface is needed. An explicit per-dim selection (for non-singleton middle dims,
e.g. picking a depth level) would be a separate, bigger feature and is out of
scope here.

Test Plan

  • Unit tests added/updated — new singleton middle dims suite:
    [time, 1, lat, lon] streams identically to the equivalent rank-3 array
    (cells/bbox/stride/values); 2d layout with a leading singleton depth dim;
    two singleton middle dims ([time, 1, 1, lat, lon]); a non-singleton middle
    dim ([time, 3, lat, lon]) still throws with the size-1 rule in the message.
  • Integration tests added/updated — n/a (reads through existing stores)
  • All existing tests pass (npm test) — 391 passed; the one failing
    s3-store test is pre-existing and unrelated (missing optional peer
    @smithy/node-http-handler in this environment), confirmed via git stash.

…lygon reader

Hydrodynamic current fields (current_vel, current_dir) from hidro/Delft3D
datasets carry a degenerate depth dim of size 1 — shape [time, 1, lat, lon].
readPolygon / resolvePolygonCells required the array rank to match the layout
exactly (2d/1d => rank 3), so these fields were rejected outright and dropped
from area-aggregated reads.

assertArrayRank now accepts rank = expected + k when the k middle dims (between
the leading time axis and the trailing spatial dims) are all size 1, returning
k; readPolygon selects index 0 for each, collapsing the dim so the block stays
C-order [rows, cols] and the mask gather is untouched. A non-singleton middle
dim still throws SliceError, now stating the size-1 rule. npoints (rank 2) and
plain rank-3 behavior are unchanged.

Closes #18
@npillar npillar self-assigned this Jul 14, 2026
@npillar
npillar requested review from brandao-andre and Copilot July 14, 2026 16:37

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

This PR updates the polygon reader to accept Zarr arrays that include one or more degenerate (size-1) middle dimensions between the leading time axis and trailing spatial axes (e.g. hydrodynamic fields shaped [time, 1, lat, lon]), collapsing those singleton dims deterministically by selecting index 0.

Changes:

  • Extend assertArrayRank to allow rank = expected + k when the k “middle” dims are all size 1, and to throw a clearer SliceError when any middle dim is non-singleton.
  • Update readPolygon to inject index-0 selections for each singleton middle dim so per-step reads stream identically to the equivalent rank-3 arrays.
  • Add unit tests covering [time, 1, lat, lon], [time, 1, 1, lat, lon], 2d layouts with singleton depth, and rejection of non-singleton middle dims; document the fix in the changelog.

Reviewed changes

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

File Description
src/spatial/polygon-reader.ts Allows and collapses singleton middle dims during per-timestep polygon reads; improves rank-validation error messaging.
tests/unit/polygon-reader.test.ts Adds coverage for singleton-middle-dim acceptance and ensures non-singleton middle dims still throw with the new rule.
CHANGELOG.md Documents the polygon-reader fix for singleton-depth arrays and references issue #18.

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

@npillar
npillar merged commit feb536c into main Jul 14, 2026
2 checks passed
@npillar
npillar deleted the fix/polygon-singleton-depth branch July 14, 2026 16:50
npillar added a commit that referenced this pull request Jul 14, 2026
Patch release with the polygon reader singleton-depth fix from PR #19:
accept [time, 1, lat, lon] arrays (degenerate size-1 middle dims) so
hydrodynamic current fields (current_vel, current_dir) stream through
readPolygon. Closes #18.
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.

readPolygon rejects rank-4 singleton-depth arrays ([time, 1, lat, lon]) — current fields excluded from area reads

3 participants