q19·intermediate

Is a volcano degassing or erupting — can I track its SO₂ plume?

atmosphereair-qualitydisaster-response Datasets: 5 20–45 min

SO₂ (sulfur dioxide) is a sharp, acrid gas that volcanoes release. A volcano that is just degassing vents gas quietly, without throwing out lava or ash. An erupting one releases SO₂ in huge bursts. Satellites can see this gas from orbit. So even with nobody on the ground, you can track how much a volcano is emitting, which way the wind carries it, and whether you're looking at a quiet simmer or a violent eruption.

Is a volcano degassing or erupting — can I track its SO₂ plume?

SO₂ (sulfur dioxide) is a sharp, acrid gas that volcanoes release. A volcano that is just degassing vents gas quietly, without throwing out lava or ash. An erupting one releases SO₂ in huge bursts. Satellites can see this gas from orbit. So even with nobody on the ground, you can track how much a volcano is emitting, which way the wind carries it, and whether you’re looking at a quiet simmer or a violent eruption.

Which data to use, and how

Use this dataset: TROPOMI SO₂ (short name S5P_L2__SO2____HiR). It’s the sharpest of the SO₂ satellites (each pixel is roughly 5.5 × 3.5 km), so it gives you the cleanest picture of a plume drifting off a vent, and it’s the easiest one to start with. There are coarser, longer-running alternatives, OMI SO₂ (OMSO2) and OMPS SO₂ (OMPS_NPP_NMSO2_PCA_L2). Reach for those later, as cross-checks or for older dates.

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

  1. Pick your volcano: a small latitude/longitude box around the vent — and the days you care about.
  2. Grab the SO₂ for each overpass. Every time the satellite flies over, it measures how much SO₂ sits in the air column above your box. Keep only the trustworthy pixels (a built-in quality score called qa_value, where you keep values above 0.5).
  3. Make a daily number and a map. For each day, record the average and the peak SO₂ over your box. A rising peak means the volcano is getting more active. For the strongest day, draw the SO₂ as a map.
  4. Add the wind and the heat. Overlay MERRA-2 (M2I3NPASM) wind arrows to see which way the plume blows, and VIIRS thermal anomalies (VNP14), hot-spot pixels, to check whether the vent itself is glowing hot.

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

  • Whether SO₂ is there at all above the normal background over the vent on a given day.
  • Which way the plume is going and how far, by laying the SO₂ map over the MERRA-2 winds.
  • Simmering vs erupting. Quiet degassing shows a modest patch of gas pinned near the vent; an eruption shows a big, fast-spreading, sometimes high-flying plume.
  • Whether the vent is hot, by adding the VIIRS/MODIS thermal-anomaly (heat-detector) pixels right at the summit.
  • A day-by-day series of SO₂ over your box to catch a volcano ramping up or a fresh bout of unrest.

What it can’t tell you

  • Round-the-clock watch. These satellites fly over roughly once a day in daylight, so you get snapshots, not surveillance. An eruption that starts and finishes between two passes can be missed entirely.
  • An exact emission rate (tonnes per day). Getting a real number means a flux calculation (SO₂ amount × wind × a line across the plume) plus a guess at how high the plume sits, and the answer shifts depending on which height assumption you pick.
  • A forecast of when it will erupt. SO₂ by itself doesn’t predict onset. You’d pair it with ground measurements (ground swelling from InSAR/GPS, earthquakes) and the local volcano observatory.
  • Exactly how high the plume is. The satellite assumes a layer height. Pinning down the true altitude (and separating ash from gas) needs a laser sounder (lidar, e.g. the legacy CALIPSO) or aircraft.
  • How much ash is in the air. SO₂ is just the gas. Volcanic ash is a separate measurement (a different VIIRS/MODIS retrieval), and ash is what actually grounds airplanes.

Gotchas to watch for

  • The answer depends on how high you assume the plume sits. TROPOMI/OMI/OMPS each publish several SO₂ products tied to different assumed plume altitudes (near the ground vs lower / mid / upper atmosphere). Pick the one that matches your situation, or you’ll misread the amount. The same gas read as “low” vs “high” gives very different totals.
  • Faint plumes are noisy. Weak degassing sits right at the edge of what the satellite can detect, so always apply the quality filter (the qa_value mask for TROPOMI, the quality flags for OMI/OMPS). Keep only the good pixels and the noise drops away.
  • One daytime look per day. Eruptions are bursty, so even a clear overpass can miss the peak moment. Cross-check the local volcano observatory (for Kīlauea, the USGS Hawaiian Volcano Observatory, HVO) and near-real-time feeds.
  • Gas is not ash. For aviation safety you also need an ash measurement. These gas products will never flag an ash cloud on their own.
  • This page is for analysis, not flight ops. Volcanic SO₂ and ash drift into flight paths, but the people who actually warn pilots are the Volcanic Ash Advisory Centers (VAACs) and the Support to Aviation Control Service (SACS), which ingest this data in near-real-time. Use this page to learn and analyze, not to route aircraft.

The real-data code

The Run it cell above runs the method on synthetic data with no login. Below is the whole recipe against the real archive: search, open each overpass, keep good pixels, build the daily mean/peak series, map the strongest day with wind arrows, and print whether it’s degassing or erupting. It needs a free Earthdata Login.

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

earthaccess.login(strategy="netrc")

aoi = (-155.4, 19.3, -155.2, 19.5)   # W, S, E, N — Kīlauea summit, Halemaʻumaʻu
window = ("2024-06-01", "2024-06-30")

# 1. Search the primary product: TROPOMI SO2 high-res (one swath per daytime overpass).
s5p = earthaccess.search_data(short_name="S5P_L2__SO2____HiR",
                              bounding_box=aoi, temporal=window)

