Two backend-parity bugs in xrspatial/reproject/__init__.py.
Dask reproject reports wrong output dtype for integer sources
_reproject_dask always builds the dask template with dtype=np.float64 (lines 1301-1310), but _reproject_chunk_numpy returns the source's integer dtype after clamping (lines 292-294, 309-312). The eager numpy path returns int8 for an int8 source; the dask path advertises float64 in its meta while chunks underneath return int8. The dask graph is internally inconsistent.
Fix: pick the template dtype from the source. Integer source -> integer output; float source -> float64 (current behaviour).
The cupy chunk has the same gap (no integer clamp on output), so apply the same dtype round-trip there for consistency.
Same-CRS dask merge does not use the direct-placement shortcut
_merge_inmemory checks info['src_crs'] == tgt_crs and calls _place_same_crs for matching CRS rasters (line 1560). The dask adapter _merge_block_adapter (line ~1601) always calls _reproject_chunk_numpy, even when source and target CRS match. Same-CRS merges then differ between eager and dask paths by interpolation noise.
Fix: precompute same_crs[i] = (src_crs_i == tgt_crs) in _merge_dask, pass via partial, and call _place_same_crs first in the per-block adapter. Fall back to _reproject_chunk_numpy if _place_same_crs returns None (resolutions too different).
Missing test coverage
- No test asserts dask reproject preserves integer dtype.
- No test asserts dask merge of same-CRS inputs equals eager merge.
- The 235-line
_reproject_dask_cupy path has no end-to-end test.
- No
test_dask_cupy_matches_numpy.
Two backend-parity bugs in
xrspatial/reproject/__init__.py.Dask reproject reports wrong output dtype for integer sources
_reproject_daskalways builds the dask template withdtype=np.float64(lines 1301-1310), but_reproject_chunk_numpyreturns the source's integer dtype after clamping (lines 292-294, 309-312). The eager numpy path returns int8 for an int8 source; the dask path advertises float64 in its meta while chunks underneath return int8. The dask graph is internally inconsistent.Fix: pick the template dtype from the source. Integer source -> integer output; float source -> float64 (current behaviour).
The cupy chunk has the same gap (no integer clamp on output), so apply the same dtype round-trip there for consistency.
Same-CRS dask merge does not use the direct-placement shortcut
_merge_inmemorychecksinfo['src_crs'] == tgt_crsand calls_place_same_crsfor matching CRS rasters (line 1560). The dask adapter_merge_block_adapter(line ~1601) always calls_reproject_chunk_numpy, even when source and target CRS match. Same-CRS merges then differ between eager and dask paths by interpolation noise.Fix: precompute
same_crs[i] = (src_crs_i == tgt_crs)in_merge_dask, pass via partial, and call_place_same_crsfirst in the per-block adapter. Fall back to_reproject_chunk_numpyif_place_same_crsreturns None (resolutions too different).Missing test coverage
_reproject_dask_cupypath has no end-to-end test.test_dask_cupy_matches_numpy.