surface-priors builds native-grid surface prior products and persists them as a STAC Item with tiled, DEFLATE-compressed GeoTIFF assets. The current implementation provides a MODIS/VIIRS BRDF prior builder; the package boundary is intentionally broader so later providers can add direct surface reflectance priors from sensors such as Sentinel-2 or Landsat.
Calendar planning is intentionally outside the core builder: callers decide which observations should enter a prior, then this package composites those observations and writes a consistent product.
import numpy as np
from surface_priors import Observation, Provider, ProviderConfig
from surface_priors.sources import InMemorySource
obs = Observation(
data=np.ones((1, 2, 2), dtype="float32") * 0.25,
quality=np.zeros((2, 2), dtype="uint16"),
uncertainty=np.ones((1, 2, 2), dtype="float32") * 12,
band_names=("brdf_iso_red",),
)
provider = Provider(
ProviderConfig(
cache_dir=".surface-cache",
source=InMemorySource((obs,), name="example"),
)
)
product = provider.build_prior(
product_id="example-brdf-prior",
wgs84_bounds=(-1.0, 51.0, -0.99, 51.01),
resolution=500.0,
band_names=("brdf_iso_red",),
composite_period="2024-07",
)The output directory contains:
<cache-root>/<request-hash>/
stac-item.json
assets/
prior/
2024-07/
brdf_iso_red.tif
uncertainty/
2024-07/
brdf_iso_red.tif
Implemented now:
- MODIS/VIIRS BRDF prior fetching through Google Earth Engine or Earthaccess-backed sources.
- Native-grid best-pixel BRDF compositing and quality tie-breaking.
- STAC/GeoTIFF persistence with a generic
surface:*metadata namespace.
Planned extension point:
- Direct surface reflectance prior sources such as Sentinel-2 or Landsat, provided they can deliver observations aligned to the requested native grid.
This package owns:
- WGS84 AOI bounds conversion into the native prior data CRS.
- Google Earth Engine BRDF product downloading through
edown. - Native-grid best-pixel compositing from caller-supplied prior observations.
- Source quality and sample-index tie-breaking, currently implemented for BRDF products.
- Relative uncertainty propagation or fallback estimation.
uint16prior encoding with scale factor10000and nodata65535.uint8relative uncertainty encoding in percent from0to200; values above200%, negative values, and non-finite values are stored as255.- One-band tiled, DEFLATE-compressed GeoTIFF persistence optimized for remote chunked reads, without overviews.
- STAC Item creation with
projectionandrasterextension metadata.
Callers own:
- Which observations to use for a prior.
- Any observation-day, month, season, or year logic.
- The optional
composite_periodlabel, such as2024-07, when assets should carry a monthly path segment. - NASA/Earthdata search policy and temporal filtering.
- SIAC atmospheric correction, SWIR refine routing, spectral mapping, and downstream
SurfacePriorconstruction.
The public AOI input is always WGS84 longitude/latitude bounds: (west, south, east, north). The package converts those bounds to the configured native prior data CRS, which defaults to MODIS/VIIRS Sinusoidal for BRDF sources. The builder still does not reproject source arrays internally; observations must already match the derived native grid.
pip install surface-priorsOptional Earthdata search support:
pip install "surface-priors[earthdata]"Optional Google Earth Engine download support through edown:
pip install "surface-priors[gee]"Optional experiment dependencies for the GEE-vs-official comparison:
pip install "surface-priors[experiments]"Development install:
python -m pip install -e ".[dev,docs]"
pytestThe built-in GEE preset uses edown to download MODIS/061/MCD43A1 native-grid GeoTIFF observations. By default it requests iso, vol, and geo BRDF coefficients for red, green, blue, NIR, SWIR1, and SWIR2. The caller still supplies explicit temporal ranges; this package does not decide which days, months, or history windows to use. To reduce downloads, pass sample_every_days to query one-day windows at a fixed stride inside each temporal range.
from surface_priors import Provider, ProviderConfig
from surface_priors.sources import EdownGeeSource
source = EdownGeeSource.for_product(
"mcd43a1",
temporal_ranges=(("2024-07-01", "2024-07-31"),),
sample_every_days=7,
output_root=".surface-gee-cache",
)
provider = Provider(ProviderConfig(cache_dir=".surface-cache", source=source))
product = provider.build_prior(
product_id="mcd43a1-prior",
wgs84_bounds=(-2.0, 51.0, -1.0, 52.0),
resolution=500.0,
composite_period="2024-07",
)With sample_every_days=7, the July range above queries 2024-07-01,
2024-07-08, 2024-07-15, 2024-07-22, and 2024-07-29 instead of every
matching image in the month.
edown handles Earth Engine authentication using GEE_SERVICE_ACCOUNT/GEE_SERVICE_ACCOUNT_KEY, existing Earth Engine user credentials, or Google Application Default Credentials.
surface-priors build \
--product-id example-brdf-prior \
--wgs84-bounds -1.0 51.0 -0.99 51.01 \
--resolution 500 \
--band brdf_iso_red \
--composite-period 2024-07 \
--local-observations observations.json \
--cache-dir .surface-cacheGEE MCD43A1 through edown:
surface-priors build \
--product-id mcd43a1-prior \
--gee-product mcd43a1 \
--temporal-range 2024-07-01 2024-07-31 \
--sample-every-days 7 \
--composite-period 2024-07 \
--wgs84-bounds -2.0 51.0 -1.0 52.0 \
--resolution 500 \
--cache-dir .surface-cache \
--edown-output-root .surface-gee-cacheobservations.json points to local native-grid NPZ observations used as input, not as output:
{
"name": "example",
"band_names": ["brdf_iso_red"],
"items": [
{
"path": "obs.npz",
"data_key": "data",
"quality_key": "quality",
"uncertainty_key": "uncertainty",
"sample_index_key": "sample_index"
}
]
}The repository includes GitHub Actions workflows for tests, package build checks, PyPI trusted publishing on GitHub releases, and MkDocs Material deployment to GitHub Pages.