Download Sentinel-1 partial products¶
This tutorial downloads Sentinel-1 SLC products as cropped .partial.SAFE directories.
Partial products are useful when you only need the bursts intersecting a given AOI. The downloader keeps the SAFE-like metadata structure, writes cropped measurement TIFFs, and stores two required metadata files in each partial product:
partial_download.yml: downloaded subswaths, polarizations, burst ranges, and cropped raster offsets.partial_aoi.geojson: the exact AOI used to select the downloaded bursts.
Important credential note:
- Product search uses the public CDSE STAC API and does not use EODAG.
- Partial raster download reads objects from CDSE S3, so you need CDSE S3 credentials, not the usual EODAG username/password flow used by full-product examples.
1. Imports and logging¶
import json
import logging
import os
from pathlib import Path
import geopandas as gpd
import yaml
from eo_tools.S1.download import download_partial_products, search_products
from eo_tools.util import explore_products
logging.basicConfig(level=logging.INFO)
logging.getLogger("httpx").setLevel(logging.WARNING)
2. Configure paths, AOI, and S3 credentials¶
Create S3 credentials from your Copernicus Data Space Ecosystem account, then either:
- save them in
/data/creds_s3.json, or - expose them as environment variables.
Expected JSON forms are either:
{"username": "<access-key>", "password": "<secret-key>"}
or:
{"aws_key": "<access-key>", "aws_secret": "<secret-key>"}
Do not commit credential files to git.
data_dir = Path("/data/S1/partial_dls")
data_dir.mkdir(parents=True, exist_ok=True)
aoi_file = Path("../data/Morocco_tiny.geojson")
shp = gpd.read_file(aoi_file).geometry.iloc[0]
creds_file = Path("/data/creds_s3.json")
if creds_file.is_file():
with creds_file.open(encoding="utf-8") as f:
creds = json.load(f)
aws_key = creds.get("aws_key", creds.get("username"))
aws_secret = creds.get("aws_secret", creds.get("password"))
else:
aws_key = os.environ.get("CDSE_S3_ACCESS_KEY") or os.environ.get("AWS_ACCESS_KEY_ID")
aws_secret = os.environ.get("CDSE_S3_SECRET_KEY") or os.environ.get("AWS_SECRET_ACCESS_KEY")
if not aws_key or not aws_secret:
raise RuntimeError(
"Missing CDSE S3 credentials. Create /data/creds_s3.json or set "
"CDSE_S3_ACCESS_KEY and CDSE_S3_SECRET_KEY."
)
print(f"Partial products will be written to: {data_dir}")
print(f"AOI: {aoi_file}")
Partial products will be written to: /data/S1/partial_dls AOI: ../data/Morocco_tiny.geojson
The partial-product API currently requires the AOI to be one Shapely Polygon. Multi-feature AOIs and multipolygons are rejected intentionally so the stored product AOI remains unambiguous.
shp.geom_type
'Polygon'
3. Search products for the AOI¶
Search the public CDSE STAC catalog for Sentinel-1 SLC products intersecting the AOI. Adjust the date range to find products for the period you want to download.
search_products(...) always uses the Sentinel-1 SLC STAC collection internally.
products = search_products(
intersects=shp,
datetime="2023-09-01/2023-09-20",
)
products[["id", "startTimeFromAscendingNode", "relativeOrbitNumber", "orbitDirection"]]
| id | startTimeFromAscendingNode | relativeOrbitNumber | orbitDirection | |
|---|---|---|---|---|
| 0 | S1A_IW_SLC__1SDV_20230920T184154_20230920T1842... | 2023-09-20 18:41:54.184015+00:00 | 118 | ascending |
| 1 | S1A_IW_SLC__1SDV_20230916T063730_20230916T0637... | 2023-09-16 06:37:30.627837+00:00 | 52 | descending |
| 2 | S1A_IW_SLC__1SDV_20230916T063705_20230916T0637... | 2023-09-16 06:37:05.804939+00:00 | 52 | descending |
| 3 | S1A_IW_SLC__1SDV_20230915T183345_20230915T1834... | 2023-09-15 18:33:45.279701+00:00 | 45 | ascending |
| 4 | S1A_IW_SLC__1SDV_20230908T184213_20230908T1842... | 2023-09-08 18:42:13.287225+00:00 | 118 | ascending |
| 5 | S1A_IW_SLC__1SDV_20230904T063730_20230904T0637... | 2023-09-04 06:37:30.213065+00:00 | 52 | descending |
| 6 | S1A_IW_SLC__1SDV_20230904T063705_20230904T0637... | 2023-09-04 06:37:05.394279+00:00 | 52 | descending |
| 7 | S1A_IW_SLC__1SDV_20230903T183344_20230903T1834... | 2023-09-03 18:33:44.895417+00:00 | 45 | ascending |
4. Explore and select products¶
explore_products(...) groups products with nearly identical footprints and relative orbits. Hover over a footprint to see its product indices and acquisition dates. Use the layer box in the top-right corner of the map to show or hide groups of overlapping products.
The map object is the final expression in the next cell so Folium stores its inline HTML output in the notebook for mkdocs-jupyter.
m = explore_products(products, shp)
m
Use the indices shown on the map to create sel, the products that will be downloaded. For simplicity, this example selects two products from the same footprint group. Replace the example indices below with your chosen products.
# in this example we select 2 fully overlapping scenes
product_indices = [1, 5]
sel = products.loc[product_indices]
sel[["id", "startTimeFromAscendingNode", "relativeOrbitNumber", "orbitDirection"]]
| id | startTimeFromAscendingNode | relativeOrbitNumber | orbitDirection | |
|---|---|---|---|---|
| 1 | S1A_IW_SLC__1SDV_20230916T063730_20230916T0637... | 2023-09-16 06:37:30.627837+00:00 | 52 | descending |
| 5 | S1A_IW_SLC__1SDV_20230904T063730_20230904T0637... | 2023-09-04 06:37:30.213065+00:00 | 52 | descending |
5. Download partial products¶
Use pol="vv", pol="vh", pol="full", or a list such as ["vv", "vh"].
If the target <product-id>.partial.SAFE directory already exists:
force_overwrite=Falseskips it and logs a warning.force_overwrite=Trueremoves the directory and downloads it again.
The downloader does not run a full integrity check on existing partial products. If in doubt, re-download with force_overwrite=True.
download_partial_products(
products=sel,
shp=shp,
out_dir=data_dir,
aws_key=aws_key,
aws_secret=aws_secret,
pol="full",
force_overwrite=True,
)
INFO:eo_tools.S1.download:Selected polarizations: VV, VH INFO:eo_tools.S1.download:Downloading S1A_IW_SLC__1SDV_20230916T063730_20230916T063757_050349_060FCD_6814. WARNING:eo_tools.S1.download:Partial product directory already exists: /data/S1/partial_dls/S1A_IW_SLC__1SDV_20230916T063730_20230916T063757_050349_060FCD_6814.partial.SAFE WARNING:eo_tools.S1.download:force_overwrite=True; removing existing partial product directory and re-downloading S1A_IW_SLC__1SDV_20230916T063730_20230916T063757_050349_060FCD_6814. INFO:eo_tools.auxils:Removing /data/S1/partial_dls/S1A_IW_SLC__1SDV_20230916T063730_20230916T063757_050349_060FCD_6814.partial.SAFE INFO:eo_tools.S1.download:Creating partial product structure for S1A_IW_SLC__1SDV_20230916T063730_20230916T063757_050349_060FCD_6814 INFO:eo_tools.S1.download:Write annotation files for S1A_IW_SLC__1SDV_20230916T063730_20230916T063757_050349_060FCD_6814 INFO:eo_tools.S1.download:Downloading partial raster for IW1 / VV, burst 1 to 1. INFO:eo_tools.S1.download:Downloading partial raster for IW2 / VV, burst 1 to 1. INFO:eo_tools.S1.download:Downloading partial raster for IW1 / VH, burst 1 to 1. INFO:eo_tools.S1.download:Downloading partial raster for IW2 / VH, burst 1 to 1. INFO:eo_tools.S1.download:Create partial download manifest partial_download.yml INFO:eo_tools.S1.download:Create partial product AOI metadata partial_aoi.geojson INFO:eo_tools.S1.download:Downloading S1A_IW_SLC__1SDV_20230904T063730_20230904T063757_050174_0609E3_DAA1. WARNING:eo_tools.S1.download:Partial product directory already exists: /data/S1/partial_dls/S1A_IW_SLC__1SDV_20230904T063730_20230904T063757_050174_0609E3_DAA1.partial.SAFE WARNING:eo_tools.S1.download:force_overwrite=True; removing existing partial product directory and re-downloading S1A_IW_SLC__1SDV_20230904T063730_20230904T063757_050174_0609E3_DAA1. INFO:eo_tools.auxils:Removing /data/S1/partial_dls/S1A_IW_SLC__1SDV_20230904T063730_20230904T063757_050174_0609E3_DAA1.partial.SAFE INFO:eo_tools.S1.download:Creating partial product structure for S1A_IW_SLC__1SDV_20230904T063730_20230904T063757_050174_0609E3_DAA1 INFO:eo_tools.S1.download:Write annotation files for S1A_IW_SLC__1SDV_20230904T063730_20230904T063757_050174_0609E3_DAA1 INFO:eo_tools.S1.download:Downloading partial raster for IW1 / VV, burst 1 to 1. INFO:eo_tools.S1.download:Downloading partial raster for IW2 / VV, burst 1 to 1. INFO:eo_tools.S1.download:Downloading partial raster for IW1 / VH, burst 1 to 1. INFO:eo_tools.S1.download:Downloading partial raster for IW2 / VH, burst 1 to 1. INFO:eo_tools.S1.download:Create partial download manifest partial_download.yml INFO:eo_tools.S1.download:Create partial product AOI metadata partial_aoi.geojson
6. Inspect one partial product¶
A partial product is not a full Sentinel-1 SAFE. It is a SAFE-like directory containing full annotation metadata, cropped measurement TIFFs, and the partial-product metadata used by EO-Tools processors.
partial_product = data_dir / f"{sel.iloc[0].id}.partial.SAFE"
manifest_file = partial_product / "partial_download.yml"
partial_aoi_file = partial_product / "partial_aoi.geojson"
print(partial_product)
print(f"Manifest exists: {manifest_file.is_file()}")
print(f"AOI metadata exists: {partial_aoi_file.is_file()}")
print("Measurement files:")
for path in sorted((partial_product / "measurement").glob("*.tiff")):
print(f"- {path.name}")
/data/S1/partial_dls/S1A_IW_SLC__1SDV_20230916T063730_20230916T063757_050349_060FCD_6814.partial.SAFE Manifest exists: True AOI metadata exists: True Measurement files: - s1a-iw1-slc-vh-20230916t063731-20230916t063756-050349-060fcd-001.tiff - s1a-iw1-slc-vv-20230916t063731-20230916t063756-050349-060fcd-004.tiff - s1a-iw2-slc-vh-20230916t063732-20230916t063757-050349-060fcd-002.tiff - s1a-iw2-slc-vv-20230916t063732-20230916t063757-050349-060fcd-005.tiff
with manifest_file.open(encoding="utf-8") as f:
manifest = yaml.safe_load(f)
manifest
{'product_id': 'S1A_IW_SLC__1SDV_20230916T063730_20230916T063757_050349_060FCD_6814',
'aoi_file': 'partial_aoi.geojson',
'subsets': {'iw1': {'vv': {'file': 'measurement/s1a-iw1-slc-vv-20230916t063731-20230916t063756-050349-060fcd-004.tiff',
'min_burst': 1,
'max_burst': 1,
'line_start': 0,
'number_of_lines': 1507,
'lines_per_burst': 1507},
'vh': {'file': 'measurement/s1a-iw1-slc-vh-20230916t063731-20230916t063756-050349-060fcd-001.tiff',
'min_burst': 1,
'max_burst': 1,
'line_start': 0,
'number_of_lines': 1507,
'lines_per_burst': 1507}},
'iw2': {'vv': {'file': 'measurement/s1a-iw2-slc-vv-20230916t063732-20230916t063757-050349-060fcd-005.tiff',
'min_burst': 1,
'max_burst': 1,
'line_start': 0,
'number_of_lines': 1519,
'lines_per_burst': 1519},
'vh': {'file': 'measurement/s1a-iw2-slc-vh-20230916t063732-20230916t063757-050349-060fcd-002.tiff',
'min_burst': 1,
'max_burst': 1,
'line_start': 0,
'number_of_lines': 1519,
'lines_per_burst': 1519}}}}
Troubleshooting¶
- If processing later raises a no-overlap error, this is likely because STAC product footprints do not represent the exact Sentinel-1 burst geometries. Two products may overlap each other and the AOI in the catalog but still have no common burst available for InSAR. Use
eo_tools.auxils.get_burst_geometry(...)to inspect both products' burst geometries and display their overlap on a Folium map before selecting or downloading another pair.
Next step: use s1-partial-product-processing.ipynb to process these .partial.SAFE directories.