Skip to content

Add terrain metrics module: TRI, TPI, and Roughness#920

Merged
brendancol merged 1 commit intomasterfrom
add-terrain-metrics
Feb 28, 2026
Merged

Add terrain metrics module: TRI, TPI, and Roughness#920
brendancol merged 1 commit intomasterfrom
add-terrain-metrics

Conversation

@brendancol
Copy link
Contributor

@brendancol brendancol commented Feb 28, 2026

Summary

  • Adds three widely-used terrain morphometry metrics as 3×3 focal window operations on elevation values (no cellsize parameter needed):
    • TRI (Terrain Ruggedness Index) — sqrt(sum((z_neighbor - z_center)²)) over 8 neighbors (Riley et al. 1999)
    • TPI (Topographic Position Index) — z_center - mean(z_neighbors) (Weiss 2001)
    • Roughnessmax(window) - min(window) in 3×3 window (GDAL definition)
  • All four backends supported: NumPy, CuPy, Dask+NumPy, Dask+CuPy
  • Boundary modes: nan, nearest, reflect, wrap
  • @supports_dataset decorator for Dataset input
  • .xrs accessor methods on both DataArray and Dataset
  • ASV benchmarks following the existing Benchmarking pattern

Files changed

File Change
xrspatial/terrain_metrics.py New — core module with kernels, wrappers, public API
xrspatial/__init__.py Add tri, tpi, roughness imports
xrspatial/accessor.py Add methods to both accessor classes
xrspatial/tests/test_terrain_metrics.py New — 179 tests
benchmarks/benchmarks/terrain_metrics.py New — ASV benchmarks
README.md Add 3 rows to Surface section

Test plan

  • pytest xrspatial/tests/test_terrain_metrics.py -v — 179 passed
  • Existing test_curvature.py still passes (75 passed)
  • GPU backends verified on CUDA hardware — 48 passed (24 CuPy, 24 Dask+CuPy)
  • Benchmarks run (ASV runner has a Python 3.14 compat issue, so ran directly)

Benchmark results

Metric Size NumPy (ms) Dask (ms) CuPy (ms)
TRI 100×50 0.10 36.27 0.39
TPI 100×50 0.11 10.10 0.40
Roughness 100×50 0.13 9.87 0.41
TRI 300×150 0.16 10.12 0.37
TPI 300×150 0.11 11.12 0.38
Roughness 300×150 0.14 11.14 0.34
TRI 1000×500 1.87 13.20 0.76
TPI 1000×500 0.60 12.76 0.35
Roughness 1000×500 1.22 13.35 0.33

Dask overhead dominates at small sizes; at 1000×500 the NumPy Numba JIT kernels are sub-2ms and CuPy stays under 1ms.

Implement three widely-used terrain morphometry metrics as 3×3 focal
window operations on elevation values (no cellsize needed):

- TRI (Terrain Ruggedness Index) — Riley et al. 1999
- TPI (Topographic Position Index) — Weiss 2001
- Roughness — GDAL definition (max - min in 3×3 window)

All three support four backends (numpy, cupy, dask+numpy, dask+cupy),
boundary modes (nan, nearest, reflect, wrap), and Dataset input via
@supports_dataset. NaN propagates through all kernels for consistency
between numpy and dask paths (standard GDAL behavior).
@github-actions github-actions bot added the performance PR touches performance-sensitive code label Feb 28, 2026
@brendancol brendancol merged commit 80e073f into master Feb 28, 2026
11 checks passed
@brendancol brendancol deleted the add-terrain-metrics branch March 5, 2026 03:31
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