name: bangladesh-brahmaputra-flood-pulse
version: "0.1"
category: change-detection
themes: [hydrology, hazards]
family: sar-seasonal-flood-pulse
description: >
  The annual monsoon flood pulse of the Brahmaputra-Jamuna river system in
  Bangladesh — one of the most dramatic seasonal water body changes on Earth.
  Each monsoon, 20-30% of Bangladesh floods; for 160 million people this is not
  a disaster but the agricultural cycle, depositing silt that renews farmland.
  SAR (Sentinel-1) is essential: monsoon clouds blanket Bangladesh during peak
  inundation, making optical useless for the event that matters most.

settings:
  default_bbox: [89.0, 24.2, 91.8, 25.8]   # Brahmaputra-Jamuna floodplain, Bangladesh
  default_crs: EPSG:32646                   # UTM 46N, metric
  flood_vv_threshold_db: -15.0             # VV_dB < this → open water (flat water = low backscatter)
  orbit_direction: descending              # Morning overpass — less wind roughening on water surface
  cloud_cover_max_pct: 100                 # SAR is cloud-independent; no filter needed

inputs:
  aoi:
    bbox: [89.0, 24.2, 91.8, 25.8]
    crs_target: EPSG:32646
    notes: >
      Jamuna (Brahmaputra) main channel + chars (river islands) + floodplain.
      Peak inundation typically August; recession by October.

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

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

layers:

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

  source/s1-grd:
    type: raster_timeseries
    uri: "@sentinel-1-grd"
    description: >
      Sentinel-1 GRD, descending orbit only (morning pass — less surface wind,
      more stable open-water signature). Monthly composites. Two polarisations only.
    params:
      bbox: [89.0, 24.2, 91.8, 25.8]   # COG spatial window
      datetime: "2016-01-01/2026-06-01"
      assets:
        - VV    # Primary flood band — open water has very low VV backscatter
        - VH    # Secondary — helps discriminate flooded vegetation from open water
      query:
        "sat:orbit_state": descending
      aggregate: median
      group_by: year_month

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

  compute/vv-db:
    type: raster_timeseries
    description: >
      Convert VV from linear power to decibels: VV_dB = 10 * log10(VV_linear).
      Log scale is required before thresholding — open water is ~-20 to -15 dB;
      vegetation is ~-10 to -5 dB.
    compute:
      op: raster_calc
      inputs:
        data: { layer: source/s1-grd }
      params:
        expression: "10.0 * log10(VV + 1e-10)"   # epsilon guard against log(0)
        output_band: vv_db

  compute/flood-mask-monthly:
    type: raster_timeseries
    description: >
      Binary monthly flood mask. 1 = open water (VV_dB < threshold), 0 = land.
      Threshold -15 dB is empirical for flat floodplain water; urban double-bounce
      can appear bright and is not misclassified as water.
    compute:
      op: raster_calc
      inputs:
        data: { layer: compute/vv-db }
      params:
        expression: "(vv_db < flood_vv_threshold_db).astype('uint8')"
        flood_vv_threshold_db: "${settings.flood_vv_threshold_db}"
        output_band: flood

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

  result/monthly-flood-extent:
    type: table
    description: >
      Monthly flood area in km². One row per month: (year_month, flood_area_km2).
      The primary time series — shows the annual flood pulse rising and falling.
    compute:
      op: raster_area_timeseries
      inputs:
        mask: { layer: compute/flood-mask-monthly }
      params:
        condition: "flood == 1"
        unit: km2

  result/annual-flood-pulse:
    type: table
    description: >
      Annual flood pulse statistics. One row per year:
      (year, dry_season_km2, peak_flood_km2, pulse_amplitude_km2).
    compute:
      op: temporal_summary
      inputs:
        timeseries: { layer: result/monthly-flood-extent }
      params:
        group_by: year
        dry_months: [1, 2, 3]     # Jan-Mar: minimum inundation
        peak_months: [7, 8, 9]   # Jul-Sep: maximum inundation
        stats: [min_as_dry, max_as_peak, amplitude]

  result/peak-flood-mask:
    type: raster
    description: Annual maximum flood extent COG — one band per year showing the high-water mark.
    compute:
      op: raster_reduce_annual
      inputs:
        timeseries: { layer: compute/flood-mask-monthly }
      params:
        reducer: max
        format: cog
        dtype: uint8

outputs:
  primary:
    - result/monthly-flood-extent   # Parquet — (year_month, flood_area_km2)
    - result/annual-flood-pulse     # Parquet — (year, dry_km2, peak_km2, amplitude_km2)
    - result/peak-flood-mask        # COG — annual max extent stack
  show_your_work:
    - compute/vv-db                 # zarr — VV in dB scale

cache:
  scope:
    - inputs.aoi.bbox
    - inputs.date_range
    - settings.flood_vv_threshold_db
    - settings.orbit_direction
  storage: ./cache/
  reuse_policy: hash_inputs

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