Skip to article frontmatterSkip to article content
earth and related environmental sciences

Sentinel-3 Patchwork L1 OLCI EFR L2 SLSTR FPR SYN AOD product format prototype

Sentinel-3 L1 OLCI EFR, Sentinel-3 L2 SLSTR FPR, Sentinel-3 SYN AOD product

Eurac Research

πŸš€ Launch in JupyterHub

Run this notebook interactively with all dependencies pre-installed

IntroductionΒΆ

In this notebook we will show an example of using Sentinel-3 L1 OLCI EFR, Sentinel-3 L2 SLSTR FPR, Sentinel-3 SYN AOD product

import matplotlib.pyplot as plt
import cartopy.crs as ccrs

import fsspec  # For remote access
import datatree

L1 OLCI EFRΒΆ

Product can only be accessed locally and also remotely, even if it is a zarr.zip

# Define the remote product path
remote_product_path = "https://eopf-public.s3.sbg.perf.cloud.ovh.net/eoproducts/S03OLCEFR_20230506T015316_0180_B117_T883.zarr.zip"

# Construct the fsspec mapper path
store = fsspec.get_mapper(f"zip::{remote_product_path}")

# Load it with datatree
dt = datatree.open_datatree(store, engine="zarr", consolidated=False, chunks={})

Open the product using EOPF API and visualize the tree structureΒΆ

