# Changelog

This changelog is generated automatically from [GitHub Releases](https://github.com/lqgentner/s1bursts/releases).


# s1bursts 0.9.0

*2026-11-07* · [GitHub](https://github.com/lqgentner/s1bursts/releases/tag/v0.9.0)

Composites now join bursts at the midline of their overlap, without their darkened edges. s1bursts is now citable: releases are archived on Zenodo under the DOI [10.5281/zenodo.23918246](https://doi.org/10.5281/zenodo.23918246); see `CITATION.cff`.


### Changed

- **Breaking:** during compositing, the bursts of one orbit and date are joined at the midline of their overlap: each pixel comes from the burst whose edge is farther away, which is how SNAP's TOPSAR-Deburst and TOPSAR-Merge join bursts and sub-swaths. Before, the burst with the lowest ID filled the whole overlap. Composites from 0.8 raise [ProductSettingsMismatchError](reference/errors.ProductSettingsMismatchError.html#s1bursts.errors.ProductSettingsMismatchError) with `overwrite=False`; rebuild them with `overwrite=True`.
- **Breaking:** the darkened edges of bursts are removed before compositing: 4 pixels for RTC and GTC and 5 for coherence at the default settings on a 10 m grid, more with more looks or a larger window. Keep them with `burst_edge_trim=False`.
- **Breaking:** [compose_coherence_lrw()](reference/resolution_weighter.ResolutionWeighter.html#s1bursts.resolution_weighter.ResolutionWeighter.compose_coherence_lrw) raises [CompositeInputError](reference/errors.CompositeInputError.html#s1bursts.errors.CompositeInputError) when a burst that supplies coherence pixels has no RTC product of the same date. Before, the scattering areas were mosaicked separately, so a neighbouring burst's area could silently stand in.
- **Breaking:** `img_resampling` accepts only `"BILINEAR_INTERPOLATION"` (the default) and `"NEAREST_NEIGHBOUR"`. The cubic and sinc kernels corrupted pixels next to missing data; reprocess products made with them.
- **Breaking:** the composite metadata builders in `product_tags` take a required keyword `burst_edge_trim_px`.


# s1bursts 0.8.0

*2026-11-03* · [GitHub](https://github.com/lqgentner/s1bursts/releases/tag/v0.8.0)

The first release on PyPI, and the first with a [documentation site](https://lqgentner.github.io/s1bursts/). Every product now records the settings it was made with, and s1bursts no longer reuses or composites products made with other settings.


### Added

- `pip install s1bursts`. The [documentation site](https://lqgentner.github.io/s1bursts/) has a user guide, three tutorials on real data, and the API reference.
- Every product records every processing setting as a GeoTIFF tag, so a file says on its own how it was made. Composites carry the settings of their inputs.
- `crs="auto"` geocodes each burst in the UTM zone of its footprint ([Burst.utm_zone](reference/burst.Burst.html#s1bursts.burst.Burst.utm_zone)), so one call processes bursts across zones. `crs` also accepts strings and EPSG codes, such as `"EPSG:32632"` or `32632`.
- [OperationSummary.raise_on_failure()](reference/summary.OperationSummary.html#s1bursts.summary.OperationSummary.raise_on_failure) raises if any item of a batch failed: `catalog.download(bursts).raise_on_failure()`.
- Burst collections can be narrowed with [within()](reference/burst.BurstCollection.html#s1bursts.burst.BurstCollection.within), [starting_within()](reference/burst.BurstPairCollection.html#s1bursts.burst.BurstPairCollection.starting_within), `intersecting()` and `filter()` instead of through `.df`.
- `FileManager.open(product, layer)` reads a product from local disk or S3.
- `SNAPConfig(timeout=...)` sets the time limit of one `gpt` run.


### Changed

- **Breaking:** with `overwrite=False`, an existing product is reused only if it records the requested settings, and otherwise raises [ProductSettingsMismatchError](reference/errors.ProductSettingsMismatchError.html#s1bursts.errors.ProductSettingsMismatchError). Composite inputs must agree on their settings and SNAP version, and otherwise raise [InconsistentInputsError](reference/errors.InconsistentInputsError.html#s1bursts.errors.InconsistentInputsError). Products written by 0.7 record fewer settings: rebuild them with `overwrite=True`.
- **Breaking:** composites default to `aggregation="mean"` instead of `"median"`.
- **Breaking:** SLC and burst product file names include the pass direction, as in `S1_RTC_066A_030346_IW1_VV_20220105_32N.tif`, so files with the old names are no longer found.
- **Breaking:** an external DEM needs a name: `RTCConfig(dem=path, dem_name="swissALTI3D 30 m")`.
- **Breaking:** `crs` must be a WGS 84 / UTM zone.
- **Breaking:** the API is reorganized:
  - `BurstDatabase` → [BurstCatalog](reference/catalog.BurstCatalog.html#s1bursts.catalog.BurstCatalog), in `s1bursts.catalog`
  - `BackscatterConfig(flatten_terrain=False)` → [GTCConfig()](reference/snap_graph.GTCConfig.html#s1bursts.snap_graph.GTCConfig), and the default → [RTCConfig()](reference/snap_graph.RTCConfig.html#s1bursts.snap_graph.RTCConfig)
  - `fm.find_rtc_products(...)` and the other `find_*` methods → `fm.find(RTCProduct, ...)`
  - `comp, (qa_num, qa_cqm) = compose_rtc_lrw(..., write_qa=True)` → `comp = compose_rtc_lrw(..., write_qa=True)`, with the QA layers as `fm.get_product_path(comp, Layer.QA_CQM)`
  - `SearchQuery(time_range=("2022-01-01", "2023-01-01"))` → `SearchQuery(time_range=TimeRange("2022-01-01", "2022-12-31"))`, and [search()](reference/catalog.BurstCatalog.html#s1bursts.catalog.BurstCatalog.search) no longer takes `max_items`
  - `find_pairs(12, 6)` → `find_pairs(baseline=12, max_delta=pd.Timedelta(hours=6))`
  - `n_workers` → `max_workers`, `gpt_threads_per_job` → `threads_per_job`, `gpt_cache_ratio` → `cache_ratio`
  - errors derive from [S1BurstsError](reference/errors.S1BurstsError.html#s1bursts.errors.S1BurstsError), such as [CatalogError](reference/errors.CatalogError.html#s1bursts.errors.CatalogError) for a failed search and [CompositeError](reference/errors.CompositeError.html#s1bursts.errors.CompositeError) for a cell that cannot be composited
- **Breaking:** pass composites raise [EmptyCompositeError](reference/errors.EmptyCompositeError.html#s1bursts.errors.EmptyCompositeError) for a cell that no input reaches, as LRW composites do, instead of writing all-NaN files.
- **Breaking:** requires freezebase 0.11.
- The default `SNAP_MAX_RAM_GB` is 8 GB instead of 4 GB.


### Removed

- **Breaking:** the interferogram product; order [HyP3 burst InSAR](https://hyp3-docs.asf.alaska.edu/guides/burst_insar_product_guide) products instead. Also decibel output of composites, and `CoherenceConfig.square_pixel`.


### Fixed

- **Affects results:** `QA-CQM` of median and quantile composites overstated the local resolution, by up to a factor of 4. It is now `1 / sum(W * A)` under every aggregation.
- **Affects results:** where bursts overlap, composites take the pixel from the same burst on every run.
- `SearchQuery(intersects=...)` rejects an empty geometry or one not in WGS 84, which silently found nothing.
- An interrupted download no longer leaves a truncated SLC that later runs skip. A burst that both endpoints fail to download reports both errors, and rejected credentials stop the download after one login attempt.
- A data error of one burst no longer stops the batch, while a full disk does, and Ctrl-C stops a batch promptly.


### Security

- A failed CDSE login no longer keeps the password in the error it records.


# s1bursts 0.7.0

*2026-10-26* · [GitHub](https://github.com/lqgentner/s1bursts/releases/tag/v0.7.0)

s1bursts 0.7.0 adds beta-0 pass composites and no longer double-corrects the DEM half-pixel offset now that SNAP 14.0.2 fixes it.


### Added

- Beta-0 pass composites: [ResolutionWeighter.compose_gtc_by_pass()](reference/resolution_weighter.ResolutionWeighter.html#s1bursts.resolution_weighter.ResolutionWeighter.compose_gtc_by_pass) averages GTC products per pass direction, as [compose_rtc_by_pass()](reference/resolution_weighter.ResolutionWeighter.html#s1bursts.resolution_weighter.ResolutionWeighter.compose_rtc_by_pass) does for RTC (`S1_GTC_COMP_A_…` / `S1_GTC_COMP_D_…`, each with a QA layer).
- Python 3.15 support.


### Changed

- **Breaking:** requires freezebase 0.10.
- **Breaking:** an LRW composite for a cell that no burst covers with valid pixels raises [EmptyCompositeError](reference/errors.EmptyCompositeError.html#s1bursts.errors.EmptyCompositeError) and writes nothing. Before, it wrote an all-NaN composite. To skip such cells, catch [EmptyCompositeError](reference/errors.EmptyCompositeError.html#s1bursts.errors.EmptyCompositeError).
- LRW composites count only bursts with valid pixels in the cell. A burst whose footprint merely touches the cell no longer adds to `CONTRIBUTING_OBSERVATIONS` or to the first and last acquisition dates.
- **Breaking:** failed downloads, SNAP runs and product writes are still recorded per burst, but any other error now stops the run, since it points to a bug. Checks for `isinstance(result.error, RuntimeError)` keep working.
- The burst-ID map cache is a third smaller (128 → 85 MB for IW). Existing caches stay valid.


### Fixed

- **Affects results:** with SNAP 14.0.2 or newer, [prepare_dem_for_snap()](reference/dem.prepare_dem_for_snap.html#s1bursts.dem.prepare_dem_for_snap) shifted external DEMs by half a pixel (15 m for a 30 m DEM), because SNAP now corrects that offset itself. The shift is applied only where SNAP still needs it, so SNAP 13 results are unchanged. Prepared DEMs are rebuilt once; pass `snap_bin` if SNAP is not found through `SNAP_BIN` or `PATH`.
- When CDSE rejects a login token early, s1bursts logs in again instead of failing every later OData download.
- An OData download that returns something other than a file, such as a login page, is recorded as that burst's failure instead of stopping the batch.
