Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

radiomax: observation geometry and radiometry for JAX

radiomax converts and locates what a sensor saw: solar and viewing angles per pixel, the Earth–Sun distance, the conversions from counts to radiance to reflectance, Planck and brightness temperature, the geometric air-mass factor, parallax and geostationary navigation, swath and bowtie geometry, and the empirical retrievals applied pixel by pixel. It sits at GeoNumerics tier 1 and has no state to retrieve; radiative transfer, which does, is radtrax’s. Status: proposed, at design-sketch depth.

At a glance

Layer, tierGeoNumerics, tier 1
Importsgeophysix, integrix; JAX, NumPy
Imported byradtrax, plumax; geoops, geoproducts
Takes overgeoops radiometry (counts, radiance, reflectance, a scene-centre solar zenith, Earth–Sun distance, brightness temperature, dark-object subtraction); the bowtie and parallax maths in geoops geom; the despeckling filters in geoops restore; the brightness-temperature copies in geoproducts; the geometric air-mass factors in radtrax and plumax; geostationary navigation from geoproducts
Does not ownradiative transfer and full air-mass factors (radtrax); spectral indices (geoops); SRF tables (georeader); cell corners and areas of a swath (gridax)
Statusproposed; no repository yet
Tracked inthe layer map and its section “radiomax and radtrax: where the line is”; the companion geophysix and integrix designs
where radiomax sits · GeoNumerics tier 1

Where radiomax sits · geonumerics tier 1.

The test that places a name, from the layer map: does it need a model of radiation moving through the atmosphere? Then it is radtrax’s. Is it geometry, a unit conversion, or an empirical formula with fitted coefficients applied pixel by pixel? Then it is radiomax’s. The import goes one way, radtrax to radiomax. This page is the design; core types, algorithms and the code survey are in radiomax: design details.

The problem

Before a matched filter or a retrieval sees a methane pixel, the scene is calibrated, located and converted, and each of those steps is coded more than once:

StepWhat it computesWhere it is coded today
Counts to radianceL = g · DN + o, with a gain and offset per bandgeoops dn_to_radiance and DNToRadiance; geoproducts’ Himawari _calibrate and GOES calibration_coefficients
Radiance to top-of-atmosphere reflectanceρ = π L d² / (E₀ cos θₛ)geoops RadianceToReflectance, earth_sun_distance_correction_factor, compute_sza; and lazy calls into georeader.reflectance
The geometric air-mass factor of the target signatureAMF = 1 / cos θₛ + 1 / cos θᵥradtrax atmosphere/geometry.py; plumax hapi_lut/beers.py and its radtran config
Cloud screening in the thermal bands of GOES and Himawaribrightness temperature from radiancegeoops bt_from_radiance; geoproducts’ Himawari _brightness_temperature; geoproducts’ GOES L1B formula
Where a plume at height H really is, seen from geostationary orbitparallax and fixed-grid navigationgeoops GeostationaryParallaxCorrect; geoproducts _src/geostationary.py
VIIRS and MODIS scan geometrybowtie detector positionsgeoops bowtie_detector_positions and BowtieCorrection

Brightness temperature is written three times in geotoolz and the geometric air-mass factor three times across radtrax and plumax. The rest lives inside geoops Operators, so radtrax and plumax, which sit on plain arrays, cannot reuse it without importing a GeoStack toolkit; they copy it instead.

Angles, units and fitted formulas

Everything radiomax computes is a function of a pixel’s position, the time, the sensor and a few coefficients. None of it follows light through the air.

Solar geometry. With δ the solar declination and ω the hour angle at time t, the solar zenith angle θₛ at latitude φ is

cos⁡θs=sin⁡φsin⁡δ+cos⁡φcos⁡δcos⁡ω\cos\theta_s = \sin\varphi \sin\delta + \cos\varphi \cos\delta \cos\omega

and the Earth–Sun distance d(t), in astronomical units, scales the solar irradiance by 1 / d².

Viewing geometry. From the satellite’s position s and the pixel’s position p, both in Earth-centred coordinates from geophysix, the line of sight is s − p; its angle from the local vertical is the view zenith θᵥ, and its direction in the local east–north plane is the view azimuth. The relative azimuth and the scattering angle follow from the solar and viewing directions.