print(dt)
DataTree('None', parent=None)
β”‚   Dimensions:  ()
β”‚   Data variables:
β”‚       *empty*
β”‚   Attributes:
β”‚       other_metadata:  {'absolute_pass_number': 52368, 'cycle_number': 79, 'dat...
β”‚       stac_discovery:  {'assets': [], 'bbox': [132.954, 29.0715, 115.986, 41.97...
β”œβ”€β”€ DataTree('conditions')
β”‚   β”œβ”€β”€ DataTree('geometry')
β”‚   β”‚       Dimensions:    (tp_rows: 4092, tp_columns: 77)
β”‚   β”‚       Coordinates:
β”‚   β”‚           latitude   (tp_rows, tp_columns) float64 3MB dask.array<chunksize=(4092, 77), meta=np.ndarray>
β”‚   β”‚           longitude  (tp_rows, tp_columns) float64 3MB dask.array<chunksize=(4092, 77), meta=np.ndarray>
β”‚   β”‚       Dimensions without coordinates: tp_rows, tp_columns
β”‚   β”‚       Data variables:
β”‚   β”‚           oaa        (tp_rows, tp_columns) float64 3MB dask.array<chunksize=(4092, 77), meta=np.ndarray>
β”‚   β”‚           oza        (tp_rows, tp_columns) float64 3MB dask.array<chunksize=(4092, 77), meta=np.ndarray>
β”‚   β”‚           saa        (tp_rows, tp_columns) float64 3MB dask.array<chunksize=(4092, 77), meta=np.ndarray>
β”‚   β”‚           sza        (tp_rows, tp_columns) float64 3MB dask.array<chunksize=(4092, 77), meta=np.ndarray>
β”‚   β”œβ”€β”€ DataTree('image')
β”‚   β”‚       Dimensions:         (rows: 4092, columns: 4865)
β”‚   β”‚       Coordinates:
β”‚   β”‚           altitude        (rows, columns) float32 80MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚           latitude        (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚           longitude       (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       Dimensions without coordinates: rows, columns
β”‚   β”‚       Data variables:
β”‚   β”‚           detector_index  (rows, columns) float32 80MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚           frame_offset    (rows, columns) float32 80MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”œβ”€β”€ DataTree('instrument')
β”‚   β”‚       Dimensions:                       (bands: 21, detectors: 3700, bands1: 21,
β”‚   β”‚                                          bands2: 21)
β”‚   β”‚       Dimensions without coordinates: bands, detectors, bands1, bands2
β”‚   β”‚       Data variables:
β”‚   β”‚           fwhm                          (bands, detectors) float32 311kB dask.array<chunksize=(21, 3700), meta=np.ndarray>
β”‚   β”‚           lambda0                       (bands, detectors) float32 311kB dask.array<chunksize=(21, 3700), meta=np.ndarray>
β”‚   β”‚           relative_spectral_covariance  (bands1, bands2) float32 2kB dask.array<chunksize=(21, 21), meta=np.ndarray>
β”‚   β”‚           solar_flux                    (bands, detectors) float32 311kB dask.array<chunksize=(21, 3700), meta=np.ndarray>
β”‚   β”œβ”€β”€ DataTree('meteorology')
β”‚   β”‚       Dimensions:                          (tp_rows: 4092, tp_columns: 77,
β”‚   β”‚                                             pressure_level: 25, wind_vector: 2)
β”‚   β”‚       Coordinates:
β”‚   β”‚         * pressure_level                   (pressure_level) float32 100B 1e+03 ... 1.0
β”‚   β”‚       Dimensions without coordinates: tp_rows, tp_columns, wind_vector
β”‚   β”‚       Data variables:
β”‚   β”‚           atmospheric_temperature_profile  (tp_rows, tp_columns, pressure_level) float32 32MB dask.array<chunksize=(4092, 77, 25), meta=np.ndarray>
β”‚   β”‚           horizontal_wind                  (tp_rows, tp_columns, wind_vector) float32 3MB dask.array<chunksize=(4092, 77, 2), meta=np.ndarray>
β”‚   β”‚           humidity                         (tp_rows, tp_columns) float32 1MB dask.array<chunksize=(4092, 77), meta=np.ndarray>
β”‚   β”‚           sea_level_pressure               (tp_rows, tp_columns) float32 1MB dask.array<chunksize=(4092, 77), meta=np.ndarray>
β”‚   β”‚           total_columnar_water_vapour      (tp_rows, tp_columns) float32 1MB dask.array<chunksize=(4092, 77), meta=np.ndarray>
β”‚   β”‚           total_ozone                      (tp_rows, tp_columns) float32 1MB dask.array<chunksize=(4092, 77), meta=np.ndarray>
β”‚   └── DataTree('orphans')
β”‚           Dimensions:            (rows: 4092, removed_pixels: 150)
β”‚           Coordinates:
β”‚               altitude           (rows, removed_pixels) float32 2MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               latitude           (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               longitude          (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚           Dimensions without coordinates: rows, removed_pixels
β”‚           Data variables:
β”‚               detector_index     (rows, removed_pixels) float32 2MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               frame_offset       (rows, removed_pixels) float32 2MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               nb_removed_pixels  (rows) uint16 8kB dask.array<chunksize=(1024,), meta=np.ndarray>
β”‚               sza                (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”œβ”€β”€ DataTree('measurements')
β”‚   β”‚   Dimensions:        (rows: 4092, columns: 4865)
β”‚   β”‚   Coordinates:
β”‚   β”‚       latitude       (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       longitude      (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       time_stamp     (rows) datetime64[ns] 33kB dask.array<chunksize=(1024,), meta=np.ndarray>
β”‚   β”‚   Dimensions without coordinates: rows, columns
β”‚   β”‚   Data variables: (12/21)
β”‚   β”‚       oa01_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       oa02_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       oa03_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       oa04_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       oa05_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       oa06_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       ...             ...
β”‚   β”‚       oa16_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       oa17_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       oa18_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       oa19_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       oa20_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   β”‚       oa21_radiance  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
β”‚   └── DataTree('orphans')
β”‚           Dimensions:        (rows: 4092, removed_pixels: 150)
β”‚           Coordinates:
β”‚               altitude       (rows, removed_pixels) float32 2MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               latitude       (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               longitude      (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚           Dimensions without coordinates: rows, removed_pixels
β”‚           Data variables: (12/21)
β”‚               oa01_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               oa02_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               oa03_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               oa04_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               oa05_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               oa06_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               ...             ...
β”‚               oa16_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               oa17_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               oa18_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               oa19_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               oa20_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
β”‚               oa21_radiance  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
└── DataTree('quality')
    β”‚   Dimensions:            (rows: 4092, columns: 4865)
    β”‚   Coordinates:
    β”‚       latitude           (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       longitude          (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚   Dimensions without coordinates: rows, columns
    β”‚   Data variables: (12/22)
    β”‚       oa01_radiance_unc  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       oa02_radiance_unc  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       oa03_radiance_unc  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       oa04_radiance_unc  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       oa05_radiance_unc  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       oa06_radiance_unc  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       ...                 ...
    β”‚       oa17_radiance_unc  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       oa18_radiance_unc  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       oa19_radiance_unc  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       oa20_radiance_unc  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       oa21_radiance_unc  (rows, columns) float64 159MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    β”‚       quality_flags      (rows, columns) uint32 80MB dask.array<chunksize=(1024, 1024), meta=np.ndarray>
    └── DataTree('orphans')
            Dimensions:            (rows: 4092, removed_pixels: 150)
            Coordinates:
                altitude           (rows, removed_pixels) float32 2MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                latitude           (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                longitude          (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
            Dimensions without coordinates: rows, removed_pixels
            Data variables: (12/22)
                oa01_radiance_unc  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                oa02_radiance_unc  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                oa03_radiance_unc  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                oa04_radiance_unc  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                oa05_radiance_unc  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                oa06_radiance_unc  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                ...                 ...
                oa17_radiance_unc  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                oa18_radiance_unc  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                oa19_radiance_unc  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                oa20_radiance_unc  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                oa21_radiance_unc  (rows, removed_pixels) float64 5MB dask.array<chunksize=(1024, 150), meta=np.ndarray>
                quality_flags      (rows, removed_pixels) uint32 2MB dask.array<chunksize=(1024, 150), meta=np.ndarray>

Opening measurement dataΒΆ

rad = dt.measurements.oa01_radiance
rad.encoding
{'chunks': (1024, 1024), 'preferred_chunks': {'rows': 1024, 'columns': 1024}, 'compressor': Blosc(cname='zstd', clevel=3, shuffle=BITSHUFFLE, blocksize=0), 'filters': None, '_FillValue': 65535, 'scale_factor': 0.013634907081723213, 'add_offset': 0.0, 'dtype': dtype('uint16'), 'coordinates': 'time_stamp latitude longitude'}

Underlying data is dask.array

rad.data
Loading...
rad.attrs
{'long_name': 'TOA radiance for OLCI acquisition band oa01', 'short_name': 'oa01_radiance', 'standard_name': 'toa_upwelling_spectral_radiance', 'units': 'mW.m-2.sr-1.nm-1', 'valid_max': 65534, 'valid_min': 0}
rad.units  ## Serving Ambiguity as a replacement for rad.is_scaled
rad.to_masked_array()
rad.sel()
Loading...

Simple raster plotΒΆ

Note that using xarray, data is correctly decoded and masked

rad.plot()
<Figure size 640x480 with 2 Axes>

Plot using the coordinates (lon,lat)ΒΆ

plt.figure(figsize=(14, 6))
ax = plt.axes()
rad.plot.pcolormesh(ax=ax, x="longitude", y="latitude", add_colorbar=False)
<Figure size 1400x600 with 1 Axes>

Open Meteorological conditionsΒΆ

meteo = dt.conditions.meteorology

Interpolate the atmo. temp. profile at p=832.2 hPa and plotΒΆ

tp = meteo["atmospheric_temperature_profile"].interp(pressure_level=832.2)
tp.plot()
<Figure size 640x480 with 2 Axes>

Open sat/sun anglesΒΆ

Angles are stored on a tiepoint subgrid

ds = dt.conditions.geometry
ds
Loading...

Have a look at condition parameters for removed pixelsΒΆ

ds = dt.conditions.orphans
ds
Loading...

SLSTR FRPΒΆ

# Define the remote product path
remote_product_path = "https://eopf-public.s3.sbg.perf.cloud.ovh.net/eoproducts/S03SLSFRP_20200908T182648_0179_A298_S883.zarr.zip"

# Construct the fsspec mapper path
store = fsspec.get_mapper(f"zip::{remote_product_path}")

# Load it with datatree
dt = datatree.open_datatree(store, engine="zarr", consolidated=False, chunks={})

Opening measurement data (1D)ΒΆ

Cannot find the lat/lon in this product ....

meas_in = dt.measurements.inadir
meas_in
Loading...

Plot Active Fire pixels positions on a PlateCarree gridΒΆ

import matplotlib.pyplot as plt

fig = plt.figure()
ax = plt.axes(projection=ccrs.PlateCarree())
# ax.set_global()
ax.coastlines()
ax.gridlines(draw_labels=True)
plt.scatter(meas_in.longitude, meas_in.latitude, c=meas_in.frp_mwir, vmax=100)
plt.colorbar()
<Figure size 640x480 with 2 Axes>

SYN AODΒΆ

# Define the remote product path
remote_product_path = "https://eopf-public.s3.sbg.perf.cloud.ovh.net/eoproducts/S03SYNAOD_20191227T124211_0060_A109_T883.zarr.zip"

# Construct the fsspec mapper path
store = fsspec.get_mapper(f"zip::{remote_product_path}")

# Load it with datatree
dt = datatree.open_datatree(store, engine="zarr", consolidated=False, chunks={})
aod550 = dt.measurements.aod_550
aod550
Loading...
aod550.plot()
<Figure size 640x480 with 2 Axes>

Plot using the coordinates (lon,lat)ΒΆ

Note that in SYN AOD product, lat/lon are undefined when the data is missing, which is not correctly handled by matplotlib pcolormesh

# Remove margins
aod550_dropna = aod550.dropna("columns", how="all")
aod550_dropna = aod550_dropna.dropna("rows", how="all")

# Fill remaining missing values
aod550_dropna["latitude"] = (
    ["rows", "columns"],
    aod550_dropna.latitude.bfill("columns").data,
)
aod550_dropna["longitude"] = (
    ["rows", "columns"],
    aod550_dropna.longitude.bfill("columns").data,
)
import matplotlib.pyplot as plt

plt.figure(figsize=(14, 6))
ax = plt.axes()
aod550_dropna.plot.pcolormesh(ax=ax, x="longitude", y="latitude", add_colorbar=False)
<Figure size 1400x600 with 1 Axes>