Skip to content

Solvers

Radiative transfer solvers turn OpticalProperties (per-layer optical depth τ (L, G)), a surface and a ViewingGeometry into the radiance at the top of the atmosphere, behind the RTSolver protocol (radtrax · 3). v0 has BeerLambert, the two-way direct path with no scattering; single scattering, two-stream and discrete ordinates arrive with v3 and v4 of the roadmap behind the same protocol.

solvers

Radiative transfer solvers behind the RTSolver protocol: Beer–Lambert in v0 (radtrax#35), scattering solvers from v3.

beer_lambert

The RTSolver protocol and the Beer–Lambert solver.

A solver turns optical properties, a surface and the viewing geometry into the radiance at the top of the atmosphere (radtrax · 3). v0's solver is Beer–Lambert along the two-way path, sun → surface → sensor, with no scattering and no thermal emission:

.. math:: L(ν) = \frac{E_0(ν)\, μ_0}{π}\, R(ν)\, \exp\Bigl(-m \sum_l τ_l(ν)\Bigr), \qquad m = \frac{1}{μ_0} + \frac{1}{μ},

with E₀ the solar irradiance at the top of the atmosphere, μ₀ and μ the cosines of the solar and viewing zenith angles, R the surface's bidirectional reflectance factor and m the plane-parallel air-mass factor (:meth:~radtrax.atmosphere.ViewingGeometry.air_mass). The single-slab models of :mod:radtrax.slab write L = F₀ R / π with no μ₀: their solar_irradiance is E₀ μ₀ here. Single scattering, two-stream and discrete ordinates arrive with v3 and v4 of the roadmap behind the same protocol.

Shapes: L layers, G wavenumbers; *G means a scalar or (G,).

RTSolver

Bases: Module

Protocol: optical properties, a surface and a geometry in, radiance out.

An abstract Equinox module, so filter_jit compiles each concrete solver and a forward model can hold any of them.

BeerLambert

BeerLambert(solar_irradiance: Float[ArrayLike, '*G'] = 1.0, *, spherical: bool = False)

Bases: RTSolver

Beer–Lambert along the two-way path; no scattering, no emission.

L = (E₀ μ₀ / π) R exp(−Σ_l m_l τ_l), with the plane-parallel air mass m_l = 1/μ₀ + 1/μ for every layer, or with spherical=True each layer's spherical-shell air mass (:meth:~radtrax.atmosphere.ViewingGeometry.layer_air_mass), which needs the optics to carry the layers' altitudes (ForwardModel.optics does).

Attributes:

Name Type Description
solar_irradiance Float[Array, '*G']

Solar irradiance at the top of the atmosphere E₀, a scalar or one value per wavenumber, (G,). The default, 1, gives radiance per unit irradiance.

spherical bool

Use each layer's spherical-shell air mass rather than the plane-parallel one (static; the default is plane parallel).

Examples:

>>> import jax.numpy as jnp
>>> from radtrax.atmosphere import ViewingGeometry
>>> from radtrax.optics import OpticalProperties
>>> from radtrax.surface import Lambertian
>>> optics = OpticalProperties(
...     jnp.array([4300.0, 4300.1]), jnp.array([[0.0, 0.1], [0.0, 0.2]])
... )
>>> radiance = BeerLambert()(
...     optics, Lambertian(1.0), ViewingGeometry(1.0, 1.0)
... )
>>> [round(float(x), 6) for x in radiance * jnp.pi]  # exp(-2 Σ τ)
[1.0, 0.548812]
Source code in src/radtrax/solvers/beer_lambert.py
def __init__(
    self, solar_irradiance: Float[ArrayLike, "*G"] = 1.0, *, spherical: bool = False
) -> None:
    self.solar_irradiance = jnp.asarray(solar_irradiance, dtype=float)
    self.spherical = spherical