Configuration#

EOMatch reads all runtime parameters from YAML configuration files. The system uses three layers, each merged on top of the previous:

package defaults          (eomatch/etc/default_config.yaml — do not edit)
     ↓
user config               (~/.config/eomatch/user_config.yaml)
     ↓
per-run override          (passed via --config on any CLI command)

You only need to supply the keys you want to override — everything else falls back to the package defaults.

Initialising the user config#

Run eomatch-init once after installation to create your user config:

eomatch-init

This writes a fully-commented template to ~/.config/eomatch/user_config.yaml. Running it again is safe — it will not overwrite an existing file unless you delete it first.

EOMatch also initialises the config automatically on first import, so the file will exist even if you never call eomatch-init explicitly.

Config file sections#

STAC catalogue (matchup_catalogue)#

Controls where eomatch stores and reads its catalogue. Used by every CLI command and by MatchupCatalogue directly.

matchup_catalogue:
  path: /data/my_catalogue   # root directory for the catalogue on disk
  id: matchup-catalogue      # STAC catalogue ID
  description: Matchup catalogue
  auto_remove_corrupted: false   # see "Handling corrupted or missing matchup files" in :ref:`catalogue`

path can be omitted from the user config and passed at run time instead (--path on the CLI, or as a constructor argument in Python).

If path already contains a saved catalogue, constructing MatchupCatalogue reopens it — preserving its existing collections and items — rather than starting a new, empty one. This lets a catalogue be built up incrementally across multiple runs by re-constructing (or calling save() again) with the same path.

auto_remove_corrupted controls what happens when get_events() finds a matchup or event item it can’t read (a missing or corrupted JSON file). The default, false, just logs a warning and skips it. Set it to true to have remove_matchup() called automatically instead, cleaning the broken matchup out of the catalogue as soon as it’s found rather than warning on every subsequent read.

Satellite finder settings#

These flat keys are used by Sat2SatMUFinder and the eomatch-find command. They are most naturally placed in a per-run --config file alongside matchup_catalogue.path, though you can set defaults for platforms and collections in your user config if you always work with the same sensor pair.

# Which satellites and collections to match — order must correspond.
platforms: Sentinel-2A, Landsat-9
collections: S2_MSI_L1C, LANDSAT_C2L1

# Search time window (format: "YYYY-MM-DD HH:MM:SS").
start_time: "2023-01-01 00:00:00"
end_time:   "2023-12-31 23:59:59"

# Spatial filter — omit or leave blank to search globally.
min_lat: 45.0
max_lat: 55.0
min_lon: -5.0
max_lon: 10.0

# Additional event filters (both optional, default false).
exclude_antimeridian_events: false   # drop bboxes spanning > 180° of longitude
exclude_night_events: false          # drop events entirely outside local daytime
                                      # at the site (requires min_lon/max_lon)

# Pin a specific eodag provider per collection (optional). eodag disables
# its usual try-every-provider-in-priority-order fallback whenever a
# provider is pinned, so this is useful for skipping providers known to be
# slow, unauthenticated, or unavailable for a collection. Collections
# without an entry keep eodag's normal fallback behaviour. A misconfigured
# provider name fails silently (no results) rather than raising, since
# fallback is disabled for that collection.
provider_by_collection:
  S2_MSI_L1C: cop_dataspace
  LANDSAT_C2L1: usgs

Orbit crossover detection is handled by orbitx. The NetCDF path is resolved in the following priority order:

Option A — per-combo NetCDF files (recommended when working with multiple satellite pairs). Keys use the platform-aware combo ID format produced by _matchup_collection_id():

orbitx_netcdf_files:
  LANDSAT_C2L1-Landsat-9-vs-S2_MSI_L1C-S2A: /path/to/LS9_S2A.nc
  LANDSAT_C2L1-Landsat-8-vs-S2_MSI_L1C-S2B: /path/to/LS8_S2B.nc

Option B — single pre-computed NetCDF (flat fallback; used when no per-combo entry is found in orbitx_netcdf_files):

orbitx_netcdf_path: /path/to/crossovers.nc

