q23·intermediate

After the cyclone made landfall, which villages and farms near me got flooded?

hydrologydisaster-responsewater-extent Datasets: 5 1–6 hours (real disaster-response timing)
Find the data for your area

Draw a rectangle to pick your area of interest, then see what NASA data covers it (live, here in your browser) or download a ready-to-run notebook with your AOI pre-filled. The notebook runs in any Python environment — it needs a free Earthdata Login to fetch the data.

Current AOI: 89, 21.5 → 91, 23 (Bangladesh coast — Khulna/Barisal delta (Bay of Bengal cyclone zone))

After the cyclone made landfall, which villages and farms near me got flooded?

What you can answer

  • Post-landfall flood extent through thick cloud — OPERA DSWx-S1 is derived from Sentinel-1 radar, which sees the ground even under the cyclone’s cloud shield when optical sensors are blind.
  • Open-water vs. partial / inundated-vegetation flooding — the DSWx-S1 water classification (WTR) layer flags open water, inundated vegetation, and low/high-confidence water separately, so flooded rice paddies and mangrove fringe show up, not just open ponds.
  • Which named villages and farm parcels overlap the flood — clip the flood mask to an AOI around a settlement and intersect with OSM building/landuse polygons to list affected places.
  • Roughly how many people are in the flooded area — overlay free WorldPop population (1 km) on the flood mask and count, then name the flooded districts with geoBoundaries (verified: ~16.3M people in the default delta box, district Pirojpur).
  • Storm rainfall driving the flood — GPM IMERG Half-Hourly Early run gives a near-real-time (~4 h latency) rainfall accumulation over the landfall window to explain where water pooled.
  • Inland flood signal during the storm itself — CYGNSS GPS-reflectometry surface-reflectivity rises sharply over standing water and penetrates the storm, giving a coarse “is it flooding right now” cue between Sentinel-1 overpasses.

What you can NOT answer with these datasets alone

  • Flood depth or “is my house’s ground floor underwater” — DSWx-S1 maps water presence, not depth. You need a DEM (e.g. Copernicus GLO-30) plus a hydraulic model (HEC-RAS) for depth.
  • Building-by-building or crop-by-crop damage — 30 m DSWx pixels and ~25 km CYGNSS footprints are far too coarse; damage assessment needs commercial high-res (Maxar, Planet, ICEYE).
  • The exact hour of peak flood — Sentinel-1 revisit is ~6–12 days at a given spot, so DSWx-S1 captures snapshots, not the rising/falling curve. CYGNSS fills gaps only coarsely.
  • Urban interior / drainage flooding — radar struggles in built-up areas (corner reflections stay bright over water); DSWx flags dense-urban pixels as unreliable.
  • Saltwater vs. freshwater inundation — these sensors see water, not salinity, which matters a lot for farmland recovery.

Code template (Python, cloud-direct)

Verified locally. OPERA DSWx-S1 coverage over the Bay of Bengal begins in 2024, so pick a recent cyclone — the window below is Cyclone Dana (landfall 25 Oct 2024). Each granule is a UTM-projected COG tile; the water layer is *_B01_WTR.tif. Download the WTR tiles, mosaic them, then reproject/clip to your AOI. (PO.DAAC occasionally returns a transient 502 on cloud reads — just retry.)

import earthaccess, glob
import rioxarray
from rioxarray.merge import merge_arrays
import xarray as xr
import numpy as np

earthaccess.login(strategy="netrc")

# Bay of Bengal landfall corridor — Khulna/Barisal delta, Bangladesh.
# Replace temporal window with the days right after YOUR cyclone's landfall.
aoi = (89.0, 21.5, 91.0, 23.0)              # (W, S, E, N)
post_window = ("2024-10-25", "2024-10-27")  # first Sentinel-1 passes after Cyclone Dana

# 1. OPERA DSWx-S1 — radar surface water, delivered as Cloud-Optimized GeoTIFFs.
results = earthaccess.search_data(
    short_name="OPERA_L3_DSWX-S1_V1",
    bounding_box=aoi,
    temporal=post_window,
)
print(f"Found {len(results)} DSWx-S1 granules")

# 2. Download the granules and keep only the water-classification layer (B01_WTR).
earthaccess.download(results, local_path="./dswx")
wtr_tiles = sorted(glob.glob("./dswx/*_B01_WTR.tif"))

# 3. Mosaic the UTM tiles, then reproject + clip to the AOI.
tiles = [rioxarray.open_rasterio(t, masked=False).squeeze() for t in wtr_tiles]
da = merge_arrays(tiles).rio.reproject("EPSG:4326").rio.clip_box(*aoi)

