Skip to main content

Finding and downloading bursts

A search queries the CDSE catalog for the bursts of a place and a time window, and a download fetches them. Searching needs no account and downloads nothing, so you can refine a query freely before committing to a download.

Search an area

Pass an area of interest as a shapely geometry in longitude and latitude, together with a time window. The search returns every burst that overlaps the area and shows their footprints on a map:

from shapely.geometry import box
from s1bursts import BurstCatalog, FileManager, SearchQuery, TimeRange

catalog = BurstCatalog(FileManager("data"))
bursts = catalog.search(SearchQuery(
    intersects=box(8.00, 46.40, 8.08, 46.48),
    time_range=TimeRange("2022-01-01", "2022-01-31"),
    polarization="VV",
))
bursts

BurstCollection

Bursts
19
Footprints
7
Bursts
burst_id sub_swath polarization date
0 140414 IW2 VV 2022-01-01 05:35:41.647945+00:00
1 187142 IW3 VV 2022-01-02 17:23:51.341251+00:00
2 187143 IW3 VV 2022-01-02 17:23:54.099528+00:00
3 297211 IW1 VV 2022-01-06 05:43:49.467183+00:00
4 297212 IW1 VV 2022-01-06 05:43:52.225460+00:00
5 30345 IW1 VV 2022-01-09 17:15:40.311026+00:00
6 30346 IW1 VV 2022-01-09 17:15:43.069303+00:00
7 140414 IW2 VV 2022-01-13 05:35:41.278530+00:00
8 187142 IW3 VV 2022-01-14 17:23:50.966877+00:00
9 187143 IW3 VV 2022-01-14 17:23:53.725154+00:00
10 297211 IW1 VV 2022-01-18 05:43:48.973546+00:00
11 297212 IW1 VV 2022-01-18 05:43:51.731823+00:00
12 30345 IW1 VV 2022-01-21 17:15:39.615073+00:00
13 30346 IW1 VV 2022-01-21 17:15:42.373350+00:00
14 140414 IW2 VV 2022-01-25 05:35:40.663418+00:00
15 187142 IW3 VV 2022-01-26 17:23:50.388553+00:00
16 187143 IW3 VV 2022-01-26 17:23:53.146830+00:00
17 297211 IW1 VV 2022-01-30 05:43:48.503805+00:00
18 297212 IW1 VV 2022-01-30 05:43:51.262082+00:00

Even a small area usually returns several footprints. Bursts from different orbits and sub-swaths overlap the same few kilometers, each seeing the ground from a different direction. The area selects whole bursts and does not crop them. A TimeRange covers whole days, and both end dates are included.

Follow one footprint

To follow one footprint through time, search by burst_id and sub_swath instead of by area. This is the usual query once an area search has shown which footprint covers your site best:

bursts = catalog.search(SearchQuery(
    time_range=TimeRange("2022-01-01", "2022-12-31"),
    burst_id=30346, sub_swath="IW1", polarization="VV",
))

SearchQuery also filters by orbit, pass direction and acquisition mode. Its reference lists every field.

Note

A search returns every matching burst, up to 1000, the size of one catalog page. If a query matches more, it raises TooManyResultsError rather than return an incomplete list. Narrow the time window or the area, or split the query and combine the results.

Combine searches

Search results add up with +, which drops any duplicates. Use this to collect several searches into one download, for example the same footprint in winter and in summer:

footprint = dict(burst_id=30346, sub_swath="IW1", polarization="VV")
winter = catalog.search(SearchQuery(time_range=TimeRange("2022-01-01", "2022-01-31"), **footprint))
summer = catalog.search(SearchQuery(time_range=TimeRange("2022-07-01", "2022-07-31"), **footprint))
both = winter + summer
print(len(winter), len(summer), len(both))
2 2 4

Pair acquisitions

Coherence compares two acquisitions of the same footprint. find_pairs() turns a search result into pairs a fixed number of days apart, which can be downloaded and processed like single bursts:

pairs = bursts.find_pairs(baseline=12)

The baseline is a whole number of days, and both arguments are passed by keyword. max_delta sets how far the actual spacing may deviate from it, six hours by default. A pair needs both of its acquisitions, so search a little beyond the end of the period you want and keep the pairs that start within it:

pairs = bursts.find_pairs(baseline=12).starting_within(january)

Download the bursts

BurstCatalog.download() fetches the bursts of a search result, or both acquisitions of every pair. Bursts already on disk are skipped, so an interrupted download can be run again:

summary = catalog.download(bursts, max_workers=4)
summary.print_summary()

max_workers sets how many bursts download in parallel. Each file is saved in the s1-slc folder below the FileManager’s base directory.

When the burst service fails

CDSE’s burst service occasionally fails for some bursts. If CDSE S3 keys are set, s1bursts then extracts the burst from the full scene on CDSE’s S3 storage instead. This route is slower but usually succeeds. Without the keys, the burst is recorded as failed. Pass endpoint="s3" to try the S3 route first.

Failed downloads

A failed burst does not stop the download by default. It is recorded in the returned OperationSummary and the remaining bursts continue. Check the summary before processing: raise_on_failure() raises an OperationFailedError that lists every failed burst, and otherwise returns the summary, so it can follow the call directly:

catalog.download(bursts).raise_on_failure()

To inspect the failures yourself, read them from the summary:

for failure in summary.failed_items:
    print(failure.source.date, failure.error)

Most failures are temporary server errors and succeed on a second run, which downloads only the missing bursts. To stop at the first failure instead, create the catalog with BurstCatalog(fm, continue_on_error=False). A burst that CDSE reports as missing is not requested again by the same BurstCatalog. Create a new one to retry it later. To accept such bursts and continue, ignore their error type:

from s1bursts.errors import BurstNotFoundError

catalog.download(bursts).raise_on_failure(ignore=BurstNotFoundError)

Reuse downloaded bursts

FileManager lists what is already stored, without a new search. Use this to process bursts downloaded in an earlier session:

from s1bursts import FileManager
from s1bursts.burst import Burst

fm = FileManager("data")
bursts = fm.find(Burst, burst_id=30346, time_range=TimeRange("2022-01-01", "2022-06-30"))

The result is a list of bursts, which the processing methods accept as it is. To form pairs, turn it into a collection first with BurstCollection.from_bursts(bursts).

find() lists every product and composite type the same way: pass the type, such as RTCProduct or RTCLRWComposite from s1bursts.product, and filter on the fields its filename records. These listings are rebuilt from filenames, so they contain less information than the original search result. Save the search if you need the full catalog record.

The burst-ID map

A burst from a search includes its relative orbit, pass direction and footprint, and product and SLC filenames record the orbit and pass direction, so the usual search, download, process and composite workflow needs no further data. Only a burst that did not come from a search needs to look these up, in the burst-ID map published by SAR-MPC. That applies to a burst you construct by hand, and to the footprint of a burst found with find(Burst), which its filename does not record. Download the map once, about 500 MB per acquisition mode, when you need it:

from s1bursts import download_burst_map

download_burst_map(mode="IW")