# catalog/operations/terrain/curvature.yaml

id: terrain_curvature
name: Curvature
description: >
  Calculate terrain curvature from DEM. Curvature describes how the slope
  changes across the surface. Profile curvature affects flow acceleration,
  planform curvature affects flow convergence. Positive values = convex
  (ridges), negative values = concave (valleys).
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: curvature
    type: raster
    format: cog
    dtype: float32
    unit: 1/meters
    concept: curvature
    description: Curvature raster (positive=convex, negative=concave)

params:
  type:
    type: enum
    default: total
    enum: [profile, planform, total]
    description: >
      Type of curvature to compute:
      - profile: curvature in direction of slope (flow acceleration)
      - planform: curvature perpendicular to slope (flow convergence)
      - total: combined Laplacian curvature

granularity:
  min_resolution_m: 1
  max_resolution_m: 30
  recommended_resolution_m: 10
  output_resolution: inherit
  suitable_aoi_km2:
    min: 0.01
    max: 10000
  realtime_max_km2: 100
  requires_continuous: true

uncertainty:
  error_model: propagated
  factors:
    - name: dem_noise_amplification
      description: "Second derivative amplifies DEM noise significantly"
      severity: high
      mitigations:
        - "Smooth DEM before computing curvature"
        - "Use 10m+ resolution to reduce noise effects"
    - name: cell_size_dependency
      description: "Curvature magnitude depends on cell size"
      severity: medium
      mitigations:
        - "Compare curvature values only within same-resolution datasets"
  limitations:
    - "Second-derivative operation: very sensitive to noise"
    - "Values are resolution-dependent and not directly comparable across resolutions"

execution:
  realtime_max_km2: 100
  cost_per_km2: 0.002
  time_per_km2_sec: 0.8
  memory_profile: medium
  profile:
    cpu: medium
    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:
  rust-wasm:
    function: terrain_ops::terrain_curvature
    handle_function: h_terrain_curvature
  js:
    function: terrain_curvature
  python:
    function: geo.terrain.curvature
    dispatch: folia/compute.py _BUILTIN_OP_MAP

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

ui:
  icon: git-branch
  color: "#4169E1"