orbitx_netcdf_path may contain Python format-string placeholders (e.g. {year}, {platforms}), letting one config path resolve to a different cache file per run without needing an orbitx_netcdf_files entry for every combination:

orbitx_netcdf_path: /data/orbitx/{year}/{platforms}.nc
# resolves to e.g. /data/orbitx/2023/S2A_LS9.nc

Option C — run orbitx from scratch (used when neither A nor B is set):

propagation_sampling_interval: 30     # satellite position step (seconds)
interpolation_sampling_interval: 1    # crossover refinement step (seconds)
space_diff_threshold: 100.0           # max cross-track distance (km)
time_diff_threshold: 1800             # max time difference (seconds)
check_before: false
check_after: false
has_land_ocean_mask: false
custom_satellites:                    # blank for standard TLEs
dump_orbit: false

Scientific dataset reading (read)#

Controls how BuildMUDT reads products via eoio. The package defaults request no bands (meas: []) so you must configure this section to get any data out of return_matchup_dataset().

read:
  defaults:
    vars_sel:
      meas: []       # band selection — list of band IDs, or "rgb" sentinel
      aux: []        # auxiliary variables
    read_params:
      use_chunks: false
      metadata_level: true
      save_extracted: false
    processors: {}

  # Per-collection overrides — merged on top of defaults above.
  collections:
    LANDSAT_C2L1:
      vars_sel:
        meas: [B2, B3, B4, B5]
    S2_MSI_L1C:
      vars_sel:
        meas: [B02, B03, B04, B8A]

vars_sel and processors are replaced wholesale at each level; read_params keys are merged individually so you can override a single parameter without losing the rest.

Cropping to the shared valid-data extent#

Products’ native grids commonly only partially overlap and/or carry NaN padding well beyond their actual footprint (e.g. a diagonal swath inside a larger rectangular tile). Every gridded product in a matchup is cropped to the lat/lon bounding box where all of them have valid measurement data, before assembling the DataTree — on by default, and overridable per call via return_matchup_dataset(). Set crop_to_shared_valid_extent: false to disable it:

read:
  crop_to_shared_valid_extent: false

Deriving lat/lon for a product that only has a projected grid + CRS (not lat/lon directly) requires the optional spatial extra (pip install eomatch[spatial]); without it, such a product is left uncropped rather than this setting having no effect at all.

Preview reading (preview.read)#

Controls how BuildMUPreview reads products when generating preview images. Kept separate from read so that lightweight preview reads do not affect scientific dataset builds.

The package default requests only the RGB bands with metadata disabled. The "rgb" sentinel is resolved by eoio to the natural-colour bands for each collection (B02/B03/B04 for S2, B2/B3/B4 for Landsat).

preview:
  read:
    defaults:
      vars_sel:
        meas: rgb     # must be a string, not a list
        aux: []
      read_params:
        use_chunks: false
        metadata_level: false
        save_extracted: false
      processors: {}
    collections: {}

Per-run config files#

All CLI commands accept --config PATH to load an additional YAML file on top of your user config. This is the recommended way to supply run-specific settings (time range, platforms, catalogue path) without modifying your persistent user config:

eomatch-find --config my_run.yaml
eomatch-download --config my_run.yaml
eomatch-preview /data/my_catalogue/catalog.json --config my_run.yaml

A minimal per-run file typically looks like:

platforms: Sentinel-2A, Landsat-9
collections: S2_MSI_L1C, LANDSAT_C2L1
start_time: "2023-06-01 00:00:00"
end_time:   "2023-06-30 23:59:59"
orbitx_netcdf_path: /data/orbitx/2023_S2A_LS9.nc

matchup_catalogue:
  path: /data/my_catalogue

See example/find_and_catalogue.yaml in the repository for a fully annotated example.

Configuring from Python#

Pass a path or a dict directly to EOMatchContext:

from eomatch import EOMatchContext

# Load from a YAML file (merged on top of user config)
ctx = EOMatchContext("my_run.yaml")

# Or pass overrides as a dict
ctx = EOMatchContext({
    "platforms": "Sentinel-2A, Landsat-9",
    "collections": "S2_MSI_L1C, LANDSAT_C2L1",
    "matchup_catalogue": {"path": "/data/my_catalogue"},
})