Radiometry. Counts become radiance through a gain g and offset o, and radiance becomes top-of-atmosphere reflectance through the band’s solar irradiance E₀:

L=g⋅DN+oL = g \cdot DN + o
ρTOA=πLd2E0cos⁡θs\rho_{\mathrm{TOA}} = \frac{\pi L d^2}{E_0 \cos\theta_s}
E0=∫E⊙(λ)R(λ)dλ∫R(λ)dλE_0 = \frac{\int E_\odot(\lambda) R(\lambda) d\lambda}{\int R(\lambda) d\lambda}

with R(λ) the band’s spectral response; the two integrals are an integrix rule.

Thermal bands. Planck’s law gives the radiance of a black body at temperature T, with h, c and k_B from geophysix:

B(λ,T)=2hc2λ51exp⁡(hc/(λkBT))−1B(\lambda, T) = \frac{2 h c^2}{\lambda^5} \frac{1}{\exp(h c / (\lambda k_B T)) - 1}

A sensor’s brightness temperature inverts it with band coefficients; GOES, for one, publishes T = (fₖ₂ / ln(fₖ₁ / L + 1) − b₁) / b₂.

Geometric air-mass factor. The path length through a plane-parallel atmosphere, down to the surface and back up to the sensor, relative to the vertical:

AMF=1cos⁡θs+1cos⁡θv\mathrm{AMF} = \frac{1}{\cos\theta_s} + \frac{1}{\cos\theta_v}

The full air-mass factor, with scattering weights per layer, is radtrax’s.

Parallax. A cloud or plume at height H, seen at view zenith θᵥ, appears displaced along the view azimuth by H tan θᵥ; geostationary navigation maps a sensor’s scan angles to latitude and longitude on geophysix’s ellipsoid.

Empirical retrievals. Formulas with fitted coefficients, applied pixel by pixel: split-window sea- and land-surface temperature from two thermal bands, SST = a₀ + a₁ T₁₁ + a₂ (T₁₁ − T₁₂) + a₃ (sec θᵥ − 1); ocean-colour band ratios; and kernel BRDF, R = f_iso + f_vol K_vol + f_geo K_geo, with fixed Ross–Li kernels and fitted weights.

Modules and boundaries

Six modules. Each takes plain arrays (angles, radiances, coefficients) and returns plain arrays; sensor metadata such as calibration coefficients and spectral responses arrive as arguments from the readers.

ModuleOwnsComes from
radiomax.geometrysolar position and zenith, Earth–Sun distance, viewing angles, relative azimuth and scattering angle, parallax, geostationary navigation, swath and bowtie scan geometrygeoops compute_sza, earth_sun_distance_correction_factor, bowtie_detector_positions, the maths of GeostationaryParallaxCorrect; geoproducts _src/geostationary.py
radiomax.radiometrycounts to radiance and back, radiance to reflectance and back, band solar irradiance, the geometric air-mass factor, dark-object subtraction and empirical-line correctiongeoops dn_to_radiance, radiance_to_dn, dn_to_reflectance, dos1, SimpleAtmosphericCorrection; the lazy georeader.reflectance calls; radtrax’s and plumax’s air_mass_factor
radiomax.thermalPlanck’s law, brightness temperature and its inverse, from band coefficients or a spectral responsegeoops bt_from_radiance; geoproducts’ Himawari _brightness_temperature and GOES L1B formula
radiomax.retrievalssplit-window SST and LST, ocean-colour ratios, Ross–Li BRDF and NBARnew
radiomax.sarSAR calibration to σ⁰, Lee, refined Lee and Frost despecklinggeoops despeckle_lee, despeckle_refined_lee, despeckle_frost
radiomax.altimetryaltimetry range corrections (tropospheric, ionospheric, inverse barometer)new

What radiomax owns, and what it hands off

