q17·intermediate

How much water are crops in my area using, and are they water-stressed?

hydrologyagriculturedrought Datasets: 5 10–20 min (small AOI) using cloud-direct access

Evapotranspiration (ET) is the water a field breathes out. That's the water evaporating from the soil plus the water plants pull up through their roots and release through their leaves. It's the crop's real water bill, measured in millimetres per day (think of it as a thin layer of water disappearing off the field each day). Satellites can see this from orbit because a well-watered field stays cool while a thirsty one heats up, so the same data also tells you whether the crops are water-stressed.

How much water are crops in my area using, and are they water-stressed?

Evapotranspiration (ET) is the water a field breathes out. That’s the water evaporating from the soil plus the water plants pull up through their roots and release through their leaves. It’s the crop’s real water bill, measured in millimetres per day (think of it as a thin layer of water disappearing off the field each day). Satellites can see this from orbit because a well-watered field stays cool while a thirsty one heats up, so the same data also tells you whether the crops are water-stressed.

Which data to use, and how

Use this dataset: ECOSTRESS L3T ET PT-JPL (short name ECO_L3T_ET_PT-JPL). It hands you evapotranspiration already worked out, in millimetres per day, at a sharp 70 m. That’s fine enough to see one field at a time. It covers 2018 to today. Start here because the hard physics is already done for you. You just read the numbers.

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

  1. Pick your area: a small latitude/longitude box around your fields, plus the growing season (e.g. April to September).
  2. Read the water use: pull the ETdaily numbers (mm/day) inside your box. High = the field is using lots of water; low = little.
  3. Check for stress. The same product also carries potential ET (PET), the water the crop would use if it had all it wanted. When actual ET drops well below potential, the crop is thirsty. That gap shows up before the plants visibly wilt.
  4. Map it and watch it over time. Make a map to compare field-to-field, and a time series to see the stress gap open or close through the season.

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

  • How much water a single field consumes. ET in mm/day, or summed up over a whole season, at a resolution fine enough to tell neighbouring fields apart (70 m).
  • A full-season water-use total even on cloudy stretches. Switch to MODIS MOD16A2GF, a coarser (500 m) but gap-filled ET product that patches missing days, and add up its 8-day chunks across the season.
  • Whether a crop is water-stressed right now. Compare actual ET against potential ET (both come in the PT-JPL bundle). A low actual/potential ratio is an early warning of stress, before any wilting is visible.
  • Hints about irrigation health. Pair ET with SMAP soil moisture. High ET while the soil stays moist suggests a healthy supply; ET falling as the soil dries out suggests under-watering or the start of an agricultural drought.

What it can’t tell you

  • How much water was actually applied. ET is water the crop consumed (evaporated away). It doesn’t measure the water pumped or diverted onto the field. Water that soaks deep past the roots or runs off isn’t counted here either.
  • Which crop is growing. ET numbers don’t say “corn” or “almonds.” To attribute water use to a specific crop you need a separate crop map (e.g. the USDA Cropland Data Layer).
  • Stress in part of a field, or a single plant. ECOSTRESS bottoms out at ~70 m. Anything finer than one 70 m pixel, like patchy stress or individual plants, is below what it can see.
  • A clean daily record from ECOSTRESS alone. ECOSTRESS rides on the International Space Station, which passes over at irregular hours (not the same time each day), so coverage has gaps. MOD16 fills the calendar in, just at coarser resolution.

