Skip to content

viewshed dask Tier C fallback diverges from exact sweep but is documented as minor #2872

@brendancol

Description

@brendancol

Describe the bug

The dask "Tier C" out-of-core fallback in viewshed() produces visibility masks that diverge substantially from the exact numpy sweep, but the docstring at xrspatial/viewshed.py:1670 only describes "minor visibility differences near the boundary of occluded regions." On random terrain the divergence is far larger than that, and there is no runtime warning. Large dask rasters can feed downstream visibility logic with silently wrong results.

Tier C (starting at xrspatial/viewshed.py:2227) is a horizon-profile distance sweep that discretizes occlusion into angular bins. It is a different, approximate visibility model from the exact GRASS r.viewshed event sweep used by the CPU/Tier-B path. The error is geometric, not a resolution artifact: raising the angular bin count does not reduce the mismatch count.

Reproduce

Force Tier C on a small random terrain (call _viewshed_distance_sweep directly, or shrink the memory budget so _viewshed_dask skips Tier B) and diff the visibility mask against _viewshed_cpu.

Measured mask mismatches vs the exact sweep (observer at grid center, integer-coordinate grid, no observer/target elevation offset):

  • 20x20, seed 0: 81 / 400 cells (20.2%)
  • 20x20, seed 42: 25 / 400 cells (6.2%)
  • 40x40, seed 42: 199 / 1600 cells (12.4%)

Mismatches include both false positives and false negatives. Raising n_angles from 360 to 500000 does not change the count.

Expected behavior

Either Tier C matches the exact sweep, or the documentation states the real accuracy contract and the code emits a runtime warning when the Tier C path runs, so users do not silently receive approximate visibility from large dask inputs.

Additional context

Reimplementing the exact event sweep out-of-core is a large undertaking, and it is the reason Tier C exists: the exact algorithm's working set does not fit when the grid exceeds memory. The horizon-profile model cannot be made exact without becoming the exact algorithm.

Affected: dask+numpy and dask+cupy backends on grids large enough to skip Tier B and without max_distance set.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdaskDask backend / chunked arrays

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions