Skip to content

Added Foundational Hydrology Tools#921

Merged
brendancol merged 16 commits intomasterfrom
add-d8-flow-direction
Mar 2, 2026
Merged

Added Foundational Hydrology Tools#921
brendancol merged 16 commits intomasterfrom
add-d8-flow-direction

Conversation

@brendancol
Copy link
Contributor

Summary

  • Adds D8 flow direction as the first hydrology operation, using ESRI power-of-2 encoding (compatible with GDAL/ArcGIS)
  • Implements all four backends: numpy, cupy, dask+numpy, dask+cupy following the slope.py pattern
  • Includes 66 tests covering correctness, NaN handling, cross-backend consistency, boundary modes, dtype acceptance, dataset support, and cellsize effects
  • Adds ASV benchmarks, accessor methods (new "Hydrology" section), and README documentation

Test plan

  • pytest xrspatial/tests/test_flow_direction.py -v — all 66 tests pass (including GPU)
  • pytest xrspatial/tests/test_slope.py xrspatial/tests/test_terrain_metrics.py -v — all 220 existing tests still pass
  • python -c "from xrspatial import flow_direction" — import works
  • agg.xrs.flow_direction() — accessor works on both DataArray and Dataset

Implements D8 flow direction using ESRI power-of-2 encoding (compatible
with GDAL/ArcGIS) across all four backends (numpy, cupy, dask+numpy,
dask+cupy). Follows the slope.py pattern with explicit cellsize-
parameterized backend wrappers.

New files:
- xrspatial/flow_direction.py — CPU kernel (@ngjit), GPU device/global
  kernels, four backend wrappers, public API with @supports_dataset
- xrspatial/tests/test_flow_direction.py — 66 tests (flat, cardinal,
  diagonal, known bowl, NaN handling, cross-backend, boundary modes,
  dtype acceptance, dataset support, cellsize effect, valid codes)
- benchmarks/benchmarks/flow_direction.py — ASV benchmark

Modified files:
- xrspatial/__init__.py — export flow_direction
- xrspatial/accessor.py — add Hydrology section to both accessors
- README.md — add Hydrology section with Flow Direction entry
@github-actions github-actions bot added the performance PR touches performance-sensitive code label Feb 28, 2026
Extract basin delineation from watershed.py into its own basin.py
module with a basin() public function. The old basins() stays as a
backward-compatible wrapper. Add basin to __init__.py and both
xarray accessors.

Add BoundarySnapshot to _boundary_store.py -- a read-only in-memory
copy of converged boundary strips. BoundaryStore.snapshot() copies
strip data to plain numpy arrays and closes the underlying memmap
temp files. Apply this pattern across all hydrology dask backends
(flow_accumulation, watershed, fill, stream_order) so temp
directories are cleaned up before the lazy dask result is returned.
Previously, BoundaryStore objects captured in map_blocks closures
kept temp files alive indefinitely.
Assigns unique position-based IDs to each stream segment between
junctions, headwaters, and outlets. Supports numpy, cupy, dask+numpy,
and dask+cupy backends.
Moves each pour point to the highest flow-accumulation cell within a
circular search radius so that watershed delineation starts from the
actual drainage channel.  Dask backend extracts sparse pour points
chunk-by-chunk (map_blocks flag pass + selective load) to keep memory
bounded regardless of grid size.
…ptive cache

Replace three memory/performance bottlenecks in _flow_path_dask:

- Path tracing (phase 3): growable numpy buffers (~24 bytes/cell)
  instead of list-of-tuples (~164 bytes/cell)
- Output assembly (phase 4): pre-group cells by chunk via vectorized
  searchsorted + stable argsort, then O(1) dict lookup per block
  instead of O(n_chunks * n_cells) linear scan
- LRU cache: adaptive sizing capped at ~512 MB instead of fixed 32
  entries regardless of chunk size
@brendancol brendancol changed the title Add D8 flow direction module Added Foundational Hydrology Tools Mar 2, 2026
@brendancol brendancol self-assigned this Mar 2, 2026
@brendancol brendancol merged commit 4b599fc into master Mar 2, 2026
11 checks passed
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.

1 participant