Describe the bug
#2651 disabled the numba fast path when either CRS uses a non-WGS84 datum: the projection kernels run in WGS84, so skipping the datum shift returned corrupt coordinates. That fix gated try_numba_transform and transform_points in _projections.py. try_cuda_transform in _projections_cuda.py never got the same guard.
The CUDA dispatcher matches projected CRSs through _tmerc_params / _lcc_params / etc., and those accept any datum present in the Helmert table via _is_wgs84_compatible_ellipsoid (OSGB36/airy, DHDN/potsdam, MGI, ED50, NAD27, ...). So a cupy or dask+cupy reproject between EPSG:4326 and EPSG:27700 runs the WGS84 Krueger series with no datum shift and no Airy ellipsoid handling.
Measured on a GPU host:
try_cuda_transform(EPSG:4326 -> EPSG:27700) coordinates differ from pyproj by up to ~0.0014 deg (~96 m).
- End to end,
reproject(raster, 'EPSG:27700') on the cupy backend differs from the numpy backend by up to 0.094 on data in [0, 1] (the sampler reads roughly 10 pixels away from the right spot), and 5 cells flip between NaN and finite on a 64x64 input.
numpy and dask+numpy are unaffected because try_numba_transform already bails to pyproj for these pairs.
Expected behavior
cupy and dask+cupy should match numpy. When either side uses a non-WGS84 datum, try_cuda_transform should return None so the chunk worker falls back to the CPU path (which then defers to pyproj), the same way #2651 handled the CPU kernels.
Additional context
Found by the accuracy sweep. Affected pairs: geographic WGS84/NAD83 to or from any projected CRS whose proj4 dict carries a datum/ellps key in _DATUM_PARAMS. EPSG:27700 confirmed live; the DHDN, MGI, ED50, and NAD27 entries hit the same dispatch.
Describe the bug
#2651 disabled the numba fast path when either CRS uses a non-WGS84 datum: the projection kernels run in WGS84, so skipping the datum shift returned corrupt coordinates. That fix gated
try_numba_transformandtransform_pointsin_projections.py.try_cuda_transformin_projections_cuda.pynever got the same guard.The CUDA dispatcher matches projected CRSs through
_tmerc_params/_lcc_params/ etc., and those accept any datum present in the Helmert table via_is_wgs84_compatible_ellipsoid(OSGB36/airy, DHDN/potsdam, MGI, ED50, NAD27, ...). So a cupy or dask+cupy reproject between EPSG:4326 and EPSG:27700 runs the WGS84 Krueger series with no datum shift and no Airy ellipsoid handling.Measured on a GPU host:
try_cuda_transform(EPSG:4326 -> EPSG:27700)coordinates differ from pyproj by up to ~0.0014 deg (~96 m).reproject(raster, 'EPSG:27700')on the cupy backend differs from the numpy backend by up to 0.094 on data in [0, 1] (the sampler reads roughly 10 pixels away from the right spot), and 5 cells flip between NaN and finite on a 64x64 input.numpy and dask+numpy are unaffected because
try_numba_transformalready bails to pyproj for these pairs.Expected behavior
cupy and dask+cupy should match numpy. When either side uses a non-WGS84 datum,
try_cuda_transformshould return None so the chunk worker falls back to the CPU path (which then defers to pyproj), the same way #2651 handled the CPU kernels.Additional context
Found by the accuracy sweep. Affected pairs: geographic WGS84/NAD83 to or from any projected CRS whose proj4 dict carries a datum/ellps key in
_DATUM_PARAMS. EPSG:27700 confirmed live; the DHDN, MGI, ED50, and NAD27 entries hit the same dispatch.