Archive (pure functions)
egms_client.archive ¶
Searching and downloading from the EGMS archive: Ortho L3 tiles and L2 bursts.
The Ortho L3 product is the ground velocity resampled on a 100 m grid in
EPSG:3035 (LAEA Europe), in 100 km tiles, one per component: U
(vertical) and E (east-west). A tile is named by its lower-left corner
in hundreds of kilometres: E47N19 covers 4,700,000-4,800,000 m east and
1,900,000-2,000,000 m north. Each ZIP (~60 MB) holds a CSV of time series
(~245 MB once unpacked) and a GeoTIFF of the mean velocity (~4 MB).
Downloading needs the id of a search, not the bearer token: the
download URL carries ?id=<search id>, and that id expires. An expired or
unknown id is answered with HTTP 401 and a plain-text message.
Verified against the live archive on 2026-11-03:
- releases are named
2020-2025in the API and2020_2025in file names; a release is a window of years, and a new one may extend the window rather than slide it (2020-2024 was followed by 2020-2025, not 2021-2025); - a tile at sea or outside coverage is answered with
status: falseandInvalid tile ID: 'E40N15', not with an empty search; - each hit carries its own
filenameandversion(2020_2025_1): the trailing number is a sub-release, so read the name from the hit instead of building it.
Beyond Ortho L3 the archive serves two levels of measurement points, one
ZIP per Sentinel-1 burst (a CSV of points with their time series and an XML
of metadata): L2A (BASIC) and L2B (CALIBRATED, tied to GNSS).
Verified on 2026-11-03:
GET /levelsnames themL2A,L2B,L3; the lower-caseL2aof the file names is refused asInvalid level;- a search needs a place:
bbox,tileId,swath,burstCycleorrelativeOrbit, elseYou must provide either bbox, ...; bboxis[[west, south], [east, north]]in degrees, for every level; any other shape is answeredAn error occurred processing the search, and an area of 7° x 7° isRequested area is too large(5° x 5° passes);relativeOrbitis a string of three digits:"022"works,22and"22"areInvalid relative orbit;- one relative orbit is ~400 bursts and ~90 GB per level.
Query
dataclass
¶
What to look for: levels, a release and at least one place.
bbox works for every level; tile is for L3; relative_orbit,
burst_cycle and swath are for L2A and L2B. product_type
narrows L3 to ORTHO-UP or ORTHO-EAST.
Hit
dataclass
¶
Search
dataclass
¶
A search id and its hits. The id is what the download URL needs.
tile_for_point ¶
tile_for_point(x: float, y: float) -> Tile
The tile containing a point in EPSG:3035 metres.
tiles_for_bounds ¶
tiles_for_bounds(minx: float, miny: float, maxx: float, maxy: float) -> list[Tile]
The tiles covering a rectangle in EPSG:3035 metres.
api_release ¶
api_release(release: str) -> str
2020_2025 (file names) or 2020-2025 → 2020-2025 (the API's form).
file_release ¶
file_release(release: str) -> str
2020-2025 or 2020_2025 → 2020_2025 (the file names' form).
tile_prefix ¶
tile_prefix(tile: Tile, component: Component, release: str) -> str
The file name up to the sub-release: EGMS_L3_E47N19_100km_U_2020_2025_.
search_body ¶
search_body(tile: Tile, component: Component, release: str) -> dict[str, Any]
The JSON body of POST {archive}/search for one Ortho L3 tile.
query_body ¶
query_body(query: Query) -> dict[str, Any]
The JSON body of POST {archive}/search for a :class:Query.
ValueError when the query has no place, which the archive would refuse.
split_bbox ¶
split_bbox(bbox: LonLatBounds, step: float = MAX_BBOX_DEG) -> list[LonLatBounds]
A box cut into pieces no larger than step degrees a side, west to east.
parse_releases ¶
parse_releases(body: bytes | str) -> list[str]
The release names, oldest first. :class:EgmsError when not logged in.
parse_names ¶
parse_names(body: bytes | str, what: str) -> list[str]
A JSON list of names (/levels, /bursts), in the archive's order.
parse_search ¶
parse_search(body: bytes | str) -> Search | None
The search, or None when the tile does not exist (sea, no coverage).
Raises :class:EgmsError for any other refusal, such as a missing login.
latest_hit ¶
latest_hit(search: Search) -> Hit | None
The hit with the highest sub-release, or None if there is none.
latest_hits ¶
latest_hits(hits: Iterable[Hit]) -> list[Hit]
One hit per file, the highest sub-release of each, in their first order.
download_url ¶
download_url(archive_url: str, hit: Hit) -> str
The URL to GET with params={"id": search.id}.
check_download ¶
check_download(status_code: int, body: bytes) -> bytes
The ZIP, or :class:EgmsError (401 means the search id expired: search again).
extract_tiff ¶
extract_tiff(archive: bytes, hit: Hit) -> bytes
The mean-velocity GeoTIFF from a tile's ZIP; the CSV is left inside.
extract ¶
extract(archive: Path, suffixes: Iterable[str], directory: Path) -> list[Path]
The files <stem>.<suffix> of a downloaded ZIP, written to directory.
Each is streamed to a .part file and renamed, so a file that exists is
whole. :class:EgmsError if the ZIP lacks one of them.