# 2. Open each granule cloud-direct, read the SO2 column, keep trustworthy pixels
#    (qa_value > 0.5), clip to the AOI, and record per-overpass mean + peak.
days, means, peaks, scenes = [], [], [], []
for fh in earthaccess.open(s5p):
    ds = xr.open_dataset(fh, group="PRODUCT")
    so2 = ds["sulfurdioxide_total_vertical_column"].where(ds["qa_value"] > 0.5)
    inbox = ((ds.longitude >= aoi[0]) & (ds.longitude <= aoi[2])
             & (ds.latitude >= aoi[1]) & (ds.latitude <= aoi[3]))
    clip = so2.where(inbox)
    if np.isfinite(clip).sum() == 0:
        continue
    days.append(np.datetime64(ds.time.values[0], "D"))
    means.append(float(clip.mean(skipna=True)))
    peaks.append(float(clip.max(skipna=True)))
    scenes.append((ds.longitude.values, ds.latitude.values, so2.values))

order = np.argsort(days)
days = np.array(days)[order]; means = np.array(means)[order]; peaks = np.array(peaks)[order]

# 3. Verdict: background is the quietest quartile of daily peaks; "erupting" if the worst day
#    spikes well above it (>3x), else steady "degassing". mol/m2 throughout.
bg = np.nanpercentile(peaks, 25)
worst = int(np.nanargmax(peaks))
ratio = peaks[worst] / bg if bg > 0 else np.inf
state = "ERUPTING / strong unrest" if ratio > 3 else "quiet degassing"
print(f"{state}: peak SO2 {peaks[worst]:.3e} mol/m2 on {days[worst]} "
      f"= {ratio:.1f}x the background ({bg:.3e}).")

# 4. Add MERRA-2 winds for the worst day to see which way the plume blows.
merra = earthaccess.search_data(short_name="M2I3NPASM", bounding_box=aoi,
                                temporal=(str(days[worst]), str(days[worst])))
md = xr.open_dataset(earthaccess.open(merra)[0])
u = float(md["U"].sel(lev=850, method="nearest").mean())
v = float(md["V"].sel(lev=850, method="nearest").mean())

# 5. Plot: daily peak/mean series + a map of the strongest overpass with the wind arrow.
lon, lat, grid = scenes[order[worst]]
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))
ax1.plot(days, peaks, "-o", label="daily peak"); ax1.plot(days, means, "-o", label="daily mean")
ax1.axhline(bg, ls="--", c="k", label="background"); ax1.set_ylabel("SO2 (mol/m2)"); ax1.legend()
pc = ax2.pcolormesh(lon, lat, grid, shading="auto"); fig.colorbar(pc, ax=ax2, label="SO2 (mol/m2)")
clon, clat = (aoi[0] + aoi[2]) / 2, (aoi[1] + aoi[3]) / 2
ax2.quiver(clon, clat, u, v, color="r", scale=80, label="850 hPa wind")
ax2.set_title(f"SO2 plume {days[worst]}"); ax2.legend(); plt.tight_layout(); plt.show()

# Cross-check before you trust it: rerun on OMPS_NPP_NMSO2_PCA_L2 for the same days —
# two independent instruments should roughly agree (and recall the amount depends on the
# assumed plume height, per the gotchas above).

You should end up with three things: a map of the SO₂ column (in mol/m²) over the vent on the peak day, with wind arrows showing the downwind plume and hot-spot pixels at the summit; a day-by-day series of average and peak SO₂, where a step-up flags a volcano escalating from quiet degassing toward eruption; and a sanity check comparing TROPOMI against OMPS for the same days, since two independent instruments should roughly agree.

Where the data comes from

Almost everything comes from NASA through one free login (Earthdata Login). The SO₂ products (TROPOMI, OMI, OMPS) and the MERRA-2 winds live at the GES DISC archive. The VIIRS/MODIS heat-detector data comes from LAADS/LANCE. Because they share one login, you don’t juggle accounts. If you’d rather pull TROPOMI from its original source, it also lives in the European Copernicus Data Space.

Sources

How a scientist answers this
Parameters
SO2 vertical column amount (Dobson Units) from Sentinel-5P TROPOMI (~5.5x3.5 km), OMI OMSO2 (~13x24 km), and OMPS-NPP (each with their air-mass/box-height assumption and quality flags); joined with VIIRS/MODIS thermal-anomaly (VNP14/MOD14) fire pixels for vent heat and MERRA-2 winds and PBL height for plume transport. SO2 is flagged above a per-scene background using the retrieval's recommended quality cutoff.
Method
Per overpass, threshold the quality-filtered SO2 column above local background to map presence and downwind extent, advect/interpret the plume with MERRA-2 winds, and stack a multi-day column time series over the vent to flag escalation; classify quiescent degassing (modest, vent-anchored) vs eruption (large, fast-spreading, high-altitude) and corroborate with summit thermal anomalies.
Validation
Apply the product quality flags and the correct air-mass/plume-height assumption (column and any flux estimate depend on it), and corroborate against the local volcano observatory, ground deformation (InSAR/GPS), and seismicity; remember these are once-daily sun-synchronous snapshots that can miss short events.
In plain EnglishRead the daily satellite snapshot of sulfur-dioxide gas over the volcano, watch it grow and drift with the wind, and check the summit for heat — a small steady cloud means degassing, a big fast-spreading one means an eruption.

Make it yours → Set the volcano bounding box and date range, choose the sensor (TROPOMI for resolution, OMI for record length) and the SO2 quality/background threshold.

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

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