Skip to content

reproject: fix vertical_crs shift on dask, cupy, and 3-D inputs (#2025)#2029

Open
brendancol wants to merge 1 commit into
mainfrom
deep-sweep-accuracy-reproject-2026-05-17
Open

reproject: fix vertical_crs shift on dask, cupy, and 3-D inputs (#2025)#2029
brendancol wants to merge 1 commit into
mainfrom
deep-sweep-accuracy-reproject-2026-05-17

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Summary

  • Fixes reproject(..., src_vertical_crs=..., tgt_vertical_crs=...) on dask, cupy, and 3-D multi-band inputs. Each used to crash before producing output.
  • Routes dask through map_blocks so the output stays lazy and the per-chunk shift is computed from each block's row/column slab.
  • Round-trips cupy arrays via host (the CPU JIT geoid lookup cannot accept cupy buffers) and returns a cupy result.
  • Loops over band slices for 3-D (y, x, band) results so the same N(y, x) correction applies to every band.
  • Recorded on the deep-sweep accuracy state CSV (issue reproject vertical_crs path crashes on dask, cupy, and 3D multi-band inputs #2025).

Test plan

  • python -m pytest xrspatial/tests/test_reproject.py — 245 passed locally.
  • New TestVerticalShift::test_dask_backend_matches_numpy confirms dask path matches numpy bit-for-bit and keeps the result lazy.
  • New TestVerticalShift::test_multiband_3d_applies_shift_per_band confirms each band sees the same geoid undulation correction and band 0 equals the 2-D reference.
  • New TestVerticalShift::test_cupy_backend_matches_numpy confirms the vertical-shift increment matches numpy on cupy backend (gated on cupy being importable).

The vertical datum shift inside reproject() only worked on the 2-D
in-memory numpy path. Three valid input shapes crashed:

- dask arrays: boolean fancy-index __setitem__ is unsupported, so the
  per-strip update raised ValueError.
- cupy arrays: the Numba JIT geoid lookup only accepts numpy buffers,
  so the call raised TypeError.
- 3-D (y, x, band) results: the per-strip is_valid mask was 2-D while
  the strip slice was 3-D, raising a broadcasting ValueError.

Restructure _apply_vertical_shift into a dispatcher that:

- routes dask inputs through map_blocks so each chunk is shifted in
  place and the output stays lazy;
- moves cupy inputs to host, shifts, and returns a cupy array;
- loops over band slices for 3-D shapes so the same N(y, x) is applied
  to every band.

The numpy path is otherwise unchanged. Add tests covering all three
previously-broken cases.

Also record the audit on the deep-sweep accuracy state CSV.
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant