Align convolution dask output dtype with numpy/cupy (#3618)#3622
Merged
brendancol merged 4 commits intoJul 6, 2026
Merged
Conversation
) The dask backends declared float64 via meta=np.array(()) even when the eager numpy/cupy backends promote an int or float32 raster to float32, so result.dtype disagreed across backends and did not match the float32 chunks dask actually computes. Pass the promoted float dtype into the map_overlap meta so the declared dtype matches both the eager backends and the computed chunks. Adds a parametrized regression test. Also records the convolution metadata sweep state (2026-07-02).
brendancol
commented
Jul 6, 2026
brendancol
left a comment
Contributor
Author
There was a problem hiding this comment.
PR Review: Align convolution dask output dtype with numpy/cupy (#3618)
Domain-aware review (metadata sweep).
Blockers (must fix before merge)
- None.
Suggestions (should fix, not blocking)
- None.
Nits (optional improvements)
- The regression test in
xrspatial/tests/test_convolution.py:12covers only the numpy and dask+numpy backends. The same untyped-meta bug lived on_convolve_2d_dask_cupy(xrspatial/convolution.py:477) and is fixed the same way, but there's no GPU assertion, so the cupy half of the fix rides on inspection. A@cuda_and_cupy_availabledtype check would exercise the cupy and dask+cupy paths on hosts with a GPU. Not blocking, since the CI matrix skips GPU tests anyway.
What looks good
- The change stays scoped to the reported defect. Both dask backends hoist
_promote_float(data.dtype)into a local and pass it as themetadtype, so the lazy DataArray advertises the same dtype the chunks compute (np.empty_like(data)on the already-promoted input in_convolve_2d_numpy). Nothing else in the two functions moves. - Verified on a CUDA host across all four backends: int32/float32 input reports float32 everywhere, and the two dask paths used to advertise float64. float64 input is unchanged.
pytest xrspatial/tests/test_convolution.pypasses. - The wider metadata audit came back clean.
convolution_2dkeeps name, dims, coords (passthrough coords included), and attrs (crs, res, transform, nodatavals, _FillValue) on every backend. dtype was the only cross-backend divergence. - The pre-existing isort drift in
convolution.pywas left alone (it already fails isort onmainand belongs in a style pass), and the second commit only fixes the isort grouping the new test imports introduced.
Checklist
- Algorithm matches reference/paper (no algorithm change; dtype metadata only)
- All implemented backends produce consistent results (float32 for int/float32, float64 preserved)
- NaN handling is correct (unchanged)
- Edge cases are covered by tests (int32/float32/float64 parametrized)
- Dask chunk boundaries handled correctly (depth/boundary unchanged)
- No premature materialization or unnecessary copies
- Benchmark exists or is not needed (metadata-only fix, no perf change)
- README feature matrix updated (not applicable)
- Docstrings present and accurate
brendancol
commented
Jul 6, 2026
brendancol
left a comment
Contributor
Author
There was a problem hiding this comment.
Follow-up review (#3622)
Follows up on my earlier review's one nit (no GPU dtype assertion) and the sync with main.
What changed since the last review
- New commit
26c904e8addstest_convolve_2d_cupy_dtype_matches_numpyinxrspatial/tests/test_convolution.py:26, a@cuda_and_cupy_availableparametrization over int32/float32/float64 that asserts the cupy and dask+cupy outputs declare (and compute) the same promoted dtype the eager numpy backend returns. That closes the gap the nit called out, so themeta=cupy.array((), dtype=fdtype)half of the fix is regression-tested rather than eyeballed. - Merged
origin/main(19 commits).mainhad touchedconvolution.pyonly in a style commit (#3613); the dtype fix is unchanged and there were no conflicts.
Verification
- Ran the new GPU test live on a CUDA host (not skipped): all three dtype cases pass on both cupy and dask+cupy. The full
xrspatial/tests/test_convolution.pyis 12 passed. isort and flake8 are clean on the changed files after the merge.
No remaining findings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3618.
The dask backends of
convolution_2d/convolve_2ddeclaredfloat64via
meta=np.array(())even when the eager numpy and cupy backends promotean int or float32 raster to float32. So
result.dtypechanged depending onthe backend, and the declared dask dtype did not even match the float32
chunks dask computes.
Change
_convolve_2d_dask_numpyand_convolve_2d_dask_cupynow pass thepromoted float dtype into the
map_overlapmeta, so the declared dtypematches both the eager backends and the computed chunks.
Backends
numpy, cupy, dask+numpy, dask+cupy all verified on a CUDA host: for a
float32 input every backend now reports float32 (was float64 on the two
dask paths). float64 input is unchanged.
Test plan
pytest xrspatial/tests/test_convolution.py(9 passed)computed chunk dtype both equal the eager dtype for int32, float32,
and float64 input.