q52·intermediate

Where did the floodwater spread — even under clouds?

hydrospherehazards Datasets: 4 15–40 min
Real events · NASA Disasters / VEDA

Analysis-ready products for actual events that this question maps to — open each in the catalog, or browse them on the NASA Disasters Portal.

A flood map is just a picture of which patches of ground are covered in water and which are still dry. The hard part during a real flood is that the sky is usually full of storm clouds. Ordinary camera-style satellites can't see through cloud, so they photograph the cloud tops instead of the water below. The trick is radar, which works like the way a bat "sees" with sound. It sends out its own signal and listens for the echo, so it works straight through cloud, rain, and darkness.

Where did the floodwater spread — even under clouds?

A flood map is just a picture of which patches of ground are covered in water and which are still dry. The hard part during a real flood is that the sky is usually full of storm clouds. Ordinary camera-style satellites can’t see through cloud, so they photograph the cloud tops instead of the water below. The trick is radar, which works like the way a bat “sees” with sound. It sends out its own signal and listens for the echo, so it works straight through cloud, rain, and darkness.

Which data to use, and how

Use this dataset: OPERA DSWx-S1 (short name OPERA_L3_DSWX-S1_V1). DSWx stands for Dynamic Surface Water extent. It’s a ready-made water / no-water map that NASA already built for you from radar. You don’t have to interpret raw radar yourself; each pixel is already labelled “water” or “not water.” That makes it the easiest place to start.

(Under the hood DSWx-S1 is made from Sentinel-1 SAR, the actual radar instrument. You can drop down to that raw radar later if you want full control, but you don’t need to for a first map.)

Then do four steps (the runnable code further down does all of this; this is just the idea):

  1. Pick your area and two dates. A small latitude/longitude box around the flooded region, plus one date before the flood and one after it.
  2. Grab the two water maps. Download the DSWx “water / no-water” map for the before date and for the after date.
  3. Subtract them. Find every pixel that was dry before but wet after. That difference is the newly flooded land, the part that actually matters for an emergency.
  4. Clip and overlay. Trim the result to your box, and optionally lay it over maps of where people and buildings are, to see who was affected.

That’s the whole method. Below, “How a scientist answers this” names the exact tools, and the Run it cell does it live on synthetic data so you can see each step work.

What you can find out

  • The flooded footprint, straight through cloud. Radar makes its own signal and passes through clouds and darkness, so it works at the exact moment a storm hides everything from normal satellites. Calm floodwater is smooth, so it bounces the radar away from the sensor and shows up dark. DSWx turns that into a clean water map.
  • The newly flooded land. Subtracting a before map from an after map isolates water that wasn’t there before (rivers and lakes that are always wet get cancelled out).
  • What drove the flood. GPM IMERG gives the rainfall totals behind the event, so you can connect “this much rain fell” to “this much land flooded.”

What it can’t tell you

  • How deep the water is. A flood map tells you where water is, not how many feet deep it is. Depth needs a separate 3-D model of the ground’s shape (a DEM, or digital elevation model) plus extra assumptions. Extent and depth are two different problems.
  • Flooding hidden under thick trees or packed city blocks. Buildings and tree canopies scatter the radar in confusing ways, so water under them can be missed. The fix is to fill those gaps with an optical (camera-style) satellite like Sentinel-2 once the skies clear.
  • Minute-by-minute, everywhere. Each satellite only flies over a given spot every few days, so you get snapshots, not a live video. You may catch the flood near its peak or hours later, and you can’t count on perfect timing.

Gotchas to watch for

  • Smooth ≠ only water. Radar shows calm water as dark because it’s smooth, but other flat surfaces (dry sand, salt flats, very smooth roads, airport tarmac) can look dark too, which leaves you with false “flood” pixels. The way out is to use the pre-event map as your baseline: anything already dark before the storm isn’t new floodwater.
  • Wind roughs up the water. A strong wind can ripple the surface of floodwater so it scatters radar back and reads bright (dry) instead of dark, and real flooding gets under-counted on a windy day. Cross-check with the rainfall data and, if possible, grab a second pass on a calmer day.
  • The two dates must line up. Subtracting a before map from an after map only works if they cover the same ground in the same way (same satellite track, same grid); misaligned maps invent fake “change” along the edges. DSWx products come already snapped to a common grid, which is another reason to start with them rather than raw radar.
  • A snapshot can miss the peak. Revisits are only every few days, so your “after” image might be taken while the water is already draining and you under-map the worst of it. Pull every available pass during the event window and keep the wettest one.

The real-data code

The Run it cell above runs the method on synthetic data (no login). Below is the whole recipe against the real archive: search the before/after water maps, open them, subtract to isolate the newly flooded land, add the rainfall that drove it, print the footprint, and plot. It needs a free Earthdata Login.

import earthaccess, numpy as np, xarray as xr
import rasterio
from rasterio.warp import reproject, Resampling
import matplotlib.pyplot as plt

earthaccess.login(strategy="netrc")

aoi = (-99.3, 29.9, -98.9, 30.2)   # flooded area as (W, S, E, N) — here, Kerrville, Texas

# 1. OPERA DSWx-S1: ready-made radar water maps. Grab a PRE- and a POST-event scene.
pre = earthaccess.search_data(short_name="OPERA_L3_DSWX-S1_V1", bounding_box=aoi,
                              temporal=("2025-06-20", "2025-06-30"))
