reproject: make transform_precision=0 force exact pyproj transforms#2654
Merged
Conversation
Dedupe duplicate module rows (last-write-wins by last_inspected) and collapse multi-line notes to single physical lines. The notes had embedded newlines, which the merge=union .gitattributes strategy splits record-by-record, corrupting the file into a 156-column phantom row on parallel-agent appends. One line per record keeps union merges safe.
…2646) The docstring promises transform_precision=0 produces exact per-pixel pyproj transforms, but every backend tried the Numba/CUDA fast path before checking the flag. For CRS pairs the fast path supports (WGS84/NAD83 <-> UTM, WGS84 <-> Web Mercator) the exact branch was never reached, so the escape hatch did nothing. Gate the fast path on transform_precision != 0 in all four call sites: _transform_coords, _reproject_chunk_numpy, _reproject_chunk_cupy, and the dask+cupy streaming loop.
brendancol
commented
May 29, 2026
Contributor
Author
brendancol
left a comment
There was a problem hiding this comment.
PR Review: reproject: make transform_precision=0 force exact pyproj transforms
Blockers
None.
Suggestions
None.
Nits
- The four gates repeat the
precision != 0check inline rather than sharing a helper. For four call sites that already had their own fast-path attempt block, inline is the right call and matches the surrounding style. Noting it so it reads as a deliberate choice, not an oversight.
What looks good
- The fix covers all four fast-path entry points, not just the two named in the issue. The CUDA paths (
_reproject_chunk_cupy, line 480;_reproject_dask_cupystreaming, line 1655) had the same bug and are now gated too. - The regression tests bite.
test_transform_coords_precision_zero_skips_numbaand its two siblings install a spy that raises iftry_numba_transformruns, and they fail on the pre-fix code (verified by stashing the source change).test_numba_fast_path_active_for_this_pairis a sanity check so the regression can't pass vacuously on a CRS pair the fast path doesn't support. test_transform_coords_precision_zero_matches_pyprojchecks the exact path against an independent pyproj reference to 1e-6, so it confirms correct coordinates, not just that numba was skipped.- Pure guard additions. No change to NaN handling, output dtype, or the transform math.
Checklist
- Algorithm matches the documented contract (docstring line 692:
transform_precision=0-> exact per-pixel pyproj) - All implemented backends gated consistently (numpy, dask+numpy via
_reproject_chunk_numpy/_transform_coords; cupy and dask+cupy via the CUDA paths) - NaN handling unchanged
- Edge cases: exact-path coordinate match tested against pyproj reference
- Dask chunk boundaries: unchanged, fix is inside the per-chunk transform
- No premature materialization or extra copies
- Benchmark: not needed, this is a correctness fix on an existing function
- README feature matrix: not applicable, no new function or backend change
- Docstrings present and accurate (the fix makes the code match the existing docstring)
CUDA-path assertions only run where a CUDA runtime is present, so the GPU gating is covered by review plus shared logic rather than an executed GPU test on the CI host.
# Conflicts: # xrspatial/tests/test_reproject.py
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 #2646
Problem
The
reprojectdocstring saystransform_precision=0produces exact per-pixel pyproj transforms matching GDAL/rasterio. The code didn't honor that. Every backend tried the Numba/CUDA fast path before checking the flag, so for CRS pairs the fast path supports (WGS84/NAD83 <-> UTM, WGS84 <-> Web Mercator) the exact pyproj branch was never reached. The escape hatch silently did nothing on exactly the projections where users are most likely to reach for it.Fix
Gate the fast path on
transform_precision != 0at all four call sites:_transform_coords(numba)_reproject_chunk_numpy(numba)_reproject_chunk_cupy(CUDA)_reproject_dask_cupy(CUDA)When
transform_precision == 0, every backend now falls through to the per-pixel pyproj transform.Backend coverage
numpy, dask+numpy go through
_reproject_chunk_numpy/_transform_coords. cupy and dask+cupy go through the CUDA-gated paths. All four are covered.Test plan
TestExactPrecisionEscapeHatchverifiestransform_precision=0matches pyproj-exact coordinates and never callstry_numba_transform(spy raises if it does).test_reproject.pysuite passes (386 tests).GPU assertions run only where a CUDA runtime is present; the CI host without a GPU skips them, so the CUDA path fix is covered by code review plus the shared gating logic rather than an executed GPU test.