msi_processor.computing.toa package#

TOA radiance/reflectance stage (C-PU-TOA; DPM-M-TOA; ALG-TOA-RAD/REF).

DN->TOA radiance (mandatory) and optional DN->TOA reflectance, emitting the L1B product. The stage is a pure core plus a thin ToaUnit wrapper.

Submodules#

msi_processor.computing.toa.core module#

Pure TOA radiance/reflectance core (C-PU-TOA; ALG-TOA-RAD/REF).

CPM-free, I/O-free numpy/math functions implementing the TOA algorithms of ATBD <5.3>, ported faithfully from the heritage level_1.py TOA class (dn_to_radiance / toa_rad_to_ref / get_ESUN / get_sun_el_esdist; RD-10). All arrays are processed in float32 (REQ-F-DEP-02, REQ-D-05).

Two heritage simplifications are corrected here (ATBD <5.3> open points):

  • the per-image radiance -= radiance.min() rebasing is dropped (not radiometrically rigorous); and

  • solar geometry is no longer derived from the satellite sub-point through a GPL pyorbital TLE fetch. solar_geometry() is a dependency-free NOAA solar-position computation and earth_sun_distance() a closed form, so the GPL dependency is removed (SRF SRF-RU-HER-TOA); at run time the unit takes illumination geometry from L0c telemetry / ADF per the ICD.

Private calibration constants (per-band ESUN, radiometric gain/offset) are never embedded; they are supplied to these functions by the wrapper from the radiometric / spectral ADFs (REQ-AD-01).

Geometry convention: arrays are 2-D (line, detector) in focal-plane geometry; per-detector gain/offset are 1-D (detector,) vectors broadcast across lines (ATBD <4.2>, SDD <5.4.5>).

Trace: REQ-F-TOA-01..03; DPM-M-TOA; ALG-TOA-RAD/REF.

class msi_processor.computing.toa.core.TOAParams(emit_reflectance=False, fill_value=None)#

Bases: object

Tunable TOA parameters (SDD <5.4.5>; DPM-PRM-TOA-03).

Parameters:
emit_reflectance:

When True the optional radiance->TOA-reflectance stage is run in addition to the mandatory DN->radiance stage (REQ-F-TOA-02, DPM-PRM-TOA-03).

fill_value:

No-data sentinel radiance; flagged QAFlag.NO_DATA when present.

Attributes:
fill_value
emit_reflectance: bool = False#
fill_value: Optional[float] = None#
msi_processor.computing.toa.core.dn_to_radiance(dn, gain, offset)#

ALG-TOA-RAD — convert corrected DN to at-sensor (TOA) radiance.

Linear inversion of the radiometric model (heritage TOA.dn_to_radiance): :rtype: ndarray[tuple[Any, ...], dtype[float32]]

\[L^{(b)}_{l,d} = \big(\mathrm{DN}^{(b)}_{l,d} - o^{\mathrm{rad},(b)}\big) \, g^{\mathrm{rad},(b)} .\]

gain/offset are the absolute radiometric coefficients from the radiometric ADF; they may be per-band scalars or 1-D (detector,) vectors broadcast across lines.

Notes

The heritage per-image radiance -= radiance.min() rebasing is not applied (ATBD <5.3>, open point); negative/no-data handling is deferred to flag_radiance(). Returns float32.

msi_processor.computing.toa.core.earth_sun_distance(doy)#

Earth-Sun distance in AU from the day-of-year (ATBD <5.3>). :rtype: float

\[d_{\mathrm{ES}} \approx 1 - 0.01672\, \cos\!\big(0.9856^\circ\,(\mathrm{DOY}-4)\big),\]

a closed-form approximation (perihelion near DOY 4). A solar ephemeris may be substituted via solar_geometry()’s caller when sub-second accuracy is required.

msi_processor.computing.toa.core.flag_radiance(radiance, params)#

Floor non-physical radiance and flag no-data (SDD <5.4.5> error handling).

Non-finite samples (e.g. from a non-finite gain) and any equal to params.fill_value are flagged QAFlag.NO_DATA; the data is then floored at 0 (radiance is non-negative by definition, ICD <5.3.3>B; the upper bound is physical, not the DN ceiling, so no top clip is applied). Mirrors the radiometric flag_saturation contract.

Return type:

tuple[ndarray[tuple[Any, ...], dtype[float32]], ndarray[tuple[Any, ...], dtype[uint16]]]

Returns:
tuple of ndarray

(floored[float32], qa[uint16]) of the same shape as radiance.

msi_processor.computing.toa.core.radiance_to_reflectance(radiance, esun, sun_zenith_rad, earth_sun_dist_au)#

ALG-TOA-REF — convert TOA radiance to TOA reflectance.