post = earthaccess.search_data(short_name="OPERA_L3_DSWX-S1_V1", bounding_box=aoi,
                               temporal=("2025-07-05", "2025-07-10"))

# 2. Open the WTR (water classification) GeoTIFF layer from each scene with rasterio.
#    DSWx WTR codes: 1 = open water, 2 = partial-surface water; 0/dry, 252-255 are fill/cloud/no-data.
def open_water(granules):
    fh = earthaccess.open([granules[0]])[0]   # first scene's file handle for this date
    src = rasterio.open(fh)
    return src, src.read(1)                    # WTR is the first band of the DSWx GeoTIFF

src_pre, wtr_pre = open_water(pre)
src_post, wtr_post = open_water(post)

# Put the post scene onto the pre scene's grid so the two dates line up exactly.
wtr_post_on_pre = np.empty(wtr_pre.shape, dtype=wtr_post.dtype)
reproject(wtr_post, wtr_post_on_pre,
          src_transform=src_post.transform, src_crs=src_post.crs,
          dst_transform=src_pre.transform, dst_crs=src_pre.crs,
          resampling=Resampling.nearest)

# 3. Subtract: dry BEFORE (code 0) AND water AFTER (code 1 or 2) = newly flooded land.
water_pre = np.isin(wtr_pre, [1, 2])
water_post = np.isin(wtr_post_on_pre, [1, 2])
valid = (wtr_pre < 252) & (wtr_post_on_pre < 252)        # drop fill / cloud / no-data
new_flood = (~water_pre) & water_post & valid

px_area_km2 = abs(src_pre.transform.a * src_pre.transform.e) / 1e6   # m² per pixel → km²
new_flood_km2 = new_flood.sum() * px_area_km2

# 4. What drove it? Sum GPM IMERG rainfall over the storm window.
rain_g = earthaccess.search_data(short_name="GPM_3IMERGHH", bounding_box=aoi,
                                 temporal=("2025-07-01", "2025-07-05"))
rain_total = 0.0
for fh in earthaccess.open(rain_g):
    ds = xr.open_dataset(fh, group="Grid")
    r = ds["precipitation"].sel(lon=slice(aoi[0], aoi[2]), lat=slice(aoi[1], aoi[3]))
    rain_total += float(r.mean()) * 0.5      # mm/hr → mm over each half-hour granule
ds.close()

# 5. Verdict + plot.
print(f"Newly flooded land: {new_flood_km2:.1f} km^2, "
      f"driven by ~{rain_total:.0f} mm of rain over the event window")

plt.imshow(water_pre, cmap="Blues", alpha=0.4)
plt.imshow(np.ma.masked_where(~new_flood, new_flood), cmap="autumn")
plt.title(f"New flood (red) over pre-event water — {new_flood_km2:.0f} km²")
plt.tight_layout(); plt.show()

# Before you trust it: confirm the dark "water" was actually dry pre-event (the pre map is
# your baseline), and fill canopy/urban gaps with clear-sky Sentinel-2 (see the gotchas above).

Where the data comes from

Everything comes from NASA through one free login (Earthdata Login). The OPERA DSWx water maps are derived by NASA from the European Sentinel-1 radar satellite, then served from the NASA archive ready to use. GPM IMERG rainfall comes from the global rain-measuring mission. This question supports the Respond phase of the NASA Disasters program, the part of the response where you need to know where the water is fast.

Sources

How a scientist answers this
Parameters
OPERA DSWx-S1 / DSWx-HLS analysis-ready surface-water extent (water / no-water classes); Sentinel-1 C-band SAR backscatter (σ0, dB) that penetrates cloud day or night; Sentinel-2 SWIR false-color where skies clear; GPM IMERG rainfall totals (mm) for the driver. Calm open water reads dark in SAR (low backscatter).
Method
Take a pre-event and post-event DSWx (or threshold radiometrically-terrain-corrected Sentinel-1 backscatter below a low-σ0 cut), difference them to isolate newly flooded pixels, clip to the AOI, and overlay population/buildings; IMERG gives the rainfall context.
Validation
Cross-check the SAR water mask against optical Sentinel-2 SWIR on the first clear day, and flag known SAR limits — wind-roughened water, dense canopy, and urban layover/scatter cause misses; extent is not depth (that needs a DEM).
In plain EnglishRadar sees through clouds and reads calm floodwater as dark, so comparing a before-flood and after-flood water map shows exactly where new water spread.

Make it yours → Draw your AOI and set the pre-event and post-event dates, then overlay your own population or buildings layer to see who's affected.

🧪 Virtual Mock Lab stand-in data · runs in your browser · no login

A safe place to practise the method on OPERA_L3_DSWX-S1_V1. The code is the real earthaccess workflow, but we feed it stand-in data shaped like the real product — so you can run it, change the numbers, and break it without an account. When you want the real data, use the recipe under “The real-data code” above, or download the notebook below.

editable · runs in your browser
Recipe ready · not yet run The recipe and the Virtual Mock Lab above are ready to use. We haven't yet run this question end-to-end on real data, so it has no verified answer yet — only the questions we've actually computed carry one. That's the honest line between a method and a result.