Description
viewshed on a numpy raster crashes with ValueError: node not found when a NaN (nodata) cell sits at certain positions relative to the observer. The CPU sweep has explicit NaN handling in _calc_event_elev (it falls back to the center elevation when any of the four bilinear-interpolation neighbours is NaN), but the handling is incomplete: a NaN elevation can still produce a NaN event angle/key, and when the sweep later tries to remove that event from the red-black status tree, _delete_from_tree searches for a node that was never inserted and raises.
How to reproduce
import numpy as np
import xarray as xr
from xrspatial import viewshed
arr = np.full((5, 5), 2.0)
arr[2, 4] = np.nan # NaN cell on the observer's row, to the right
r = xr.DataArray(arr, coords=dict(x=np.arange(5.0), y=np.arange(5.0)), dims=["y", "x"])
viewshed(r, x=2.0, y=2.0, observer_elev=5) # ValueError: node not found
The failure is position-dependent. With the same 5x5 raster and observer at (2, 2):
- NaN at (1, 1), (0, 0), (4, 4): runs fine, no NaN propagated into the output.
- NaN at (2, 4): raises
ValueError: node not found.
Traceback
File ".../xrspatial/viewshed.py", line 1715, in viewshed
return _viewshed_cpu(raster, x, y, observer_elev, target_elev)
File ".../xrspatial/viewshed.py", line 1595, in _viewshed_cpu
viewshed_img = _viewshed_cpu_sweep(...)
File ".../xrspatial/viewshed.py", line 562, in _delete_from_tree
raise ValueError("node not found")
ValueError: node not found
Expected behavior
A NaN/nodata cell should be treated as nodata. The GRASS r.viewshed algorithm this is ported from skips nodata cells when building events. The function should either skip NaN cells when generating events or mark them INVISIBLE/NaN in the output, not crash. Behaviour should not depend on where the NaN sits.
Notes
Found during the viewshed test-coverage sweep. A test that documents the working NaN positions plus an xfail marking the crashing position is being added in a separate test-only PR; this issue tracks the underlying source fix.
Environment
- xarray-spatial: current main
- numpy backend (CPU sweep path)
Description
viewshedon a numpy raster crashes withValueError: node not foundwhen a NaN (nodata) cell sits at certain positions relative to the observer. The CPU sweep has explicit NaN handling in_calc_event_elev(it falls back to the center elevation when any of the four bilinear-interpolation neighbours is NaN), but the handling is incomplete: a NaN elevation can still produce a NaN event angle/key, and when the sweep later tries to remove that event from the red-black status tree,_delete_from_treesearches for a node that was never inserted and raises.How to reproduce
The failure is position-dependent. With the same 5x5 raster and observer at (2, 2):
ValueError: node not found.Traceback
Expected behavior
A NaN/nodata cell should be treated as nodata. The GRASS
r.viewshedalgorithm this is ported from skips nodata cells when building events. The function should either skip NaN cells when generating events or mark them INVISIBLE/NaN in the output, not crash. Behaviour should not depend on where the NaN sits.Notes
Found during the viewshed test-coverage sweep. A test that documents the working NaN positions plus an xfail marking the crashing position is being added in a separate test-only PR; this issue tracks the underlying source fix.
Environment