Is a flash drought drying out my region's soil before anyone notices?
Draw a rectangle, then check which collections cover it. Most NASA data is global, so a big box matches a lot.
-98, 38 → -94, 42 (US Central Plains (Kansas/Nebraska))A flash drought is a drought in fast-forward. Weeks of heat and wind pull water out of the ground faster than rain can replace it, and a green field can turn brown before the official drought maps catch up. Soil moisture is how much water is sitting in the soil. NASA's SMAP satellite measures it from orbit, so you can watch the top layer of soil dry out across your whole region, day by day, even where there isn't a single ground sensor.
Is a flash drought drying out my region’s soil before anyone notices?
A flash drought is a drought in fast-forward. Weeks of heat and wind pull water out of the ground faster than rain can replace it, and a green field can turn brown before the official drought maps catch up. Soil moisture is how much water is sitting in the soil. NASA’s SMAP satellite measures it from orbit, so you can watch the top layer of soil dry out across your whole region, day by day, even where there isn’t a single ground sensor.
Which data to use, and how
Use this dataset: SMAP enhanced soil moisture (short name
SPL3SMP_E). It gives you one soil-moisture value per day for every 9 km square on Earth, going
back to 2015. The number is volumetric, in cubic metres of water per cubic metre of soil
(m³/m³), so a value of 0.23 means 23% of the soil volume is water. The satellite only senses the
top ~5 cm of soil.
Then do four steps. The runnable code further down does all of this; this is just the idea.
- Pick your region as a small latitude/longitude box, and an early date before the suspected drying.
- Average the soil moisture inside your box on that early date, throwing out any “no-data”
pixels (the file marks them with the value
-9999). That gives you one number for “how wet was the soil then.” - Pick a later date, a few weeks on, and do the same averaging again. One number for “how wet is the soil now.”
- Compare the two numbers. A clear drop means the surface soil dried out fast. That falling line is the signal you’d watch to catch a flash drought early.
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.
Verified locally. For the US Central Plains box (38–42 °N, 98–94 °W), the SMAP soil_moisture
field averaged 0.235 m³/m³ on 1 Jun 2023 and fell to 0.220 m³/m³ by 5 Aug 2023. That’s a
real, measurable drying of the surface soil over a single summer, read straight from the data files.
It’s the signal, not yet a verdict, but it’s exactly what you’d watch.
What you can find out
- How wet the top ~5 cm of soil is right now, and on any day back to 2015, straight from SMAP’s
soil_moisturefield. - Whether soil is drying faster than usual. Compare two dates weeks apart, or stack a whole season of days to see the slope of the decline.
- Where the drying is concentrated. The 9 km grid is fine enough to show which parts of a region are losing water fastest, not just one regional average.
- How drying lines up with stressed plants. Pair with MOD13 NDVI, a greenness index (NDVI = how green/healthy the vegetation looks), to see whether crops and grass are starting to respond.
- How drying lines up with the atmosphere’s “thirst”. Pair with ECOSTRESS or MOD16 evapotranspiration (the water evaporating off the land and breathing out of plants), which a flash drought speeds up.
What it can’t tell you
- Whether it’s officially a “drought.” That’s a human-judged label (e.g., the US Drought Monitor) built from many inputs. SMAP gives you one physical measurement, wetness, not the official designation.
- Water deeper down. SMAP senses only the top few centimetres. Crops can still drink from moisture below what the satellite sees, so dry surface soil doesn’t automatically mean a dead crop.
- What caused the drying. Falling soil moisture could be heat, wind, missing rain, or just irrigation being switched off. The data shows the drying happened, not why.
- What happens next. These are observations, not a forecast. Predicting whether the drought deepens needs weather models layered on top.
- Single-field detail. At 9 km, one pixel blends many fields, roads, and ponds together. For one farm you’d need higher-resolution data or a probe in the ground.
- Frozen or thickly forested ground. The microwave measurement gets unreliable under snow, ice, open water, or dense tree canopy, so always respect the data’s quality flags there.
Gotchas to watch for
- Throw out the “no-data” value. Pixels with no valid reading are stored as
-9999, not as blank. If you average without removing them, your result is garbage (a huge negative number). The fix: drop every pixel equal to-9999before you average. The code below does this automatically. - AM vs PM passes. SMAP measures each spot twice a day. Most studies use the morning (“AM”,
group
Soil_Moisture_Retrieval_Data_AM) pass, because the soil and air are closest to the same temperature then, which makes the retrieval cleaner. Stick with AM unless you have a reason not to. - Compare like with like. Always average over the same box on both dates, and prefer dates in the same season so you’re seeing real drying, not just summer-vs-winter differences.
- Mind the quality flags under snow/water/forest. Where the surface is frozen, flooded, or heavily wooded, the measurement degrades. SMAP ships quality flags that mark these pixels. Check them before trusting a value in those areas.
The real-data code
The Run it cell above runs this method on synthetic data with no login. The code below is the
whole recipe against the real NASA archive (search → open → average → compare → plot). It just needs
a free Earthdata Login (the single free account that unlocks NASA’s data). It reads SMAP enhanced
soil moisture (SPL3SMP_E) directly from the cloud, drops the -9999 fill
value, averages two dates weeks apart, and maps where the surface dried.
import os, re, warnings, earthaccess, h5py, numpy as np
import matplotlib.pyplot as plt
warnings.filterwarnings("ignore") # quiet earthaccess FutureWarnings
# load Earthdata credentials from a .env file (a password can break the shell, so we don't `source` it)
for line in open(".env"):
m = re.match(r'\s*(?:export\s+)?([A-Z0-9_]+)\s*=\s*(.*)\s*$', line)
if m: os.environ.setdefault(m.group(1), m.group(2).strip().strip('"').strip("'"))
earthaccess.login(strategy="environment") # free Earthdata Login
W, S, E, N = -98, 38, -94, 42 # US Central Plains (Kansas/Nebraska)
FILL = -9999.0
# 1. Open one SMAP enhanced granule for a date window and pull the AM-pass arrays.
def open_sm(date0, date1):
g = earthaccess.search_data(short_name="SPL3SMP_E",
temporal=(date0, date1),
bounding_box=(W, S, E, N))
with h5py.File(earthaccess.open(g[:1])[0], "r") as h5:
grp = h5["Soil_Moisture_Retrieval_Data_AM"] # morning pass: cleaner retrieval
sm = np.array(grp["soil_moisture"][:], dtype="float64")
lat = np.array(grp["latitude"][:], dtype="float64")
lon = np.array(grp["longitude"][:], dtype="float64")
return sm, lat, lon
# 2. Mask to our box and drop the -9999 "no-data" pixels, then area-average.
def mean_sm(sm, lat, lon):
aoi = (lat >= S) & (lat <= N) & (lon >= W) & (lon <= E) & (lat != FILL)
valid = (sm != FILL) & np.isfinite(sm)
return sm[aoi & valid]
sm0, lat0, lon0 = open_sm("2023-06-01", "2023-06-10") # early: before the drying
sm1, lat1, lon1 = open_sm("2023-08-05", "2023-08-15") # late: a few weeks on
early = float(mean_sm(sm0, lat0, lon0).mean())
late = float(mean_sm(sm1, lat1, lon1).mean())
# 3. Compare the two regional averages — a clear drop is the flash-drought signal.
drop = early - late
verdict = "FLASH-DROUGHT SIGNAL: surface drying fast" if drop > 0.01 else "no rapid drying"
print(f"surface soil moisture {early:.3f} -> {late:.3f} m3/m3 "
f"(down {drop:+.3f} over ~9 wk) => {verdict}")
# 4. Map where the soil dried: per-pixel change on the 9 km grid, masked to the box.
aoi = (lat0 >= S) & (lat0 <= N) & (lon0 >= W) & (lon0 <= E) & (lat0 != FILL)
good = aoi & (sm0 != FILL) & (sm1 != FILL) & np.isfinite(sm0) & np.isfinite(sm1)
delta = np.where(good, sm1 - sm0, np.nan)
plt.scatter(lon0[good], lat0[good], c=delta[good], cmap="BrBG", vmin=-0.1, vmax=0.1, s=40)
plt.colorbar(label="ΔSM Jun→Aug (m³/m³)"); plt.xlabel("lon"); plt.ylabel("lat")
plt.title("SMAP surface soil-moisture change"); plt.tight_layout(); plt.show()
# Before you trust it: cross-check the drying date against the US Drought Monitor, and remember
# SMAP senses only the top ~5 cm — deeper moisture (and the official "drought" label) can differ.
Where the data comes from
All of it is NASA data, reached through one free login (Earthdata Login). SMAP soil moisture
(SPL3SMP_E) is archived at NSIDC, the snow-and-ice data center, and stored as HDF5 files on a
global grid. The optional companions, vegetation greenness (MOD13 NDVI) and evapotranspiration
(ECOSTRESS / MOD16), come from NASA’s land-data archives under the same single login, so you can
line up “soil drying,” “plants stressing,” and “atmosphere pulling water out” without juggling
accounts.
Sources
- SMAP enhanced L3 soil moisture (
SPL3SMP_E): https://nsidc.org/data/spl3smp_e/versions/5 - SMAP mission: https://smap.jpl.nasa.gov/
- US Drought Monitor (the official “drought” label): https://droughtmonitor.unl.edu/
Make it yours → Edit the AOI box, the date window, the climatology baseline, and the percentile/anomaly threshold in the notebook.
A safe place to practise the method on SPL3SMP_E. 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.