Skip to content

Commit 6f8d2ec

Browse files
authored
Merge pull request #62 from EOPF-Sample-Service/konstntokas-016-add_sen3_slstr_rbt
Add analysis mode for Sentinel-3 SLSTR RBT product
2 parents cd2ef78 + c46ec0b commit 6f8d2ec

17 files changed

Lines changed: 22081 additions & 119215 deletions

CHANGES.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1+
## Changes in 0.2.3 (under development)
2+
3+
- **Sentinel-3 SLSTR Level-1 RBT products** are now supported in analysis mode. This
4+
allows data from grids a, b, f, and i — in both nadir and oblique viewing
5+
geometries — to be represented on a unified grid within a single dataset.
6+
- **Sentinel-3 SLSTR datasets** are now terrain-corrected using the elevation
7+
information provided within the product itself.
8+
9+
110
## Changes in 0.2.2 (from 2025-09-24)
211

312
* In analysis mode for Sentinel-3 products, coordinates are now filtered so that only
4-
`"lat"` and `"lon"` remain. Since the data is rectified, non-spatial coordinates lose
13+
`"lat"` and `"lon"` remain. Since the data is rectified, non-spatial coordinates loose
514
their association with the data after rectification.
615

716

docs/guide.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,28 @@ Examples:
102102
#### Sentinel-3
103103

104104
Sentinel-3 products are provided on their **native grid mapping**, where each pixel
105-
is defined by a latitude/longitude pair, forming a **2D irregular grid**.
105+
is defined by a latitude/longitude pair, forming a **2D irregular grid**.
106106

