Open a TROPOMI CH₄ granule and screen it¶
A Sentinel-5P TROPOMI methane L2 granule (S5P_*_L2__CH4____*.nc) spreads one
retrieval over four NetCDF groups. LocalL2Source flattens them into a single
CF Dataset, renames the variables to the registry names, and applies the
quality, bounding-box and time screening in one call. The file itself has to
be on disk already (Earthdata acquisition is a separate step), and reading it
needs a NetCDF backend: pip install 'xrtoolz-products[local]'.
One granule, screened¶
from xrproducts import BBox, LocalL2Source, TimeRange
src = LocalL2Source()
ds = src.open(
"tropomi.ch4",
path="S5P_RPRO_L2__CH4____20190601T104423_20190601T122553_08532_03_020400.nc",
bbox=BBox(lon_min=4.0, lon_max=6.0, lat_min=51.0, lat_max=53.0),
time=TimeRange.parse("2019-06-01T11:00", "2019-06-01T12:00"),
qa_min=0.5, # PUM recommendation; None keeps the opener default (0.5), 0.0 keeps all
)
ds
<xarray.Dataset>
Dimensions: (time: 1, scanline: 212, ground_pixel: 31, layer: 12, ...)
Coordinates:
time (time) datetime64[ns] 2019-06-01
scanline_time (time, scanline) datetime64[ns] ...
lon (time, scanline, ground_pixel) float32 ...
lat (time, scanline, ground_pixel) float32 ...
Data variables:
xch4 (time, scanline, ground_pixel) float32 ...
xch4_bias_corrected (time, scanline, ground_pixel) float32 ...
xch4_precision (time, scanline, ground_pixel) float32 ...
qa_value (time, scanline, ground_pixel) float32 ...
column_averaging_kernel (time, scanline, ground_pixel, layer) float32 ...
ch4_profile_apriori (time, scanline, ground_pixel, layer) float32 ...
dry_air_subcolumns (time, scanline, ground_pixel, layer) float32 ...
sp (time, scanline, ground_pixel) float32 ...
pressure_interval (time, scanline, ground_pixel) float32 ...
...
What happened:
PRODUCT,DETAILED_RESULTS,INPUT_DATAandGEOLOCATIONSwere merged on the shared(time, scanline, ground_pixel)swath; the averaging kernel and a-priori profile keep theirlayeraxis.latitude/longitudebecame the 2-Dlat/loncoordinates, sobboxwas applied withsubset_bbox(where(..., drop=True)— scanlines and ground pixels entirely outside the box are dropped).timeis the granule reference time; the per-scanlinedelta_timebecamescanline_time, which thetime=window masks on.- Pixels with
qa_value < 0.5are NaN in every data variable (shape kept).
Only the opener¶
Skip the screening and keep the whole swath — or the raw product names — with the opener directly:
from xrproducts import open_tropomi_ch4_l2
raw = open_tropomi_ch4_l2(path, qa_min=None, keep_groups=True) # product names
ds = open_tropomi_ch4_l2(path) # canonical, qa >= 0.5
Several granules¶
paths=[...] concatenates granules along time in the order given (they must
share the swath shape):
Pressure per layer¶
The averaging kernel is applied on the product's pressure grid, which is not
stored per layer. Rebuild it from sp and pressure_interval:
p_layer = ds["sp"] - ds["layer"] * ds["pressure_interval"] # Pa, (time, scanline, ground_pixel, layer)
The same call for EMIT and GHGSat scenes¶
emit = src.open("emit.ch4", path="EMIT_L2B_CH4ENH_...nc", glt_path="EMIT_..._GLT.nc", bbox=box)
scenes = src.open("emit.ch4", paths=[scene_a, scene_b], glt_paths=[glt_a, glt_b])
plume = src.open("ghgsat.ch4", path="GHGSat_plume.nc")
Both come back on (time, y, x) with 2-D lon / lat, so subset_bbox
and the xrops.geom operators run on them unchanged. See
Local L2 products for the full API.