Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Catalog ↔ Patch bridge

Catalog ↔ Patch bridge — tiled inference across a real S2 archive

A CatalogDomain adapts a catalog into the Domain shape that geopatcher.SpatialPatcher consumes. Each catalog row contributes one sub-domain; the patcher iterates them. Pairing catalogs with the Patcher framework is how you scale tiled inference across a multi-file archive.

This notebook reuses the real Sentinel-2 catalog built in 01_intro (Lake Tahoe, June–July 2024) — eight scenes across the same MGRS tile. The “model” is a trivial NDVI-like rule, but the indirection it exercises is the production one: Catalog → CatalogDomain → SpatialPatcher.split → ApplyToChips → Stitch is exactly the shape a real tiled-inference pipeline takes.

1. Reuse the catalog from 01_intro

Same STAC discovery + URL collection as the intro — we use B04 (Red, 10 m) since it is the canonical 10 m grid the rest of the bands resample to.

catalog: 22 rows  bounds=(699960.0, 4290240.0, 809760.0, 4400040.0)

2. CatalogDomain — the bridge

Wrap the catalog in a CatalogDomain with a chosen target resolution. Each catalog row becomes a GeoSlice that downstream consumers (the patcher or your own inference loop) iterate.

len(domain): 22 sub-domains
domain.bounds: (699960.0, 4290240.0, 809760.0, 4400040.0)
  slice 0: bounds=(699960.0, 4290240.0, 809760.0, 4400040.0)  shape=(10980, 10980)
  slice 1: bounds=(699960.0, 4290240.0, 809760.0, 4400040.0)  shape=(10980, 10980)
  slice 2: bounds=(699960.0, 4290240.0, 809760.0, 4400040.0)  shape=(10980, 10980)
  ... (19 more)

3. Tiled per-row inference loop

The canonical pattern: iterate the catalog’s slices, load each, apply your model, and store the result. This is the multi-file equivalent of Patcher.split + ApplyToChips — but where the tiling boundary is the file boundary, not a fixed pixel stride.

AOI subset matches 22 scenes
produced 22 per-scene classifications

4. Visualise per-scene predictions

Cycle through the matching scenes and plot the water-mask classification per acquisition date.

<Figure size 6600x350 with 22 Axes>

5. Same shape, expressed as a Sequential

The per-row inference loop above is the imperative version of what in the single-raster case would be a three-op Sequential([ GridSampler, ApplyToChips, Stitch ]). The shapes line up exactly:

Single raster (RasterField)Multi-file archive (catalog)
patcher.split(field) ⇒ list of chipsdomain.slices() ⇒ list of GeoSlices
op(patch.data) per chipop(load_raster(catalog, slice)) per slice
aggregation.merge(...) ⇒ fieldconcat / write per-slice ⇒ archive

In production the catalog version typically writes per-scene predictions to S3 / GCS / a follow-up catalog rather than merging back into one giant raster — at archive scale, the “stitch step” is the catalog write.

Why this matters

The CatalogDomain is the indirection that lets the same operator pipeline work over:

  • a single in-RAM raster (via RasterField),
  • a multi-file archive (via CatalogDomain),
  • a streaming zarr accumulator (via RioXarrayField over zarr),
  • any future backend that implements the Domain Protocol.

Catalogs are a tiling for the Patcher framework — the bridge is the production-ready story for “I have ten thousand Sentinel-2 scenes; run my model across all of them and stitch the per-scene predictions into a global GeoParquet.”

See also:

  • 01_intro — the catalog build/query/load story.
  • 03_set_algebra — intersect / union over multiple catalogs (e.g. imagery × labels).
  • 04_duckdb — DuckDBGeoCatalog for archive-scale row counts (millions of rows).
  • ../patching/01_intro — the SpatialPatcher four-axis story for a single raster.