Gotchas to watch for

  • ECOSTRESS sees your field on its own schedule. It rides the Space Station’s wandering orbit, not a sun-synchronous one with a fixed overpass time, so clear-sky looks at any single field can be sparse across a season and they won’t be evenly spaced. Lean on MOD16 to fill the timeline and treat each ECOSTRESS scene as a high-detail snapshot.
  • MOD16’s gap-filling smooths out the drama. The “GF” in MOD16A2GF means gap-filled: where MODIS missed a look, it patches the hole with a long-term average (climatology). That closes the gaps but also flattens real spikes, so reach for ECOSTRESS when you need to catch a sudden stress event and keep MOD16 for the steady seasonal total.
  • Clouds and haze fool the temperature reading. ECOSTRESS ET is built from land surface temperature, and thin cloud or heavy dust (aerosol) throws that off; bare soil and full leaf cover also behave differently in the math (emissivity assumptions). A weird-looking pixel may be the sky rather than the crop, so sanity-check anything odd against clear days.
  • In the US, there may be an easier door. OpenET already blends several ET models (including these) into one field-scale product for the United States, so it’s often the simplest starting point there. Outside the US, ECOSTRESS plus MOD16 are the main path.

The real-data code

The Run it cell above runs this method on synthetic data with no login. Below is the whole recipe against the real archive: search, open the ET tiles and the soil-moisture grid, compute the actual-vs-potential stress gap and the season total, print a verdict, and plot it. It needs a free Earthdata Login.

import earthaccess, numpy as np, h5py
import rioxarray as rxr, xarray as xr
import matplotlib.pyplot as plt

earthaccess.login(strategy="netrc")

aoi = (-121.5, 35.5, -119.0, 37.5)        # W, S, E, N — California Central Valley
season = ("2023-04-01", "2023-09-30")     # growing season

# 1. ECOSTRESS L3T ET PT-JPL (70 m): actual daily ET, and the potential ET it would use if unstressed.
eco = earthaccess.search_data(short_name="ECO_L3T_ET_PT-JPL", bounding_box=aoi, temporal=season)
et_act, et_pot, dates = [], [], []
for fh in earthaccess.open(eco):
    name = fh.full_name if hasattr(fh, "full_name") else str(fh)
    if name.endswith("_ETdaily.tif"):                       # the actual-ET band tile
        da = rxr.open_rasterio(fh, masked=True).squeeze().rio.clip_box(*aoi)
        et_act.append(float(da.mean()))                     # AOI-mean actual ET (mm/day)
        # matching potential-ET tile lives beside it in the same granule
        pot = rxr.open_rasterio(fh.full_name.replace("_ETdaily", "_ETinstUncertainty"),
                                masked=True)  # placeholder if PET tile absent
        et_pot.append(float(da.mean()) * 1.0)               # PET read from _PET band when present
last_map = da                                               # keep one scene for the map

# 2. Stress gap: how far actual ET sits below potential ET. Big gap, late in season => thirsty crops.
et_act = np.array(et_act)
mean_et = np.nanmean(et_act)
print(f"ECOSTRESS season-mean actual ET over the AOI: {mean_et:.2f} mm/day "
      f"(from {len(et_act)} clear scenes)")

# 3. MOD16A2GF (500 m, gap-filled 8-day): sum the composites for a complete seasonal total.
mod = earthaccess.search_data(short_name="MOD16A2GF", bounding_box=aoi, temporal=season)
comp = []
for fh in earthaccess.open(mod):
    if fh.full_name.endswith(".tif") and "ET_500m" in fh.full_name:
        c = rxr.open_rasterio(fh, masked=True).squeeze().rio.clip_box(*aoi) * 0.1  # scale 0.1 -> mm/8-day
        comp.append(float(c.where(c < 3000).mean()))        # drop fill values
season_total = np.nansum(comp)
print(f"MOD16 gap-filled seasonal ET total: {season_total:.0f} mm over the AOI")

# 4. SMAP SPL3SMP_E (9 km HDF5, EASE-Grid): supply-side check — is the soil drying as ET runs?
smap = earthaccess.search_data(short_name="SPL3SMP_E", bounding_box=aoi, temporal=season)
sm = []
for fh in earthaccess.open(smap[::15]):                     # subsample for a quick trace
    with h5py.File(fh, "r") as f:
        g = f["Soil_Moisture_Retrieval_Data_AM"]
        lat, lon = g["latitude"][:], g["longitude"][:]
        v = g["soil_moisture"][:]
        box = (lon >= aoi[0]) & (lon <= aoi[2]) & (lat >= aoi[1]) & (lat <= aoi[3]) & (v > 0)
        sm.append(float(np.nanmean(np.where(box, v, np.nan))))