107-
The analysis mode applies the [rectification algorithm in xcube-resampling](https://xcube-dev.github.io/xcube-resampling/guide/#3-rectification) to transform the irregular dataset into a **regular grid** with 1D latitude/longitude coordinates.
107+
The analysis mode applies the [rectification algorithm in xcube-resampling](https://xcube-dev.github.io/xcube-resampling/guide/#3-rectification)
108+
to transform the irregular dataset into a **regular grid** with 1D latitude/longitude
109+
coordinates.
110+
111+
For SLSTR products, a terrain correction is applied during this process. This is
112+
necessary because the original geolocation is corrected only for Earth curvature,
113+
but not for terrain variability caused by topography. See the
114+
[SLSTR product description](https://sentiwiki.copernicus.eu/web/slstr-products)
115+
for details.
116+
117+
For OLCI products, no additional terrain correction is required, as it is already
118+
incorporated in the Level-1 data. See the [OLCI Level-1 product description](https://sentiwiki.copernicus.eu/web/olci-products#OLCIProducts-L1BProducts-ObservationModeS3-OLCI-Products-L1B-OM)
119+
for details.
108120

109121
**Suported Products:**
110122

111123
- [Sentinel-3 OLCI Level-1 EFR](https://stac.browser.user.eopf.eodc.eu/collections/sentinel-3-olci-l1-efr)
112124
- [Sentinel-3 OLCI Level-1 ERR](https://stac.browser.user.eopf.eodc.eu/collections/sentinel-3-olci-l1-err)
113125
- [Sentinel-3 OLCI Level-2 LFR](https://stac.browser.user.eopf.eodc.eu/collections/sentinel-3-olci-l2-lfr)
126+
- [Sentinel-3 SLSTR Level-1 RBT](https://stac.browser.user.eopf.eodc.eu/collections/sentinel-3-slstr-l1-rbt)
114127
- [Sentinel-3 SLSTR Level-2 LST](https://stac.browser.user.eopf.eodc.eu/collections/sentinel-3-slstr-l2-lst)
115128

116129
Example:

environment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ dependencies:
1414
- requests
1515
- s3fs
1616
- xarray >=2024.10
17-
- xcube-resampling
17+
- xcube-resampling >=0.2.0
1818
- zarr >=2,<3.0
1919
# Development Dependencies - Tools
2020
- black

examples/open-sen1.ipynb

Lines changed: 9736 additions & 4437 deletions
Large diffs are not rendered by default.

examples/open-sen2.ipynb

Lines changed: 1198 additions & 1431 deletions
Large diffs are not rendered by default.

examples/open-sen3.ipynb

Lines changed: 10513 additions & 113261 deletions
Large diffs are not rendered by default.

integration/test_sen3_analysis.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Copyright (c) 2025 by EOPF Sample Service team and contributors
2+
# Permissions are hereby granted under the terms of the Apache 2.0 License:
3+
# https://opensource.org/license/apache-2-0.
4+
5+
from collections.abc import Sequence
6+
from unittest import TestCase
7+
8+
import xarray as xr
9+
10+
from integration.helpers import assert_dataset_is_chunked
11+
from xarray_eopf.constants import DEFAULT_ENDPOINT_URL
12+
from xarray_eopf.utils import timeit
13+
14+
15+
allowed_open_time = 1000 # seconds
16+
show_chunking = False
17+
18+
ol1efr_url = (
19+
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202508-s03olcefr/19/"
20+
"products/cpm_v256/S3B_OL_1_EFR____20250819T074058_20250819T074358_"
21+
"20250819T092155_0179_110_106_3420_ESA_O_NR_004.zarr"
22+
)
23+
24+
ol1err_url = (
25+
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202510-s03olcerr-global/"
26+
"19/products/cpm_v256/S3A_OL_1_ERR____20251019T145533_20251019T153950_"
27+
"20251019T165332_2657_131_353______PS1_O_NR_004.zarr"
28+
)
29+
30+
ol2lfr_url = (
31+
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202510-s03olclfr-"
32+
"global/15/products/cpm_v256/S3A_OL_2_LFR____20251015T050206_20251015T050506_"
33+
"20251015T070316_0179_131_290_2340_PS1_O_NR_003.zarr"
34+
)
35+
sl1rbt_url = (
36+
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202510-s03slsrbt-global/"
37+
"16/products/cpm_v256/S3B_SL_1_RBT____20251016T072510_20251016T072810_"
38+
"20251016T092049_0179_112_163_2700_ESA_O_NR_004.zarr"
39+
)
40+
sl2lst_url = (
41+
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202510-s03slslst-eu/16/"
42+
"products/cpm_v256/S3B_SL_2_LST____20251016T215803_20251016T220103_20251017T004323_"
43+
"0179_112_172_0540_ESA_O_NR_004.zarr"
44+
)
45+
46+
47+
class Sentinel3AnalysisTest(TestCase):
48+
def test_open_dataset_sen3_olci_l1_efr(self):
49+
expected_vars = ["oa01_radiance", "oa02_radiance", "oa03_radiance"]
50+
expected_size = (5000, 5269)
51+
self._test_sen3(ol1efr_url, expected_vars, expected_size)
52+
53+
def test_open_dataset_sen3_olci_l1_err(self):
54+
expected_vars = ["oa01_radiance", "oa02_radiance", "oa03_radiance"]
55+
expected_size = (14432, 11065)
56+
self._test_sen3(ol1err_url, expected_vars, expected_size)
57+
58+
def test_open_dataset_sen3_olci_l2_lfr(self):
59+
expected_vars = ["gifapar", "iwv", "otci"]
60+
expected_size = (4790, 5125)
61+
self._test_sen3(ol2lfr_url, expected_vars, expected_size)
62+
63+
def test_open_dataset_sen3_slstr_l1_rbt(self):
64+
expected_vars = ["s1_radiance_an", "s7_bt_in", "s7_bt_io"]
65+
expected_size = (2959, 3308)
66+
self._test_sen3(sl1rbt_url, expected_vars, expected_size)
67+
68+
def test_open_dataset_sen3_slstr_l2_lst(self):
69+
expected_vars = ["lst"]
70+
expected_size = (1473, 1657)
71+
self._test_sen3(sl2lst_url, expected_vars, expected_size)
72+
73+
def _test_sen3(
74+
self, path: str, expected_vars: Sequence[str], expected_size: tuple[int, int]
75+
):
76+
with timeit("open " + path) as result:
77+
# noinspection PyTypeChecker
78+
ds = xr.open_dataset(
79+
path,
80+
engine="eopf-zarr",
81+
chunks={},
82+
)
83+
self.assertTrue(result.time_delta < allowed_open_time)
84+
85+
for expected_var in expected_vars:
86+
self.assertIn(expected_var, ds)
87+
88+
assert_dataset_is_chunked(self, ds, verbose=show_chunking)
89+
for var_name in ds.data_vars:
90+
self.assertEqual(expected_size, ds[var_name].shape[-2:], msg=var_name)

integration/test_sen3_native.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,31 @@
1010
from xarray_eopf.utils import timeit
1111

1212
ol1efr_url = (
13-
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202508-s03olcefr/"
14-
"19/products/cpm_v256/S3B_OL_1_EFR____20250819T074058_20250819T074358_"
13+
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202508-s03olcefr/19/"
14+
"products/cpm_v256/S3B_OL_1_EFR____20250819T074058_20250819T074358_"
1515
"20250819T092155_0179_110_106_3420_ESA_O_NR_004.zarr"
1616
)
1717

1818
ol1err_url = (
19-
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202508-s03olcerr/"
20-
"20/products/cpm_v256/S3B_OL_1_ERR____20250820T082222_20250820T090603_"
21-
"20250820T113046_2621_110_121______ESA_O_NR_004.zarr"
19+
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202510-s03olcerr-global/"
20+
"19/products/cpm_v256/S3A_OL_1_ERR____20251019T145533_20251019T153950_"
21+
"20251019T165332_2657_131_353______PS1_O_NR_004.zarr"
2222
)
2323

2424
ol2lfr_url = (
25-
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202508-s03olclfr/"
26-
"20/products/cpm_v256/S3A_OL_2_LFR____20250820T110024_20250820T110324_"
27-
"20250820T125434_0179_129_265_2520_PS1_O_NR_003.zarr"
25+
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202510-s03olclfr-"
26+
"global/15/products/cpm_v256/S3A_OL_2_LFR____20251015T050206_20251015T050506_"
27+
"20251015T070316_0179_131_290_2340_PS1_O_NR_003.zarr"
2828
)
2929
sl1rbt_url = (
30-
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202508-s03slsrbt/"
31-
"20/products/cpm_v256/S3A_SL_1_RBT____20250820T074725_20250820T075025_"
32-
"20250820T095144_0180_129_263_3060_PS1_O_NR_004.zarr"
30+
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202510-s03slsrbt-global/"
31+
"16/products/cpm_v256/S3B_SL_1_RBT____20251016T072510_20251016T072810_"
32+
"20251016T092049_0179_112_163_2700_ESA_O_NR_004.zarr"
3333
)
3434
sl2lst_url = (
35-
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202508-s03slslst/"
36-
"21/products/cpm_v256/S3A_SL_2_LST____20250821T085614_20250821T085914_"
37-
"20250821T110745_0179_129_278_2700_PS1_O_NR_004.zarr"
35+
"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202510-s03slslst-eu/16/"
36+
"products/cpm_v256/S3B_SL_2_LST____20251016T215803_20251016T220103_"
37+
"20251017T004323_0179_112_172_0540_ESA_O_NR_004.zarr"
3838
)
3939

4040
allowed_open_time = 5 # seconds
@@ -65,14 +65,14 @@ def test_open_dataset_sen3_ol1efr_subgroup(self):
6565

6666
def test_open_datatree_sen3_ol1err(self):
6767
self._test_open_datatree_sen3(
68-
ol1err_url, 8, "measurements", {"columns": 1217, "rows": 14893}, 21
68+
ol1err_url, 8, "measurements", {"columns": 1217, "rows": 15098}, 21
6969
)
7070

7171
def test_open_dataset_sen3_ol1err(self):
7272
self._test_open_dataset_sen3(
7373
ol1err_url,
7474
"measurements_oa21_radiance",
75-
{"measurements_columns": 1217, "measurements_rows": 14893},
75+
{"measurements_columns": 1217, "measurements_rows": 15098},
7676
59,
7777
)
7878

@@ -81,7 +81,7 @@ def test_open_dataset_sen3_ol1err_subgroup(self):
8181
ol1err_url,
8282
"oa21_radiance",
8383
"measurements",
84-
{"columns": 1217, "rows": 14893},
84+
{"columns": 1217, "rows": 15098},
8585
21,
8686
)
8787

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ dependencies = [
5252
"requests",
5353
"s3fs",
5454
"xarray>=2024.10",
55-
"xcube-resampling",
55+
"xcube-resampling>=0.2.0",
5656
"zarr>=2,<3.0"
5757
]
5858

0 commit comments

Comments
 (0)