GOME2_NO2_2024_banner.png

Title

This notebook is an AC SAF notebook prepared by BIRA-IASB (Gaia Pinardi, Hugues Brenot), on illustrating the use of volcanic SO2 GOME-2 data:

A sample zip file is provided with this notebook and instructions on how to register and download more data from the AC SAF archive are also provided below.

AC SAF recomend the usage of HARP for reading, filtering, and gridding, as shown in a companion notebook (also available here: https://acsaf.org/notebooks.php).

Table of Contents

This notebook contains several sections:

Data description

Documentation

The GOME-2/MetOp total column products are generated at DLR in the framework of EUMETSAT’s AC SAF.

For information and access to all AC SAF products, please refer to the AC SAF web page and help desk: AC SAF Web page: http://acsaf.org AC SAF Helpdesk: helpdesk@acsaf.org

Additional information can be found in EUMETSAT's product Navigator accessible through the following link: http://navigator.eumetsat.int

Current and historical quick look images as well as value added products generated by DLR are available at: http://atmos.eoc.dlr.de/gome2

The ATBD (Algorithm Theoretical Basis Documents) and PUM (PRODUCT USER MANUAL) are available here: https://acsaf.org/docs/atbd/Algorithm_Theoretical_Basis_Document_NTO_OTO_Nov_2019.pdf and https://acsaf.org/docs/pum/Product_User_Manual_NTO_OTO_Nov_2019.pdf

Data download is described here: https://acsaf.org/offline_access.php and rely on accessing an ftp server.

Downloading test data

For this example, the data are included in the zip folder available with this notebook: SO2.zip

save then the zip folder into the data folder, at the same level than this notebook

Data files

The GOME-2 GDP 4.8/4.9 L2 reprocessed datafiles are structures as one file per orbit, ie 15 files per day:

image.png

HDF5 Product Format Description

The product content comprises the following groups:

image.png

Several gases are provided into the same orbital file, as mentionned in the file name:

i.e., GOME_O3-NO2-NO2Tropo-BrO-SO2-H2O-HCHO_L2_20181201134102_051_METOPA_62878_DLR_06.HDF5 will include O3, NO2, NO2Tropo, BrO, SO2, H2O and HCHO data.

In the TOTAL_COLUMNS, the final VCD values are given for all the gases, in a order specified in the file name and in the variable /META_DATA/MainSpecies:

image.png

In addition, each gas has his own specific variables within the DETAILED_RESULTS group.

SO2 specific information

GOME-2 reports SO2 VCDs under several plume-height hypotheses, since the retrieved column depends strongly on this a-priori assumption. The 4 standard assumed layer heights are 15 km, 6 km, 2 km and 1 km.

The highest altitudes are usually relevant for the volcanic cases, while the lower altitudes are targetting anthropogenic emissions. The recommendation is to interpolate between the SO2 VCD provided at the different altitudes, for the altitude that best match the situation of interest.

In order to be able to do this, we recommend to read the VCD in the DETAILED_RESULTS/SO2 group:

image.png

The order of the altitudes is provided in the PlumeHeights variable in the same SO2 group.

Imports

Standard library / numerics / IO imports for what follows: h5py/netCDF4/xarray to read the HDF5 file with three different approaches, numpy for arrays, cf_units for unit handling, datetime/warnings as usual helpers (glob for multi-file patterns, matplotlib/cartopy for the maps built later).

These imports support several parallel approaches shown later in the notebook: xarray/h5py to read the HDF5 file directly, cartopy/matplotlib (with the PolyCollection/GeoAxes patch) to draw the satellite pixels as true geolocated polygons (not just points), numpy.ma and scipy.ndimage.label for the noise/background filtering of the SO2 signal, and math/calendar/datetime for the date and solar-angle calculations used to build the SZA quality flag. warnings.filterwarnings("ignore") silences library warnings (convenient here, but worth removing if you need to debug something upstream).

Define some useful variables

constants/unit conversions

In order to later turn an SO2 column (in DU) into an SO2 mass in kilotonnes once combined with a pixel area, we need a few physical conversion factors: Dobson Units (DU) to molecules/m², to mass (kt, kg/m²), using Avogadro's number and the molar mass of SO2 (64.066 g/mol). We provide the unit conversions here

nice colorbar for SO2

We build an SO2-specific colour scale (white → violet → cyan → green → yellow → orange → red → dark red) with a non-linear, piecewise normalization (PiecewiseNorm). The colorbar bounds (bounds = [0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10]) are irregular, so a standard linear normalization would crowd out the low values; PiecewiseNorm stretches every interval to the same visual width regardless of its actual size in DU, so both the background noise and concentrated plumes stay visible on the same map.

define some functions

We define here some functions that we will use to calculate SO2 mass, visualize footprints, calculate date from julian date, ...

Utility functions used further down:

start the routine

Reading the data

Here we points at a some sample orbit files of GOME-2 data on the downloaded and unzipped folder, builds the selected instrument and period and then lists the matching files on disk as a quick existence check before opening anything.

There are several possibilities in python to read an HDF5 file.

We refer here to illustrations presented in the NO2 notebook (https://acsaf.org/notebooks.php) both using HARP or xarray. In the following, we will show the use of both without many explanation.

select instrument and period

Defines the parameters of this run: which satellite (metop), which orbit/time (period, format YYYYMMDDHHMMSS), which SO2 layer height to assume (SO2LH, in km — lower for anthropogenic sources, higher for volcanic plumes), and which region (region). The values are hard-coded here, with several alternative example cases left commented out for quick switching.

Norilsk and Kivu/DR Congo are the two pre-configured cases for anthropogenic emission and volcanic emissions, respectively.

get the data from the path and separate the file name into its different parts

read data (with xarray)

Reading approach: xarray: opens the HDF5 file with xr.open_dataset, targeting in turn the DETAILED_RESULTS, GEOLOCATION, CLOUD_PROPERTIES and DETAILED_RESULTS/SO2 groups.

and get all the needed variables

We extract the SO2 column at the 4 standard assumed layer heights (15 km, 6 km, 2 km, 1 km) and convert them from molecules/cm² to DU. These will later be used to interpolate to the height of interest. We also retrieve the 4 pixel-corner coordinates (A/B/C/D → SW/SE/NE/NW) and the SZA. loncen is wrapped into [-180, 180] (the source files sometimes use [0, 360]).

Filter the data

We want to estimate the best SZA limit, which depend on the day of the year. For this, we compute the decimal day-of-year (integer DOY plus the fraction of the day already elapsed) from period, which is then used by the SZAlimitGOME2 function (defined earlier) to derive the SZA quality limit for this specific pixel time.

flag due to high sza

We now build a flagVCD = 1 where the pixel's SZA is below the seasonal limit (north or south, chosen from the scene's mean latitude), 0 otherwise. We then cleans the data: negative SO2 columns (not physically possible, noise artifacts) are set to 0, and pixels with flagVCD < 0 are set to NaN.

select SO2 column (depending on the SO2 layer height mean values)

As discussed above, the idea is to linearly interpolates between the 2 standard layer heights bracketing SO2LH (the parameter chosen at the top of the notebook) to estimate the SO2 column at the actually assumed plume height. E.g. with SO2LH=8 (between 6 and 15 km), it interpolates between gome2_so2_6km and gome2_so2_15km.

criteria to filter backscan

Typically, the "backscan" pixels are geometrically larger and of lower quality, so we compute each pixel's area (calcSO2massPXL/pixel_area) and excludes pixels whose area exceeds 9000 km². The mask is applied consistently to every geometry-related variable (corners, center, flag) and the corner arrays are then re-stacked (latcor, loncor) as needed for the polygon plot.

criteria for the lat/lon box used for mapping

We Define lat/lon boxes for the selected region: first a larger box (lonmin/max, latmin/max) used for the map display, and a tighter box (lonmini/maxi, latmini/maxi) that is used to select the pixels that go into the SO2 mass estimate. Norilsk (anthropogenic emission) and Kivu/DR Congo (volcanic) are the two pre-configured cases.

We now restrict the data to the small lat/lon box (latmini/maxi, lonmini/maxi), which is the precise area where the SO2 mass should be estimated (e.g. just around the Norilsk/Kivu plume, not the whole display region).

These variables are then converted to plain numpy arrays (.values) for the calculations that follow.

calculate SO2 max and do plot of the region

Now we follow a 5-step processing chain to calculate the maximum SO2 and prepare everything for the plot:

  1. Quality filter — keep only pixels with flagVCD != 0 (valid SZA).
  2. Noise estimate — standard deviation of values below 1 DU (presumed signal-free area).
  3. Background removal — computes a "background" value (median of values under the noise/detection threshold) and zeroes out anything below it.
  4. Thresholding — boolean mask of pixels above the threshold (3× noise, or the 0.45 DU detection limit).
  5. Connected components (scipy.ndimage.label) — removes small isolated clusters under 20 connected pixels, filtering out residual noise that happens to cross the threshold in isolation, keeping only genuinely contiguous plumes.

The total SO2 mass is then computed (calcSO2massPXL, summed over positive pixels), the colour-scale max (vmax) is chosen dynamically based on the plume's intensity, a summary is printed (mass, area, max value and its location), the output PNG filename is built, and in the cell after the visualize_footprints function is run to produce the map.

Now we Call visualize_footprints with the cleaned, region-cropped SO2 field and its pixel corners, plus the mass/area/max statistics just computed, so they get included into the map title.

We can now save the figure as a PNG file:

end of the notebook