You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
mean() returns a different dtype depending on the backend. The function casts input to float64 (agg.data.astype(float)) before dispatch, and the numpy and dask+numpy paths keep that. But _mean_cupy re-casts to float32 (cupy.asarray(data, dtype=cupy.float32)) and _mean_dask_cupy does data.astype(cupy.float32), so the GPU backends silently downcast float64 input and lose precision. _mean_dask_cupy also builds its graph with an untyped meta=cupy.array(()), so the lazy DataArray advertises float64 while .compute() returns float32.
apply() and focal_stats() advertise the wrong dtype on the dask backends. Preserve input float dtype in apply() and focal_stats() (#2769) #2805 made the chunk functions preserve the input float dtype via _promote_float, but the map_overlap calls in _apply_dask_numpy, _apply_dask_cupy, and _focal_stats_dask_cupy still pass an untyped meta (np.array(()) / cupy.array(())), which defaults to float64. For float32 or integer input, the lazy result claims float64 but computes to float32.
Describe the bug
Two related dtype problems in
xrspatial/focal.py:mean()returns a different dtype depending on the backend. The function casts input to float64 (agg.data.astype(float)) before dispatch, and the numpy and dask+numpy paths keep that. But_mean_cupyre-casts to float32 (cupy.asarray(data, dtype=cupy.float32)) and_mean_dask_cupydoesdata.astype(cupy.float32), so the GPU backends silently downcast float64 input and lose precision._mean_dask_cupyalso builds its graph with an untypedmeta=cupy.array(()), so the lazy DataArray advertises float64 while.compute()returns float32.apply()andfocal_stats()advertise the wrong dtype on the dask backends. Preserve input float dtype in apply() and focal_stats() (#2769) #2805 made the chunk functions preserve the input float dtype via_promote_float, but themap_overlapcalls in_apply_dask_numpy,_apply_dask_cupy, and_focal_stats_dask_cupystill pass an untypedmeta(np.array(())/cupy.array(())), which defaults to float64. For float32 or integer input, the lazy result claims float64 but computes to float32.Measured on this host (all four backends live):
Expected behavior
mean()returns float64 on all four backends, matching the CPU contract and the docstring examples, with no precision loss on the GPU paths.apply()andfocal_stats()advertise the dtype they actually compute.Same class of bug as #2682 (aspect) and #2723 (proximity), which were fixed by passing a typed
meta/dtypeto the dask graph constructors.Additional context
Found by the metadata propagation sweep against
focal. attrs, coords, dims, and.namechecked clean across all four backends on the same run.