name: piton-de-la-fournaise
version: "0.1"
category: events-hazards
themes: [hazards]
family: active-lava-flow-mapping
description: >
  Active lava flow mapping at Piton de la Fournaise, Réunion Island, using
  Sentinel-2 SWIR and NBR. One of the most active basaltic shield volcanoes on
  Earth, Piton de la Fournaise erupts frequently with effusive flows confined
  largely to the Enclos Fouqué caldera; EONET tracked an eruptive episode
  closing April 2026. B12 SWIR saturates over incandescent basaltic channels
  and reveals flow extent even under the eruption's gas plume where visible
  bands are obscured.

settings:
  default_bbox: [55.558, -21.394, 55.858, -21.094]   # Enclos Fouqué caldera, Réunion Island
  default_crs: EPSG:32740                              # UTM 40S, metric
  active_lava_b12_threshold: 0.5    # B12 reflectance > this → thermally active lava
  cooled_lava_nbr_threshold: -0.5   # NBR < this → dark cooled lava / severe burn
  cloud_cover_max_pct: 70           # Tropical island cloud is common; SWIR still penetrates
  prefire_reference:
    start: "2017-07-01"
    end: "2017-09-01"               # Pre-eruption reference window

inputs:
  aoi:
    bbox: [55.558, -21.394, 55.858, -21.094]
    crs_target: EPSG:32740
    notes: Covers Enclos Fouqué caldera and outer flanks of Piton de la Fournaise

  date_range:
    start: "2018-01-01"
    end: "2026-06-01"

  collection:
    uri: "@sentinel-2-l2a"
    stac_endpoint: "https://earth-search.aws.element84.com/v1"

layers:

  # ── SOURCE ──────────────────────────────────────────────────────────────────

  source/s2:
    type: raster_timeseries
    uri: "@sentinel-2-l2a"
    description: >
      Sentinel-2 L2A, bi-weekly scenes (not composited — individual acquisitions
      preserve active-flow evolution). Minimum bands for NBR + thermal anomaly.
    params:
      bbox: [55.558, -21.394, 55.858, -21.094]   # COG spatial window
      datetime: "2018-01-01/2026-06-01"
      assets:
        - B04    # Red — for NBR denominator context; also RGB
        - B08    # NIR — numerator of NBR; dark over cooled lava
        - B12    # SWIR2 — saturates at lava temperatures; penetrates SO2 plume
        - SCL    # Scene classification — mask cloud and cloud shadow
      query:
        "eo:cloud_cover": { lt: 70 }

  source/s2-prefire:
    type: raster
    uri: "@sentinel-2-l2a"
    description: Pre-eruption reference composite for dNBR calculation.
    params:
      bbox: [55.558, -21.394, 55.858, -21.094]
      datetime: "2017-07-01/2017-09-01"
      assets: [B08, B12, SCL]
      query:
        "eo:cloud_cover": { lt: 40 }
      aggregate: median

  # ── COMPUTE ─────────────────────────────────────────────────────────────────

  compute/cloud-masked:
    type: raster_timeseries
    compute:
      op: cloud_mask_sentinel2
      inputs:
        data: { layer: source/s2 }
      params:
        scl_classes: [4, 5, 6, 11]   # keep: vegetation, bare soil, water, snow/ice

  compute/nbr:
    type: raster_timeseries
    description: NBR = (B08 - B12) / (B08 + B12). High = healthy veg; low = bare/burned.
    compute:
      op: raster_calc
      inputs:
        data: { layer: compute/cloud-masked }
      params:
        expression: "(B08 - B12) / (B08 + B12)"
        output_band: nbr

  compute/active-lava-mask:
    type: raster_timeseries
    description: >
      Active lava: B12 > 0.5 (SWIR2 saturation from thermal emission at ~600°C+).
      Identifies actively flowing or fountaining lava in each scene.
    compute:
      op: raster_calc
      inputs:
        data: { layer: compute/cloud-masked }
      params:
        expression: "(B12 > active_lava_b12_threshold).astype('uint8')"
        active_lava_b12_threshold: "${settings.active_lava_b12_threshold}"
        output_band: active_lava

  compute/prefire-nbr:
    type: raster
    description: Pre-eruption NBR reference from the Jul-Sep 2017 composite.
    compute:
      op: raster_calc
      inputs:
        data: { layer: source/s2-prefire }
      params:
        expression: "(B08 - B12) / (B08 + B12)"
        output_band: nbr_prefire

  compute/dnbr-stack:
    type: raster_timeseries
    # raster_calc reads ONE raster and binds bands positionally (b1..bN), so two-layer
    # arithmetic composes through stack_concat: stack the pair, difference the bands.
    compute:
      op: stack_concat
      inputs:
        rasters:
          - { layer: compute/prefire-nbr }   # band 1: prefire NBR
          - { layer: compute/nbr }   # band 2: postfire NBR

  compute/dnbr:
    type: raster_timeseries
    description: >
      dNBR = NBR_prefire - NBR_postfire. Positive = vegetation/surface loss.
      USGS severity classes: low 0.1-0.27, mod-low 0.27-0.44, mod-high 0.44-0.66, high >0.66.
    compute:
      op: raster_calc
      inputs:
        data: { layer: compute/dnbr-stack }
      params:
        expression: "b1 - b2"   # NBR_prefire - NBR_postfire
        output_band: dnbr

  # ── RESULTS ─────────────────────────────────────────────────────────────────

  result/lava-flow-extent:
    type: vector
    description: >
      Dated lava flow polygons: cooled lava (NBR < -0.5) per acquisition.
      Attributes: date, area_km2, type (active | cooled), dnbr_mean.
    compute:
      op: raster_to_vector_timeseries
      inputs:
        active: { layer: compute/active-lava-mask }
        dnbr: { layer: compute/dnbr }
      params:
        cooled_threshold: "${settings.cooled_lava_nbr_threshold}"
        min_area_ha: 0.5

  result/dnbr-severity:
    type: raster
    description: Peak dNBR severity COG — maximum dNBR value per pixel across all post-eruption scenes.
    compute:
      op: raster_reduce
      inputs:
        timeseries: { layer: compute/dnbr }
      params:
        reducer: max
        format: cog
        dtype: float32

outputs:
  primary:
    - result/lava-flow-extent   # GeoParquet — dated flow polygons
    - result/dnbr-severity      # COG — peak burn severity map
  show_your_work:
    - compute/nbr               # zarr — per-scene NBR
    - compute/active-lava-mask  # zarr — active lava detections

cache:
  scope:
    - inputs.aoi.bbox
    - inputs.date_range
    - settings.active_lava_b12_threshold
    - settings.cooled_lava_nbr_threshold
  storage: ./cache/
  reuse_policy: hash_inputs

license:
  recipe: Apache-2.0
  output_dataset: CC-BY-4.0
  upstream_data:
    - { source: sentinel-2-l2a, license: copernicus-open }