Neighbourradiomax ownsThe neighbour ownsThe line
radtraxangles, unit conversions, the geometric air-mass factor, Planck with band coefficientsradiative transfer, spectroscopy, full air-mass factors, the instrument model that convolves a modelled spectrum with an SRF, methane retrievalsdoes it need radiation moving through an atmospheric state? Then radtrax
geoopsthe mathsOperators on GeoArray, spectral indices, masksgeoops’ radiometry Operators stay and call radiomax
geoproductsnavigation and brightness-temperature mathsreaders, file formats, the calibration coefficients as metadataa reader passes its coefficients to radiomax
georeadernothing of its ownthe SRF tables, read-only (spaceml-org’s)SRFs arrive as arrays; radiomax does not import georeader
geophysixsensor geometrythe Earth, its constants, h, c, k_Bradiomax reads geophysix for every constant
gridaxthe scan geometry of a swaththe cell corners and areas of a swath gridhow a sensor scanned is radiomax’s; the grid it produced is gridax’s
integrixwhich integral a band needsthe rule that computes itband irradiance is an ix.rule over the SRF

What moves in

FromWhatIts users then import
geoops radiometrythe array functions in _src/array.py and _src/solar.pyradiomax; the Operators stay in geoops and call it
geoops geom, restorebowtie and parallax maths; the despeckling filtersradiomax; the Operators stay
geoproductsHimawari and GOES brightness temperature; geostationary navigation mathsradiomax; the readers and geos_crs stay
radtrax, plumaxthree air_mass_factor copiesradiomax.radiometry
geoops (via georeader)the lazy georeader.reflectance callsradiomax, with georeader as a test reference

In use

A methane scene from counts to the inputs a matched filter needs: angles, reflectance, the air-mass factor of the target signature, and a brightness temperature for cloud screening. Every radiomax name is proposed.

# Shapes: B bands; Ny × Nx pixels; W wavelengths of the spectral responses

import geophysix as gpx
import radiomax as rmx

# --- angles ---
# proposed (radiomax)
# cos θₛ = sin φ sin δ + cos φ cos δ cos ω
solar_zenith = rmx.geometry.solar_zenith(lat, lon, time)  # (Ny, Nx) → (Ny, Nx)
# proposed (radiomax)
# θᵥ = angle between the line of sight s − p and the local vertical
view_zenith = rmx.geometry.view_zenith(  # (Ny, Nx) → (Ny, Nx)
    lat, lon, satellite_position, earth=gpx.earth.WGS84
)
# proposed (radiomax)
# d(t), in astronomical units
distance = rmx.geometry.earth_sun_distance(time)  # → ()

# --- counts to reflectance ---
# proposed (radiomax)
# L = g · DN + o, per band
radiance = rmx.radiometry.counts_to_radiance(counts, gain, offset)  # (B, Ny, Nx)
# proposed (radiomax)
# E₀ = ∫ E⊙ R dλ / ∫ R dλ, an integrix rule over each response
irradiance = rmx.radiometry.band_irradiance(  # (W,), (B, W) → (B,)
    solar_spectrum, responses, wavelength
)
# proposed (radiomax)
# ρ = π L d² / (E₀ cos θₛ)
reflectance = rmx.radiometry.reflectance(  # (B, Ny, Nx) → (B, Ny, Nx)
    radiance, irradiance, solar_zenith, distance
)

# --- what the matched filter and the cloud screen need ---
# proposed (radiomax)
# AMF = 1 / cos θₛ + 1 / cos θᵥ
air_mass = rmx.radiometry.air_mass_factor(solar_zenith, view_zenith)  # → (Ny, Nx)
# proposed (radiomax)
# T = (fₖ₂ / ln(fₖ₁ / L + 1) − b₁) / b₂
brightness = rmx.thermal.brightness_temperature(  # (Ny, Nx) → (Ny, Nx)
    thermal_radiance, coefficients
)

radtrax takes solar_zenith, view_zenith and air_mass as inputs to its forward model and builds the target signature from them; nothing in this block models the atmosphere.

Integration across the stack

Four libraries would import radiomax. geoops and geoproducts keep their Operators and readers and call radiomax inside them; radtrax and plumax drop their copies.

ConsumerUses todayWith radiomax
radtraxits own geometric air_mass_factor; angles passed in by the callerradiomax.radiometry.air_mass_factor; angles from radiomax.geometry; keeps radiative transfer and the instrument model
plumaxair_mass_factor in hapi_lut/beers.py and its radtran configradiomax
geoopsradiometry array functions, bowtie and parallax maths, despeckling filters, lazy georeader.reflectance callsthe same Operators, calling radiomax; the georeader calls go
geoproductsHimawari and GOES brightness temperature; geostationary navigationradiomax inside the readers; the calibration coefficients stay reader metadata

