Skip to content

Fix cupy backend crash in cumulative_viewshed/visibility_frequency#3205

Merged
brendancol merged 5 commits into
mainfrom
deep-sweep-metadata-visibility-2026-06-10
Jun 11, 2026
Merged

Fix cupy backend crash in cumulative_viewshed/visibility_frequency#3205
brendancol merged 5 commits into
mainfrom
deep-sweep-metadata-visibility-2026-06-10

Conversation

@brendancol

Copy link
Copy Markdown
Contributor

Closes #3193

cumulative_viewshed initialized its accumulator count as a numpy array for every non-dask raster, so accumulating cupy viewshed results raised TypeError: Unsupported type <class 'numpy.ndarray'> on the GPU backend. visibility_frequency wraps cumulative_viewshed, so it failed the same way.

  • Initialize count as a cupy array when the raster is cupy-backed, mirroring the existing dask branch. The accumulation stays on-device and the result is a cupy-backed DataArray.
  • On cupy the returned DataArray now carries the input coords, dims, and attrs (crs included), matching numpy and dask+numpy.
  • Add cupy cross-backend tests for both functions.

Backend coverage: numpy and dask+numpy unchanged; cupy now works instead of crashing. dask+cupy isn't exercised by these functions (the dask branch runs before the cupy branch).

Test plan:

  • pytest xrspatial/tests/test_visibility.py (28 passed, including 3 new cupy tests on an RTX host)
  • Confirmed the cupy result is a real cupy.ndarray with int32/float64 dtype and preserved coords/dims/attrs
  • Confirmed cupy cumulative_viewshed matches the cupy viewshed binary mask for a single observer

…3193)

count was always initialized as a numpy array, so accumulating cupy
viewshed results raised TypeError on the GPU backend. Initialize count
as a cupy array when the raster is cupy-backed, mirroring the existing
dask branch, so the result is a cupy-backed DataArray that carries the
input coords, dims, and attrs. Add cupy cross-backend tests.

Also records the visibility metadata sweep state.

@brendancol brendancol left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review: Fix cupy backend crash in cumulative_viewshed/visibility_frequency

Blockers

None.

Suggestions

None blocking. One thing worth a sentence in the docstring or a comment: cumulative_viewshed checks the dask branch before the cupy branch, so a dask-of-cupy raster goes through the dask path and never hits the new cp.zeros branch. That matches how the function already worked and the PR body calls it out, but a one-line comment at the branch would save the next reader the trace.

Nits

The new _is_cupy guard recomputes has_cuda_and_cupy(); that is cheap and matches the style of the surrounding code, so leaving it is fine.

What looks good

  • The cupy branch mirrors the existing dask branch exactly: detect backend, allocate the accumulator on the right device, let the final DataArray wrap whatever count is. Minimal and consistent.
  • Tests assert the result is a real cupy.ndarray, check dtype, and confirm coords/dims/attrs (crs included) survive, which is the actual contract that was broken.
  • The single-observer test compares against the cupy viewshed binary mask rather than the numpy result, which is correct: the RTX viewshed and the CPU sweep disagree on visible-cell counts, so a numpy-vs-cupy value assertion would be wrong here. Good call.

Checklist

  • Fix matches the backend-dispatch pattern used for dask
  • cupy result is consistent with cupy viewshed
  • coords/dims/attrs preserved on cupy
  • Edge cases: empty observers still raises (unchanged path)
  • No premature materialization introduced
  • No new public API, so README/benchmark unaffected
  • Tests gated on cuda+rtx availability

@github-actions github-actions Bot added the performance PR touches performance-sensitive code label Jun 10, 2026
…isibility-2026-06-10

Conflicts:
- .claude/sweep-metadata-state.csv: took main's copy (LF line endings,
  newer rows for other modules) and re-inserted this branch's visibility
  row; diff vs main is exactly that one row.
- xrspatial/visibility.py auto-merged: main's isort import ordering
  (#3189) composed with this branch's cupy accumulator change.
@brendancol brendancol merged commit fd5a59c into main Jun 11, 2026
7 checks passed
brendancol added a commit that referenced this pull request Jun 11, 2026
The two cupy tests pinned issue #3192 with xfail(strict=True), but
open PR #3205 fixes that crash (filed there as #3193, a duplicate)
and ships its own cupy parity tests for both functions. Merging the
strict pins would break main with XPASS the moment #3205 lands, so
they're dropped and the sweep-state note updated. The rest of the
branch's coverage (cupy transect/line_of_sight parity, NaN LOS,
Fresnel-blocked branch) is unaffected.
brendancol added a commit that referenced this pull request Jun 11, 2026
The remote merge (6e83087) resolved against an older main and kept
the strict #3192 xfails; this side drops them because open PR #3205
fixes that crash and the pins would XPASS once it lands.
brendancol added a commit that referenced this pull request Jun 11, 2026
The dropped xfail pins are confirmed right: #3205's cupy fix for
cumulative_viewshed/visibility_frequency is now on main with its own
parity tests, which auto-merged cleanly alongside this branch's
coverage. CSV keeps this branch's visibility row plus main's newer
zonal row, with main's CRLF endings preserved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cumulative_viewshed and visibility_frequency crash on the cupy backend

1 participant