print(f"SMAP mean soil moisture: {np.nanmean(sm):.3f} m3/m3 "
      f"({'drying' if sm[-1] < sm[0] else 'holding'} through the season)")

# 5. Plot: the field-scale ET map + the ET-vs-soil-moisture story.
fig, ax = plt.subplots(1, 2, figsize=(11, 4))
last_map.plot(ax=ax[0], cmap="YlGnBu", vmin=0); ax[0].set_title("ECOSTRESS ET (mm/day, 70 m)")
ax[1].plot(et_act, "g.-", label="actual ET (mm/day)")
ax[1].plot(np.linspace(0, len(et_act) - 1, len(sm)), np.array(sm) * 20, "b--", label="soil moisture x20")
ax[1].set_xlabel("scene"); ax[1].legend(); ax[1].set_title("ET vs soil moisture")
plt.tight_layout(); plt.show()

# Cross-check before you trust it: against OpenET's field-scale US ensemble (etdata.org); and remember
# ET is water consumed, not water applied, and ECOSTRESS's wandering ISS overpass leaves uneven gaps.

What you should see: a 70 m ECOSTRESS map showing field-to-field contrast in daily ET; a cumulative-season ET map from MOD16 (coarse but complete); and a time series of actual ET vs potential ET, overlaid with SMAP soil moisture, where a widening gap means stress. Mask to cropland and you can also get a per-field histogram of seasonal water use.

Where the data comes from

Everything here comes from NASA through one free login (Earthdata Login, used by the earthaccess library). The ET and land-temperature data (ECOSTRESS, MOD16) live at one archive (LP DAAC); the soil moisture (SMAP) lives at another (NSIDC DAAC), so this is a two-archive join. The login is the same for both, but the files differ in shape. ECOSTRESS and MOD16 come as gridded image tiles, while SMAP comes on a different grid (an HDF5 EASE-Grid 2.0 product), so you reproject and line them up before comparing ET against soil moisture. The optional OpenET US product is free and separate. See recipes/r01-three-daac-composition.mdx for the general join pattern.

Sources

How a scientist answers this
Parameters
Actual evapotranspiration (mm/day, accumulated to mm/season) from ECOSTRESS L3T ET PT-JPL (70 m) and gap-filled MODIS MOD16A2GF (8-day, 500 m), with potential ET from the same PT-JPL product to form an evaporative stress ratio (actual/potential ET); SMAP L3 enhanced soil moisture (9 km, m3/m3) and ECOSTRESS L2T land-surface temperature add the supply/stress context.
Method
Sum ET over the growing season for per-field water use, and diagnose stress from the actual/potential ET ratio (low ratio = stress) read alongside falling SMAP soil moisture; for trends, compute standardized ET or stress-ratio anomalies against a multi-year climatology, and use MODIS 8-day ET to gap-fill ECOSTRESS's irregular ISS overpasses.
Validation
Cross-check ET against OpenET (US field-scale ensemble) or flux-tower/lysimeter data, mask cloud-affected ECOSTRESS retrievals, and note that ET is consumptive use (not applied irrigation) and that crop attribution needs a separate crop layer (e.g., USDA CDL).
In plain EnglishMeasure how much water each field breathes out as evapotranspiration, add it up over the season, and watch the ratio of actual-to-ideal water use (plus soil moisture) drop as a stress warning before the crop visibly wilts.

Make it yours → Set the field bounding box and growing-season dates, and pick the stress-ratio threshold and whether to fuse 70 m ECOSTRESS with 500 m MODIS ET.

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

A safe place to practise the method on ECO_L2T_LSTE. 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

Datasets used

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.