name: kilauea-lava
version: "0.1"
category: events-hazards
themes: [hazards]
family: active-lava-flow-mapping
description: >
  Active lava flow mapping on the Big Island of Hawai'i using Sentinel-2 SWIR
  and NBR. The 2018 Lower East Rift Zone eruption destroyed 716 structures and
  added 3.5 km² of new land; ongoing Halemaʻumaʻu summit activity from 2020
  continues. SWIR bands (B12) saturate at active lava temperatures and penetrate
  volcanic SO2 plumes where visible bands cannot — essential for mapping through
  the eruption haze.

settings:
  default_bbox: [-154.95, 19.35, -154.75, 19.55]   # LERZ + Kilauea summit, Big Island
  default_crs: EPSG:32605                            # UTM 5N, 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: 80           # Volcanic scenes often partly cloudy; SWIR still penetrates
  prefire_reference:
    start: "2018-01-01"
    end: "2018-04-01"               # Before LERZ eruption onset (May 2018)

inputs:
  aoi:
    bbox: [-154.95, 19.35, -154.75, 19.55]
    crs_target: EPSG:32605
    notes: Covers LERZ (Leilani Estates) + Kilauea summit caldera (Halemaʻumaʻu)

  date_range:
    start: "2018-04-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: [-154.95, 19.35, -154.75, 19.55]   # COG spatial window
      datetime: "2018-04-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: 80 }

  source/s2-prefire:
    type: raster
    uri: "@sentinel-2-l2a"
    description: Pre-eruption reference composite for dNBR calculation.
    params:
      bbox: [-154.95, 19.35, -154.75, 19.55]
      datetime: "2018-01-01/2018-04-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 Jan-Apr 2018 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 }
