# catalog/operations/terrain/tpi.yaml

id: terrain_tpi
name: Topographic Position Index
description: >
  Calculate Topographic Position Index (TPI) from DEM. TPI compares elevation
  at each cell to the mean elevation in a neighborhood. Positive values indicate
  ridges/hilltops, negative values indicate valleys/depressions, near-zero
  indicates flat areas or mid-slopes.
version: 1.0.0
category: terrain
type: raster-to-raster
default_implementation: native

inputs:
  - name: dem
    type: raster
    format: cog
    description: Input Digital Elevation Model (GeoTIFF or COG)
    required: true

requires:
  concepts: [elevation]

outputs:
  - name: tpi
    type: raster
    format: cog
    dtype: float32
    unit: meters
    concept: tpi
    description: TPI raster (elevation difference from local mean)

params:
  radius:
    type: integer
    default: 3
    description: Neighborhood radius in cells (e.g., 3 = 7x7 window)
    min: 1
    max: 50

granularity:
  min_resolution_m: 1
  max_resolution_m: 90
  recommended_resolution_m: 10
  output_resolution: inherit
  suitable_aoi_km2:
    min: 0.1
    max: 50000
  realtime_max_km2: 200
  requires_continuous: true

execution:
  realtime_max_km2: 200
  cost_per_km2: 0.001
  time_per_km2_sec: 0.4
  memory_profile: low
  profile:
    cpu: low
    memory: low
    io: medium
  scaling:
    model: linear
    parallelizable: true
    min_chunk_km2: 1

default_input:
  connector: usgs_3dep
  params:
    resolution: 10m

cache_policy:
  regional_precompute: [ski_areas]
  ttl_days: 90
  invalidate_on: [source_update]

# backends: audited 2026-08-14 (defect 50). A key means a runtime that DISPATCHES this op —
# folia-engine `dispatch_op` (products/sdk/folia-engine/src/lib.rs), a `registerOp`/OP_TABLE
# entry in packages/compute, `_BUILTIN_OP_MAP` in folia/compute.py, or a backend manifest
# (folia/backends/*/backend.yaml).
backends:
  python:
    function: geo.terrain.tpi
    dispatch: folia/compute.py _BUILTIN_OP_MAP

display_hints:
  map:
    renderer: maplibre
    palette: diverging
    opacity: 0.8
  info:
    fields: [tpi]
    format: "{value}m"
    section: Terrain

ui:
  icon: trending-up
  color: "#6B8E23"