# DSWx-S1 WTR class values:
#   0 = not water, 1 = open water, 2 = partial surface water,
#   252 = inundated vegetation, 253 = high backscatter (uncertain),
#   254 = no data (layover/shadow), 255 = fill
flood_mask = da.isin([1, 2, 252])           # open water + partial + inundated vegetation

flooded_px = int(flood_mask.sum())
flooded_km2 = flooded_px * (0.030 * 0.030)  # DSWx-S1 native pixel is ~30 m
print(f"Flooded pixels: {flooded_px:,}{flooded_km2:.1f} km^2")

# 4. GPM IMERG Half-Hourly EARLY run — fast rainfall to explain the flood.
imerg = earthaccess.search_data(
    short_name="GPM_3IMERGHHE",
    bounding_box=aoi,
    temporal=("2024-10-24", "2024-10-26"),  # Cyclone Dana landfall day(s)
)
imerg_ds = xr.open_mfdataset([earthaccess.open([g])[0] for g in imerg],
                             group="Grid")            # IMERG vars live in the /Grid group
storm_total_mm = (imerg_ds["precipitation"] * 0.5).sum("time")  # 0.5 h * mm/hr -> mm
print(f"Max storm rainfall: {float(storm_total_mm.max()):.0f} mm")

# 5. (Optional) CYGNSS L2 — coarse inland flood signal through the storm.
cygnss = earthaccess.search_data(
    short_name="CYGNSS_L2_V3.2",
    bounding_box=aoi,
    temporal=("2024-10-24", "2024-10-26"),
)
# Rising surface_reflectivity over normally-dry land -> standing water during the storm.

# 6. Who's affected — free WorldPop population + geoBoundaries place names (no NASA login)
import requests
from rasterio.windows import from_bounds
import rasterio, geopandas as gpd
from shapely.geometry import Point

meta = requests.get("https://www.worldpop.org/rest/data/pop/wpic1km?iso3=BGD").json()
pop_url = next(f for f in meta["data"][-1]["files"] if f.endswith(".tif"))
open("bgd_pop_1km.tif", "wb").write(requests.get(pop_url).content)   # ~1 MB

with rasterio.open("bgd_pop_1km.tif") as src:
    pop = src.read(1, window=from_bounds(*aoi, transform=src.transform)).astype("float64")
    pop[pop == src.nodata] = np.nan
print(f"People in AOI: {np.nansum(pop):,.0f}")        # verified ~16.3M for this delta box

adm = gpd.read_file(requests.get(
    "https://www.geoboundaries.org/api/current/gbOpen/BGD/ADM2/").json()["gjDownloadURL"])
print("District:", adm[adm.contains(Point(90.0, 22.3))].iloc[0]["shapeName"])   # 'Pirojpur'
# People *in the flood*: resample `pop` onto the flood grid and sum where flood_mask is True.

# 7. List affected places: intersect flood_mask with OSM village/landuse polygons
#    (geopandas overlay) to turn pixels into a named list for responders.

Expected output

  • Flood-extent map: DSWx-S1 water pixels (open water, partial, inundated vegetation) overlaid on a basemap, clipped to the village/farm AOI.
  • Rainfall map: IMERG Early storm-total accumulation (mm) over the landfall window, showing where the water came from.
  • Affected-places list: village names and farm/landuse parcels whose footprints intersect the flood mask, ranked by flooded area.
  • People affected: estimated population in the flooded area (WorldPop), with the flooded districts named (geoBoundaries).
  • Statistics: total flooded area (km²), max storm rainfall (mm), and a count of settlements touched.
  • Optional CYGNSS track: a coarse during-storm reflectivity overlay confirming inland flooding before the first clear Sentinel-1 pass.

Caveats

  • DSWx-S1 maps water presence, not depth — a flagged pixel says “wet,” not “how deep.”
  • Snapshots, not a time series — Sentinel-1 revisit (~6–12 days) means you see the flood when a pass happens, possibly missing the peak.
  • Compare to a pre-storm baseline — perennial rivers, ponds, and tidal flats appear as “water”; difference against a dry-season DSWx scene to isolate new flooding.
  • Urban and densely-vegetated areas are unreliable — DSWx flags high-backscatter and layover/shadow pixels; treat them as “unknown,” not “dry.”
  • CYGNSS is coarse (~25 km) — it’s a regional “is it flooding” cue, not a parcel-level map.

Cross-DAAC composition

ASF / PO.DAAC (OPERA DSWx-S1) + GES DISC (GPM IMERG Early) + PO.DAAC (CYGNSS L2) — one Earthdata Login across all three.

Sources

Datasets used

📚 Problem Finder KB

1 matching entry in the Knowledge Base:

§14 Glossary
OPERA
Observational Products for End-Users from Remote-sensing Analysis (NASA JPL) — incl. the **DISP-S1** surface-displacement (InSAR) product suite