libera_utils.footprint_matching.weighting.AngularPSFWeigher#

class libera_utils.footprint_matching.weighting.AngularPSFWeigher(fov_halfangle_deg: float = 1.0, energy_fraction: float = 0.95)#

Bases: PixelWeigher

Science-accurate PSF weighting via the radiometer angular frame.

This is the CERES-faithful weigher. For each footprint it projects every sample’s (lat, lon) into the along-scan/cross-scan angular frame (delta, beta) (via libera_utils.footprint_matching.geometry.project_to_angular(), the inverse of the bounding-box ray-trace) and evaluates the analytic CERES PSF libera_utils.footprint_matching.psf.psf_weight() at each sample – so the weight a sample receives is the real, asymmetric instrument response, not a boresight-distance kernel. Because it returns the same WeightField, the aggregation engine is unchanged.

Scan direction and stationary scanner#

The CERES PSF is asymmetric along-scan (a trailing detector-response tail), so the orientation of +delta depends on the scan direction. That is read from the L1B Cone_Angle_Rate (cone_angle_rate): positive means scanning away from nadir (outward), which reverses the sign of delta (design doc section 2.8.1.2 step 5); a (near-)zero rate means the scanner is stationary at a scan turnaround, so the uniform static FOV is used instead of the dynamic PSF. The rate is therefore required, and weight_field() raises ValueError without a finite one or with a non-finite viewing zenith.

Centroid offset#

The projected delta is anchored at the reported footprint centroid (the boresight). Any residual alignment offset to the PSF centroid is _CENTROID_OFFSET_DEG, currently assumed 0 (see its LIBSDC-794 note).

Coverage#

Measured on a fine angular reference grid over the 95 %-energy contour: each finite sample covers a rectangle seen from the satellite, atan(RESOLUTION_KM / sqrt(2) / slant range) to each side cross-scan – the circumradius of its native cell (see the module docstring) – and cos(VZA) of that along-scan, where the scan plane holds the view direction and the ground cell is foreshortened. A source whose cell is wider than the contour (the 1 degree VIIRS composites) therefore scores 1.0 as soon as one sample lies in it.

Direct evaluation vs pre-integrated bins#

This uses direct per-sample PSF evaluation, which yields one weight per sample that plugs straight into WeightField. The CERES pre-integrated angular-bin scheme (ATBD Eq. 4.4-18) is a possible later optimization but needs a bin-aware aggregation path, so it is intentionally out of scope here.

param fov_halfangle_deg:

Instrument FOV half-angle used for the stationary-scanner static response and as a diagnostic radius floor. Defaults to LIBERA_FOV_HALFANGLE_DEG.

type fov_halfangle_deg:

float, optional

param energy_fraction:

PSF energy fraction defining the truncation contour. Default 0.95 (CERES heritage).

type energy_fraction:

float, optional

__init__(fov_halfangle_deg: float = 1.0, energy_fraction: float = 0.95) → None#

Methods

weight_field(samples, boresight_lat_deg, ...)

Compute the CERES-PSF WeightField for samples.

Attributes

uses_viewing_frame

Whether this weigher consumes a precomputed per-footprint viewing frame (the frame argument of weight_field()).

uses_viewing_frame: bool = True#

Whether this weigher consumes a precomputed per-footprint viewing frame (the frame argument of weight_field()). The orchestrator batches the frames up front only when this is True, so a weigher that ignores frame (the radial stand-in) pays nothing for the machinery.

weight_field(samples: SampleSet, boresight_lat_deg: float, boresight_lon_deg: float, *, subsatellite_lat_deg: float, subsatellite_lon_deg: float, satellite_radius_km: float, sample_resolution_km: float, viewing_zenith_deg: float, cone_angle_rate: float | None = None, frame: ViewingFrame | None = None) → WeightField#

Compute the CERES-PSF WeightField for samples. See class docstring.

When frame is supplied (the orchestrator batched the viewing frames up front), it is passed straight to project_to_angular(), skipping the per-footprint viewing-geometry reconstruction; the result is identical.

Raises:

ValueError – If cone_angle_rate is None or not finite (the scan direction, and so the side the PSF’s trailing tail lies on, is unknown), or if viewing_zenith_deg is not finite.