libera_utils.footprint_matching.readers.era5_surface.ERA5SurfaceReader#
- class libera_utils.footprint_matching.readers.era5_surface.ERA5SurfaceReader(file_paths: Sequence[Path])#
Bases:
ERA5ReaderBaseRead ERA5 single-level fields from a CDS NetCDF4 file.
Serves one hourly step at a time as a
(7, n_lat, n_lon)grid where axis 0 corresponds to_ERA5_SURFACE_VARIABLES/VARIABLESorder.Class Attributes#
- READER_KEYstr
Registry key
"ERA5_Surface".- RESOLUTION_KMfloat
28 km (the 0.25 degree ERA5 grid spacing at the equator).
- VARIABLEStuple[VariableSpec, …]
Seven continuous float32 variables, carried by FMATCH-IMAGER and FMATCH-IMAGER-CAMTIME.
- param file_paths:
The ERA5 single-levels NetCDF4 granule(s) covering the processing period, each containing all the variables in
_ERA5_SURFACE_VARIABLESand an hourly time axis.- type file_paths:
Sequence[Path]
Methods
nearest_step_index(time)Index of the step nearest
time, orNonebeyondMAX_TIME_OFFSET.preload()Load whatever this reader holds for the whole run, ahead of the first query.
Return every stacked product variable this reader contributes.
Return every variable this reader contributes to the product definition.
samples_in(bbox, time)Return the native samples inside
bboxthat matchtime.Attributes
The staged granule paths passed at construction, in the order given.
Number of read variables (the first axis of every
valuesarray).The one granule of a reader that reads exactly one per period.
- ADDITIONAL_PRODUCT_VARIABLES: tuple[VariableSpec, ...] = ()#
- MAX_TIME_OFFSET: timedelta64 | None = np.timedelta64(1,'h')#
- PASS_WINDOW: timedelta64 | None = None#
- PRODUCT_STACKS: tuple[ProductStack, ...] = ()#
- VARIABLES: tuple[VariableSpec, ...] = (VariableSpec(name='Wind_U10', dtype='float32', aggregation='weighted_mean', modes=frozenset({<OperationalMode.IMAGER: 'FMATCH-IMAGER'>, <OperationalMode.IMAGER_CAMTIME: 'FMATCH-IMAGER-CAMTIME'>}), n_categories=None), VariableSpec(name='Wind_V10', dtype='float32', aggregation='weighted_mean', modes=frozenset({<OperationalMode.IMAGER: 'FMATCH-IMAGER'>, <OperationalMode.IMAGER_CAMTIME: 'FMATCH-IMAGER-CAMTIME'>}), n_categories=None), VariableSpec(name='Temperature_2m', dtype='float32', aggregation='weighted_mean', modes=frozenset({<OperationalMode.IMAGER: 'FMATCH-IMAGER'>, <OperationalMode.IMAGER_CAMTIME: 'FMATCH-IMAGER-CAMTIME'>}), n_categories=None), VariableSpec(name='Dew_Point_Temperature_2m', dtype='float32', aggregation='weighted_mean', modes=frozenset({<OperationalMode.IMAGER: 'FMATCH-IMAGER'>, <OperationalMode.IMAGER_CAMTIME: 'FMATCH-IMAGER-CAMTIME'>}), n_categories=None), VariableSpec(name='Surface_Pressure', dtype='float32', aggregation='weighted_mean', modes=frozenset({<OperationalMode.IMAGER: 'FMATCH-IMAGER'>, <OperationalMode.IMAGER_CAMTIME: 'FMATCH-IMAGER-CAMTIME'>}), n_categories=None), VariableSpec(name='Surface_Geopotential', dtype='float32', aggregation='weighted_mean', modes=frozenset({<OperationalMode.IMAGER: 'FMATCH-IMAGER'>, <OperationalMode.IMAGER_CAMTIME: 'FMATCH-IMAGER-CAMTIME'>}), n_categories=None), VariableSpec(name='Forecast_Albedo', dtype='float32', aggregation='weighted_mean', modes=frozenset({<OperationalMode.IMAGER: 'FMATCH-IMAGER'>, <OperationalMode.IMAGER_CAMTIME: 'FMATCH-IMAGER-CAMTIME'>}), n_categories=None))#
- _box_samples(native: GridSamples | _PointIndex | _BoxNative, bbox: BoundingBox) tuple[ndarray, ndarray, ndarray, ndarray | None]#
Return
(lats, lons, values, times)of the native samples inside one plain box.- Raises:
TypeError – If
nativeis none of the three native forms.
- classmethod _check_product_stacks() None#
Reject a
PRODUCT_STACKSdeclaration the product could not be built from.- Raises:
TypeError – If a stack names a spec the reader does not produce, a spec is stacked twice, a stack takes the name of a product spec, a stack’s members have standard-deviation companions for some members but not others, or a stack’s members do not all have the same
modes.
- _index_points(native: PointSamples) _PointIndex#
Validate a loaded point cloud against the reader’s contract and index it.
- _load_step(index: int) GridSamples#
Load one hourly step as a global grid, longitudes -180..180, latitudes ascending.
- _native_for(time: datetime64) tuple[GridSamples, ...]#
Return the native data a query at
timedraws from; empty for no match.StaticReaderreturns its one indexed body of data regardless oftime;SteppedGridReaderthe step nearesttime, or nothing when that step is farther thanMAX_TIME_OFFSET.
- _nearest_pass_mask(times: ndarray, time: datetime64, inside: ndarray) ndarray#
Boolean mask of the samples that belong to the pass nearest
time.The nearest pass is every sample, padding included, within
PASS_WINDOWof the observation time of the sample nearesttimeamong the samplesinsidethe footprint’s own (unpadded) box, so a pass that only clips the padding, where the PSF weight is zero, cannot displace one that covers the footprint. The window is centred on that sample’s own time rather than on its offset, so two passes on either side of the footprint time are never served together. When no sample lies inside the box (a footprint smaller than one native cell), the nearest sample is taken from every served sample; on a tie, the first in array order. When its offset exceedsMAX_TIME_OFFSETno sample is kept.
- static _normalize_longitudes(ds: Dataset) Dataset#
Normalize a CDS dataset’s longitude coordinate to -180..180.
ERA5 files from the CDS can use either -180..180 or 0..360 longitude convention depending on how the download was configured. Normalizing to -180..180 means the box query (which always uses -180..180) works correctly for both.
- _padded(bbox: BoundingBox, resolution_km: float) BoundingBox#
Widen
bboxby half a native cell (resolution_km) on every side.A sample whose cell overlaps the footprint’s box belongs to the footprint even when its center lies just outside: without the padding a coarse grid (ERA5 at 0.25 degree) never serves the points whose cells cover the rim of the contour, and the weigher scores the rim as missing. The PSF weight of a sample outside the contour is zero, so padding changes no aggregated value, only the coverage.
- _read_step_layers(step: Dataset, path: Path, out: ndarray) None#
Read every single-level variable from one time step into
out.- Raises:
KeyError – If the file is missing any of the expected ERA5 variables (e.g. a download configured with only a subset of the required fields).
- _require_valid_time(time: datetime64) None#
Raise when a footprint time a time-selecting query needs is NaT.
- Raises:
ValueError – If
timeis NaT.
- _resolution_km(natives: tuple[GridSamples | _PointIndex | _BoxNative, ...]) float#
The native cell size the served samples stand for, km.
The largest spacing a loaded point cloud measured on itself, else the reader’s declared
RESOLUTION_KM. A measured spacing wins because a swath subsampled on delivery (e.g. every eighth pixel) must be credited with the cell it really stands for, not the instrument’s nominal one.
- _step_times() ndarray#
Collect every hourly step across the staged granules, ascending.
Also records where each step lives (granule, local index) for
_load_step().
- static _time_dimension(ds: Dataset, path: Path) str#
Return the name of the dataset’s time dimension (
timeorvalid_time).- Raises:
ValueError – If the file has no time-like dimension: an ERA5 CDS download always carries one, and without it a step cannot be matched to a footprint time.
- property file_paths: tuple[Path, ...]#
The staged granule paths passed at construction, in the order given.
- nearest_step_index(time: datetime64) int | None#
Index of the step nearest
time, orNonebeyondMAX_TIME_OFFSET.- Parameters:
time (np.datetime64) – A footprint time.
- Returns:
The index into the step times of the step nearest
time, orNonewhen that step is farther thanMAX_TIME_OFFSET.- Return type:
int or None
- Raises:
ValueError – If
timeis NaT, or the staged granules hold no time steps, a NaT step, or step times that are not strictly ascending.
- preload() None#
Load whatever this reader holds for the whole run, ahead of the first query.
A process pool calls this before forking so the workers share one copy of the loaded data. This base implementation loads nothing: a reader that loads by time step or pass window loads on the query that needs it.
StaticReaderoverrides it to load its whole source.
- classmethod product_stacks() tuple[ProductStack, ...]#
Return every stacked product variable this reader contributes.
Each stack in
PRODUCT_STACKS, followed by a<name>_Standard_Deviationstack of its members’ companions when its members are continuous. The stacked members leave the product as separate variables; every other spec inproduct_variable_specsstays a 1-D product variable.
- classmethod product_variable_specs() tuple[VariableSpec, ...]#
Return every variable this reader contributes to the product definition.
This is the full set of output variables – what appears, prefixed with
<READER_KEY>_, in the FMATCH product definition YAMLs and what the product/test cross-check is built against. It is distinct fromVARIABLES(the smaller set actually read from the source file) and is composed of, in order:each read variable in
VARIABLES;a
<name>_Standard_Deviationcompanion for every continuous (mean-aggregated) read variable, inserted right after its parent bywith_standard_deviation_companions();any reader-specific derived outputs declared in
ADDITIONAL_PRODUCT_VARIABLES(e.g. IGBP ranked scenes).
- samples_in(bbox: BoundingBox, time: datetime64) SampleSet#
Return the native samples inside
bboxthat matchtime.- Parameters:
bbox (BoundingBox) – The footprint’s geographic box, widened by half a native cell (
RESOLUTION_KM) on every side so a sample whose cell overlaps the box is served. A box that wraps the antimeridian (given in the [0, 360) form) is split and both halves served.time (np.datetime64) – The footprint’s observation time (radiometer or camera time). Ignored by a
DAILYreader.
- Returns:
The selected samples; zero samples when the box holds none, or when no sample lies within
MAX_TIME_OFFSEToftime.- Return type:
- Raises:
ValueError – If
timeis NaT and this reader selects in time; if more than one granule is staged for a reader that reads one per period; if the loaded data carries a different number of variables thanVARIABLES; if a stepped reader’s step times are empty, hold a NaT or are not strictly ascending; or if aNEAREST_PASSreader serves samples without per-sample times.TypeError – If the reader’s native data is none of
GridSamples,PointSamplesor a box-queried native.
- property single_file_path: Path#
The one granule of a reader that reads exactly one per period.
- Raises:
ValueError – If more than one granule was staged for this reader.