Skip to content

Add Dinf flow accumulation (#938)#945

Merged
brendancol merged 1 commit into
masterfrom
worktree-issue-938
Mar 4, 2026
Merged

Add Dinf flow accumulation (#938)#945
brendancol merged 1 commit into
masterfrom
worktree-issue-938

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Summary

  • flow_accumulation() silently returned wrong results for Dinf input (every cell = 1.0) because _code_to_offset truncated float angles to ints that never matched any D8 code
  • Auto-detects D8 vs Dinf from input values, then branches to the appropriate algorithm
  • Dinf path uses Tarboton's proportional flow splitting between two downslope neighbors
  • All four backends: numpy, cupy, dask+numpy, dask+cupy

What changed

xrspatial/flow_accumulation.py

  • _classify_flow_block / _detect_flow_type: scan input values to distinguish D8 codes from Dinf angles (handles the 0.0 ambiguity between D8 pit and Dinf east-angle)
  • _angle_to_neighbors: decompose a Dinf angle into two downstream neighbors with proportional weights
  • _flow_accum_dinf_cpu: Kahn's BFS with fractional splitting
  • GPU kernels (_init_accum_indegree_dinf, _pull_from_frontier_dinf, _flow_accum_dinf_cupy): frontier-peeling with inlined angle decomposition, reuses _find_ready_and_finalize from D8
  • Dask tile sweep (_flow_accum_dinf_tile_kernel, _compute_seeds_dinf, etc.): boundary-propagation with fractional cross-tile seeds
  • flow_accumulation() docstring updated, Tarboton (1997) reference added

xrspatial/tests/test_flow_accumulation.py

  • Detection tests (D8 codes, Dinf angles, all-NaN, -1.0 pit)
  • Correctness tests (cardinal east chain, pit center, 50/50 split, cascading chain, NaN handling)
  • End-to-end: flow_direction_dinf(elevation) -> flow_accumulation()
  • Cross-backend: dask with 6 chunk configs, cupy, dask+cupy

Test plan

  • All 45 tests pass (pytest xrspatial/tests/test_flow_accumulation.py)
  • 24 existing D8 tests unchanged and passing
  • Smoke test: flow_direction_dinf -> flow_accumulation on random 20x20 elevation, all values >= 1.0

flow_accumulation() only understood D8 integer codes. Passing Dinf
angles from flow_direction_dinf() silently produced wrong results
(every cell got 1.0) because float angles never matched any D8 code
in _code_to_offset.

Auto-detect D8 vs Dinf from input values, then run Tarboton's
proportional splitting for Dinf. All four backends covered: numpy,
cupy, dask+numpy, dask+cupy. 45 tests pass (24 existing D8 unchanged,
15 new Dinf, 6 detection).
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label Mar 4, 2026
@brendancol brendancol merged commit bfafd6f into master Mar 4, 2026
11 checks passed
@brendancol brendancol deleted the worktree-issue-938 branch May 4, 2026 13:06
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