For a geoops user nothing changes; for a library below GeoStack the import moves down:

# Today:
# today (geoops)
from geoops.radiometry import bt_from_radiance

# After:
# proposed (radiomax)
from radiomax.thermal import brightness_temperature

geoops keeps bt_from_radiance as a deprecated alias for one release, and its BTFromRadiance Operator keeps its name.

Decisions and open questions

Two decided on the layer map, three leaning, two open. Each entry gives the position first, then the trade-off.

1. Layer: GeoNumerics tier 1

Decided (5 Nov 2026, on the layer map). radiomax imports geophysix and integrix and nothing from GeoStack, so radtrax and plumax can use it on plain arrays. geoops and geoproducts sit above it.

2. The line with radtrax

Decided (5 Nov 2026, on the layer map). Geometry, unit conversions and empirical formulas with fitted coefficients are radiomax’s; anything that needs radiation moving through an atmospheric state is radtrax’s. Kernel BRDF falls on radiomax’s side (fixed kernels, fitted weights, no path); convolving a modelled spectrum with an SRF falls on radtrax’s.

3. Spectral responses and coefficients arrive as arguments

Leaning. The SRF tables stay in georeader, which is spaceml-org’s and read-only to us. radiomax never imports it: a reader or a geoops Operator loads the SRF and the calibration coefficients and passes arrays in. That keeps radiomax free of file formats and of any GeoStack dependency.

4. Replace the lazy calls into georeader.reflectance

Leaning. geoops reaches into georeader.reflectance for counts, radiance and reflectance conversions. Those become radiomax calls, traceable under JAX, with georeader’s results kept as the test reference.

5. Coefficient tables as data

Leaning. Split-window, ocean-colour and BRDF coefficients differ by sensor and by version. They ship as plain data specs, one per sensor, passed to the formula, as geoproducts’ presets become plain data; the formula itself has no sensor in it.

6. Which solar-position algorithm

Open. The simple almanac formulas are accurate to about 0.01° and trace cheaply; NREL’s SPA reaches about 0.0003° at many times the cost. Leaning: the almanac formulas by default, SPA behind an argument, both tested against pvlib.

7. SAR and altimetry: now or when needed?

Open. The layer map gives radiomax SAR calibration, despeckling and altimetry corrections, but only geoops’ despeckling filters exist today and nothing below GeoStack calls them. Leaning: move the despeckling filters in wave 4, and write the altimetry corrections when a consumer asks.

Roadmap

Six waves, each a GitHub issue epic in the radiomax repository once it exists. Geometry and radiometry come first: they end the most copies and every methane retrieval needs them.

WaveDeliversEndsNeeds
0. Scaffoldthe repository from the library template; CI, capability index; reference tests against georeader.reflectance and pvlib—geophysix wave 1
1. Geometry and radiometrysolar and viewing angles, Earth–Sun distance, counts, radiance and reflectance, band irradiance, the geometric air-mass factorgeoops’ radiometry arrays; the three air-mass factors; the lazy georeader calls (decision 4)0; integrix wave 0
2. Thermal and navigationPlanck and brightness temperature; parallax, geostationary navigation, bowtie geometrythe three brightness-temperature copies; the navigation and parallax maths in geoproducts and geoops1
3. Empirical retrievalssplit-window SST and LST, ocean-colour ratios, Ross–Li BRDF and NBAR, with coefficient tables as data (decision 5)—1
4. SAR and altimetrySAR calibration and despeckling; altimetry corrections when asked for (decision 7)geoops’ despeckling arrays1
5. Consumers switchradtrax, plumax, geoops and geoproducts onto radiomaxthe remaining copies1–4

Waves 2, 3 and 4 can run side by side. Wave 5 is one issue per consumer, filed in that consumer’s repository and linked to the radiomax epic.

Sources

References
  1. Reda, I., & Andreas, A. (2004). Solar position algorithm for solar radiation applications. Solar Energy, 76, 577–589.
  2. NOAA, & NASA. (n.d.). GOES-R Series Product Definition and Users’ Guide, Volume 3: Level 1b Products. NOAA.
  3. Lucht, W., Schaaf, C. B., & Strahler, A. H. (2000). An algorithm for the retrieval of albedo from space using semiempirical BRDF models. IEEE Transactions on Geoscience and Remote Sensing, 38(2), 977–998.