The canonical solar normalisation (heritage TOA.toa_rad_to_ref): :rtype: ndarray[tuple[Any, ...], dtype[float32]]

\[\rho^{(b)}_{\mathrm{TOA}} = \dfrac{\pi\,L^{(b)}\,d_{\mathrm{ES}}^{\,2}}{E^{(b)}_{\mathrm{SUN}} \,\cos\theta_s} ,\]

with esun the band-integrated exo-atmospheric solar irradiance \(E_{\mathrm{SUN}}\) (spectral ADF / profile), earth_sun_dist_au the Earth-Sun distance \(d_{\mathrm{ES}}\) in AU at acquisition, and sun_zenith_rad the solar zenith angle \(\theta_s\) in radians. The result is clipped to [0, 1] (REQ-D-05). Returns float32.

msi_processor.computing.toa.core.solar_geometry(acq_time, lon, lat)#

Solar zenith/azimuth from acquisition time and sub-point (NOAA algorithm).

A dependency-free implementation of the NOAA solar-position algorithm, replacing the heritage satellite-sub-point conflation that relied on the GPL pyorbital TLE fetch (ATBD <5.3> open point; SRF SRF-RU-HER-TOA).

Return type:

tuple[float, float]

Parameters:
acq_time:

Acquisition time in UTC (naive datetimes are treated as UTC).

lon, lat:

Sub-point longitude/latitude in degrees (east/north positive).

Returns:
tuple of float

(sun_zenith_rad, sun_azimuth_rad) with azimuth measured clockwise from geographic north.

msi_processor.computing.toa.unit module#

Thin EOProcessingUnit wrapper for TOA radiance/reflectance (C-PU-TOA).

Adapts the pure core to the EOPF CPM runtime following the wrapper template of SDD <5.4.1>/<5.4.5>: read parameters, extract input bands, load/validate ADFs, call the core per band, propagate QA, and build the output L1B EOProduct. No algorithm lives here.

Mandatory inputs/ADFs are declared by the CPM computing-model JSON (models/msi_toa_1.0.0.json), not by overriding the list methods.

Input convention (this increment). The upstream stage is the mandatory enhancement unit; since it is not yet implemented, this unit accepts the corrected/enhanced bands product under input key enh carrying corrected DN under measurements/detector/<band> and QA under quality/mask/<band> (IF-PROD-02) – exactly the shape the radiometric unit emits, which will feed enhancement once it lands.

ADF data convention (this increment). The unit reads ADF content from the AuxiliaryDataFile.data_ptr mapping (the CPM data_ptr is documented as holding the opened data):

  • radiometric -> {"gain": {band: float|ndarray1d}, "offset": {band: ...}} (mandatory; absolute radiometric coefficients, ICD <5.3.2>A)

  • spectral -> {"esun": {band: float}} (required only when emit_reflectance is set)

Illumination geometry (solar zenith, Earth-Sun distance) is taken from the run kwargs sourced from L0c telemetry / ADF per the ICD (the GPL pyorbital TLE fetch is dropped, SRF SRF-RU-HER-TOA); the proper solar ephemeris solar_geometry() is available for the caller and will be wired to telemetry plumbing once it lands.

Trace: REQ-F-TOA-01..03; DPM-M-TOA; ALG-TOA-RAD/REF; ICD IF-PROD-03.

class msi_processor.computing.toa.unit.ToaUnit(identifier='')#

Bases: EOProcessingUnit

TOA radiance/reflectance processing unit (C-PU-TOA; SDD <5.4.5>).

Attributes:
identifier

Identifier of the processing step

Methods

run:

Convert corrected DN to TOA radiance (mandatory) and optional TOA reflectance, and emit the L1B product.

PROCESSOR_LEVEL = 'L1B'#
PROCESSOR_MODEL = True#
PROCESSOR_NAME = 'msi_toa'#
PROCESSOR_VERSION = '1.0.0'#
run(inputs, adfs=None, mode=None, **kwargs)#

Run the TOA conversion.

Return type:

Mapping[str, Union[EOProduct, EOContainer, DataTree, Iterable[Union[EOProduct, EOContainer, DataTree]]]]

Parameters:
inputs:

{"enh": EOProduct} with bands under measurements/detector and optional QA under quality/mask.

adfs:

radiometric (mandatory; gain/offset); spectral (required only when emit_reflectance is set; per-band ESUN).

mode:

"nominal" (the only supported mode).

**kwargs:

TOAParams fields (emit_reflectance, fill_value); illumination geometry for reflectance (sun_zenith_rad or sun_zenith_deg; earth_sun_distance_au or day_of_year); optional name for the output product.

Returns:
Mapping[str, DataType]

{"l1b": EOProduct} with measurements/radiance/<band> (+ measurements/reflectance/<band> when requested) and quality/mask/<band>.