Surfaces API
Surface models are implemented in CoreRT because they form the lower boundary of the adding-doubling column.
Surface Types
vSmartMOM.CoreRT.LambertianSurfaceScalar Type
LambertianSurfaceScalar{FT} <: AbstractSurfaceTypeIsotropic Lambertian surface with a single scalar albedo α shared across all spectral points in a band. The BRDF is ρ = α/π, independent of viewing and illumination angles. Only the m = 0 Fourier moment is nonzero.
Supports analytical Jacobians with respect to albedo in linearized RT.
Fields
albedo::FT: hemispherical albedo ∈ [0, 1].
vSmartMOM.CoreRT.LambertianSurfaceSpectrum Type
LambertianSurfaceSpectrum{FT} <: AbstractSurfaceTypeIsotropic Lambertian surface with a per-spectral-point albedo vector. The vector length must match the number of spectral points in the band.
Fields
albedo::AbstractArray{FT,1}: spectral albedo vector, one value per grid point.
vSmartMOM.CoreRT.LambertianSurfaceLegendre Type
Defined by Legendre polynomial terms as function of spectral grid, which is scaled to [-1,1] (degree derived from length of a_coeff)
vSmartMOM.CoreRT.LambertianSurfaceSpline Type
Defined by a simple spline from Interpolations.jl
sourcevSmartMOM.CoreRT.rpvSurfaceScalar Type
rpvSurfaceScalar{FT} <: AbstractSurfaceTypeRahman-Pinty-Verstraete (1993) four-parameter empirical BRDF model. Combines a Minnaert angular shape, a Henyey-Greenstein-like hot-spot function, and a geometric bowl/bell correction. Scalar only (Stokes-I); no built-in linearization.
Fields
ρ₀: Overall reflectance level parameter (scalar)ρ_c: Hotspot function parameter (1.0 = no hotspot)k: Anisotropy shape parameter. k < 1.0 (> 1.0) corresponds to a bowl (bell) shape.Θ: Asymmetry parameter, Θ < 0.0 (> 0.0) corresponds to a predominantly backward (forward) scattering.
vSmartMOM.CoreRT.RossLiSurfaceScalar Type
RossLiSurfaceScalar{FT} <: AbstractSurfaceTypeRoss-Li kernel-based BRDF (Lucht, Schaaf & Strahler, 2000). Decomposes the surface reflectance into three semi-physical kernels: isotropic, RossThick (volumetric canopy scattering), and LiSparse (geometric mutual shadowing). Standard MODIS/RAMI parameterization. Scalar only (Stokes-I); no built-in linearization.
By default the incident and reflected zenith angles are capped at 80° before the kernels are evaluated (zenith_cap_deg = 80), a vSmartMOM regularization of grazing quadrature nodes, where the LiSparse kernel becomes large and negative. zenith_cap_deg = nothing evaluates the kernels at the true angles, as MODIS (MCD43) and VLIDORT do.
RossLiSurfaceScalar(fvol, fgeo, fiso; zenith_cap_deg = 80)Fields
fvol: Volumetric RossThick fractionfgeo: Geometric LiSparse fractionfiso: Isotropic reflectance fractionzenith_cap_deg: Kernel zenith-angle cap [deg];nothing= no cap (MODIS/VLIDORT definition)
vSmartMOM.CoreRT.CoxMunkSurface Type
CoxMunkSurface{FT} <: AbstractSurfaceTypeCox-Munk (1954) ocean surface: Fresnel reflection from wind-roughened wave facets. Supports full polarization (Mueller matrix) and optional Lambertian whitecap contribution.
Isotropic Gaussian slope distribution with total mean-square slope ⟨zx² + zy²⟩ = 0.003 + 0.00512·U (Cox & Munk 1954), i.e. per-axis variance σ² = ½(0.003 + 0.00512·U); see CoreRT.wind_to_sigma2.
With n_water = nothing the solvers use the Segelstein (1981) index (water_refractive_index) at the wavelength of every spectral point; a vector n_water is used element-wise and must have one entry per spectral point of the band. The exact direct-solar glint correction (apply_ss_correction!) is applied at TOA only; interior observer levels carry the Fourier-series glint.
Fields
wind_speed: 10-m wind speed [m/s]n_water: Complex refractive index n + ik of water:nothing→ Segelstein (1981) at each spectral point's wavelength; a scalar for the whole band; or a vector with one entry per spectral pointwhitecap_albedo: Whitecap Lambertian albedo (Koepke 1984)include_whitecaps: Include whitecap contributionshadowing: Include Smith (1967) shadow masking
vSmartMOM.CoreRT.CanopySurface Type
CanopySurface{FT} <: AbstractSurfaceTypeComposite lower boundary: a vegetation canopy (one or more scattering layers) backed by a soil BRDF. When used as the surface in rt_run, the canopy sub-layers are processed internally via the adding-doubling method before interacting with the soil, producing an effective canopy+soil reflectance.
The direct beam enters the effective layer only through its reflected source (j₀⁺ = 0), so rt_run's BHR-down output bhr_dw is the diffuse downwelling flux for a canopy (no direct solar term), and the forward BOA radiance carries no collimated beam at a view on the solar ordinate. TOA radiances include the reflected direct beam.
Requires CanopyOptics.jl for leaf-angle distribution and scattering models.
vSmartMOM.CoreRT.CanopySurface_from_prospect Function
CanopySurface_from_prospect(leaf_prospect, prospect_grid; soil, LAI, kwargs...)Convenience constructor: compute spectral leaf R/T from PROSPECT and build a CanopySurface with the spectral leaf optics on the PROSPECT wavelength grid. If LAD is omitted, CanopySurface uses CanopyOptics.spherical_leaves().
Arguments
leaf_prospect: aCanopyOptics.LeafProspectProProperties(N, Ccab, Ccar, ...)prospect_grid: wavelength range in nm (default 400:1:2500)Remaining keyword arguments are forwarded to
CanopySurface(...).
Surface Construction and Optics Helpers
vSmartMOM.CoreRT.create_surface_layer! Function
create_surface_layer!(lambertian, added_layer, SFI, m, pol_type,
quad_points, τ_sum, architecture)Computes (in place) surface optical properties for any Lambertian surface flavour (LambertianSurfaceScalar, LambertianSurfaceSpectrum, LambertianSurfaceLegendre, LambertianSurfaceSpline) as an AddedLayer. The four differ only in how the spectral albedo is produced (surface_albedo); the scaffold — including the m>0 / j₀⁺ conventions documented at the top of this file — is shared.
- `lambertian` a Lambertian surface struct (one of the four flavours)
- `SFI` bool if SFI (Source Function Integration) is used
- `m` Fourier moment (starting at 0)
- `pol_type` Polarization type struct
- `quad_points` Quadrature points struct
- `τ_sum` total optical thickness from TOA to the surface
- `architecture` Compute architecture (GPU,CPU)create_surface_layer!(RS_type, lambertian, added_layer, added_layer_lin, iparam,
SFI, m, pol_type, quad_points, τ_sum, τ̇_sum, architecture)Compute surface reflection/transmission matrices and their derivatives for a scalar Lambertian surface.
Sets the added_layer forward matrices and added_layer_lin derivative matrices for the surface "layer", including the source function contribution from the solar beam attenuated through the full atmosphere.
Arguments
RS_type::noRS: No Raman scattering.lambertian::LambertianSurfaceScalar: Surface with scalar albedo. added_layer::AddedLayer: Output forward matrices (modified in-place).added_layer_lin::AddedLayerLin: Output linearized matrices (modified in-place).iparam::Int: Parameter index for the surface albedo derivative.SFI::Bool: Source Function Integration flag.m::Int: Fourier moment (only has nonzero surface contribution).pol_type: Polarization type.quad_points: Quadrature points and weights.τ_sum: Total optical depth from TOA to surface[nSpec].τ̇_sum: Derivative of total τ[nSpec × Nparams].architecture: CPU or GPU.
Linearized Lambertian-Legendre surface. Each coefficient is one consecutive surface state-vector element, so iparams[k] stores ∂y/∂ρₖ₋₁.
create_surface_layer!(brdf::AbstractSurfaceType, added_layer, SFI, m,
pol_type, quad_points, τ_sum, architecture)Build an AddedLayer from any analytic BRDF that implements reflectance(brdf, stokes_index, μᵢ, μᵣ, Δϕ). RPV and Ross-Li specialize that scalar interface; this shared method performs the Fourier integration and operator assembly.
create_surface_layer!(canopy::CanopySurface, added_layer, SFI, m, pol_type,
quad_points, τ_sum, architecture;
spec_bands_wn=nothing, m_max=2, F₀=nothing,
soil_spec_wn=spec_bands_wn)Compute the effective canopy+soil surface layer for Fourier moment m. F₀ is the (nStokes, nSpec) solar Stokes vector at TOA used by both the leaf and soil source terms (nothing: unit unpolarized beam). m_max is the Fourier loop bound in order semantics.
When spectral leaf optics are provided, spec_bands_wn (the concatenated computation wavenumber grid) is required for initializing the spectral cache on first call. soil_spec_wn (default spec_bands_wn) is the grid on which a soil with spectral properties is resolved; solvers that do not set up the spectral canopy cache pass only this one.
Internally:
Compute Z-matrices from the cached analytic stack (or coarse-grid interpolation).
For each canopy sub-layer: build
CoreDirectionalScatteringOpticalProperties, runelemental!(canopy kernel) +doubling!.Accumulate sub-layers via
interaction!.Create soil surface layer and interact with the canopy composite. A soil with spectral properties (a
CoxMunkSurfacewithn_water = nothing) is resolved onsoil_spec_wnfirst.Copy the resulting R⁻⁺ and J₀ into the output
added_layer.
The direct beam enters only through the reflected source j₀⁻; the layer's j₀⁺ is zero. The BHR-down diagnostic (bhr_dw of rt_run) is therefore the diffuse downwelling flux at the canopy top, without the direct solar flux, and the forward BOA radiance carries no collimated beam at a view on the solar ordinate. TOA radiances, hdr and bhr_uw include the reflected direct beam.
TODO: Canopy + Raman (RRS/VS) coupling is not currently implemented. The
canopy BRDF code is noRS-only; calling rt_run with CanopySurface + RRS/VS
has undefined behavior (the inelastic ieR/ieT branches in the kernels
never see a canopy-adapted contribution and will return garbage or crash).
Future work: couple the canopy path to the inelastic path — this is a
separate project, not part of the sanghavi-unified merge.
sourcecreate_surface_layer!(RS_type, canopy::CanopySurface, added_layer, added_layer_lin,
iparam, SFI, m, pol_type, quad_points, τ_sum, τ̇_sum, F₀, architecture;
soil_spec_wn = nothing)Linearized surface dispatch for CanopySurface. Computes the forward canopy+soil reflectance (same as the non-linearized dispatch) and the derivative of the soil albedo parameter at iparam via finite differences. soil_spec_wn is forwarded to the forward builder (spectral soil properties).
Canopy-specific parameter derivatives (LAI, leaf R/T) are not yet implemented in the linearized path; their Jacobian slots should be populated via the hybrid AD boundary (ForwardDiff through canopy optical properties).
sourcecreate_surface_layer!(surf::CoxMunkSurface, added_layer, SFI, m, pol_type,
quad_points, τ_sum, architecture; F₀ = nothing)Cox–Munk surface layer for Fourier moment m. With one refractive index for the whole band (scalar n_water, or a vector with equal entries) this is the shared analytic-surface assembly: one reflectance matrix for every spectral point. A spectrally varying n_water (one entry per spectral point; resolve n_water = nothing first with _resolve_spectral_surface) gives a reflectance matrix per spectral point: the Fourier reflectance is evaluated at the knots of _n_water_knots and interpolated on the device to the other points, and the reflected direct beam j₀⁻ uses each point's matrix.
create_surface_layer!(RS_type::noRS, surf::CoxMunkSurface, added_layer, added_layer_lin,
iparam, SFI, m, pol_type, quad_points, τ_sum, τ̇_sum, F₀, architecture)Compute forward + linearized surface reflection for a Cox-Munk surface.
The surface parameter is wind speed. The derivative ∂R_surf/∂U is computed analytically via the derivative chain through the slope PDF, shadow factor, and whitecap fraction — all sharing the wind-speed-independent Fresnel and geometry computations with the forward evaluation.
A spectrally varying n_water is handled as in the forward builder: the reflectance and its wind derivative are evaluated at the knots of _n_water_knots and interpolated with the same weights, so forward and Jacobian use the same per-point operator.
vSmartMOM.CoreRT.water_refractive_index Function
water_refractive_index(λ_nm)Complex refractive index n + i k (k ≥ 0) of liquid water at 25 °C and vacuum wavelength λ_nm (nanometres), from Segelstein (1981).
Between the tabulated wavelengths, n and k are interpolated linearly in wavelength. The table spans 33.96 nm to 10 m; a wavelength outside that range throws an ArgumentError.
Returns a Complex{Float64}. CoxMunkSurface(n_water = nothing) evaluates it at the wavelength of every spectral point.
Reference: D. J. Segelstein, "The complex refractive index of water", M.S. thesis, University of Missouri–Kansas City (1981).
sourcevSmartMOM.CoreRT.fresnel_coefficients Function
fresnel_coefficients(n_rel, cos_θᵢ)Complex Fresnel amplitude reflection coefficients for s- and p-polarization.
Arguments
n_rel::Complex: relative refractive index (n_transmitted / n_incident)cos_θᵢ::Real: cosine of the incidence angle
Returns
(r_s, r_p): complex amplitude coefficients
vSmartMOM.CoreRT.fresnel_mueller Function
fresnel_mueller(r_s, r_p, n_stokes)Mueller matrix for Fresnel reflection given complex amplitude coefficients, in the facet basis (ŝ, p̂ = k × ŝ) with ŝ normal to the plane of reflection. Stokes parameters follow vSmartMOM's convention for a basis (e₁, e₂) = (ŝ, p̂): Q = |E₁|² − |E₂|², U = 2Re(E₁E₂_), V = 2Im(E₁E₂_), with the refractive index n = n_r + i n_i (n_i ≥ 0). For n_stokes = 4 (IQUV):
M = [(|rs|²+|rp|²)/2 (|rs|²-|rp|²)/2 0 0 ]
[(|rs|²-|rp|²)/2 (|rs|²+|rp|²)/2 0 0 ]
[0 0 Re(rs·rp*) -Im(rs·rp*) ]
[0 0 Im(rs·rp*) Re(rs·rp*) ]The U–V elements follow from U' + iV' = 2 E₁'E₂'* = (rs rp*)(U + iV); this sign is confirmed against VLIDORT 2.8.3's complex-index Cox–Munk kernel (test_coxmunk_polarization.jl).
sourcevSmartMOM.CoreRT.stokes_rotation_matrix Function
stokes_rotation_matrix(φ, n_stokes)Rotation matrix L(φ) for the Stokes reference plane.
Rotates the Stokes vector reference plane by angle φ (radians). Convention matches vSmartMOM's D = [1, 1, -1, -1]:
L = [1 0 0 0]
[0 cos2φ sin2φ 0]
[0 -sin2φ cos2φ 0]
[0 0 0 1]vSmartMOM.CoreRT.invalidate_canopy_cache! Function
invalidate_canopy_cache!(canopy::CanopySurface)Force recomputation of the canopy cache on the next create_surface_layer! call. Use after changing canopy parameters (LAI, LAD, etc.) between runs.