Skip to content

CoreRT API

CoreRT owns the adding-doubling solver, the RT model containers, and the linearized/Jacobian-facing model layout.

Forward and Linearized Modes

vSmartMOM.FwdMode Type
julia
FwdMode()

Marker selecting the forward radiative-transfer model construction path.

source
vSmartMOM.LinMode Type
julia
LinMode()

Marker selecting the linearized model construction path used for Jacobians.

source
vSmartMOM.CoreRT.model_from_parameters_lin Function
julia
model_from_parameters_lin(params)

Convenience alias for model_from_parameters(LinMode(), params). Returns (model, lin_model).

source
vSmartMOM.CoreRT.rt_run_lin Function
julia
rt_run_lin(model, lin_model, NAer, NGas, NSurf; i_band=1)

Convenience alias for the linearized rt_run overload. Equivalent to rt_run(model, lin_model, NAer, NGas, NSurf; i_band).

source

Model Types

vSmartMOM.CoreRT.AbstractRTModel Type

Abstract base type for all RT models

source
vSmartMOM.CoreRT.RTModel Type
julia
RTModel{ARCH, FT} <: AbstractRTModel{ARCH, FT}

Central model state for vSmartMOM radiative transfer.

Only two type parameters:

  • ARCH: compute architecture (CPU or GPU)

  • FT: floating-point precision (Float32 or Float64)

All physics sub-components are organized hierarchically:

  • solver: RT solver configuration (polarization, quadrature, truncation)

  • geometry: observation geometry (SZA, VZA, VAZ, observer altitude)

  • quad_points: precomputed quadrature points and weights

  • atmosphere: atmospheric state (profile + spectral bands)

  • optics: all precomputed optical properties (Rayleigh, aerosol, absorption)

  • surfaces: per-band surface BRDF models

Fields

  • architecture: Compute architecture (CPU/GPU)

  • solver: RT solver configuration

  • numerics: Numerical-knob parameters (doubling threshold, etc.) — see RTNumericalParameters

  • geometry: Observation geometry

  • quad_points: Quadrature points and weights

  • atmosphere: Atmospheric state (profile + spectral bands)

  • optics: Precomputed optical properties

  • surfaces: Surface models, one per spectral band

  • sources: Source-term scene (v0.6 source-term refactor). Defaults to a single SolarBeam — i.e. the historical unit-Stokes-I direct solar illumination — and can be overridden at rt_run call time via the sources= kwarg. Mirrors the abstract-typed surfaces slot.

source
vSmartMOM.CoreRT.SolverConfig Type
julia
SolverConfig{FT, PT, QT}

Immutable RT solver configuration: polarization mode, quadrature scheme, Fourier truncation, and Legendre truncation. Fixed after model construction; never differentiated.

Fields

  • polarization_type: Type of polarization (Stokes_I / IQU / IQUV)

  • quadrature_type: Quadrature type (RadauQuad / GaussLegQuad)

  • m_max_bands: Per-band Fourier loop bound, order semantics: loop runs m = 0:m_max_bands[iBand]. Equals n_fourier_moments_bands .- 1.

  • n_fourier_moments_bands: Per-band Fourier moment count: n_fourier_moments_bands[iBand] = m_max_bands[iBand] + 1. Provided so consumers don't have to remember the count↔order convention.

  • l_max: Per-band max truncated Legendre index

  • l_trunc: Legendre truncation order (user-specified)

  • Δ_angle: Exclusion angle for forward peak [deg]

  • depol: Depolarization factor

  • use_component_traits: Phase C flag: when true (current default), per-band m_max_bands are derived from component_m_max(c, ctx) traits across active components — Cox-Munk / RPV / RossLi / canopy run to their full user_l_cap instead of the historical half-truncated aggregator. Flip to false to fall back to the legacy min(ceil((l_max+1)/2), params.max_m) aggregator (bit-equal to Phase B).

source
vSmartMOM.CoreRT.Atmosphere Type
julia
Atmosphere{FT, VMR}

The atmospheric column: profile data plus spectral grid definitions.

Fields

  • profile: Atmospheric profile (T, p, q, vmr, vcd, etc.)

  • spec_bands: Spectral bands — Vector of wavenumber grids, one per band

source
vSmartMOM.CoreRT.RayleighScattering Type
julia
RayleighScattering{FT, GC}

Precomputed Rayleigh and Cabannes (elastic) scattering properties. Derived from the depolarization ratio; fixed for a given spectral band.

Fields

  • greek_rayleigh: Greek coefficients for total Rayleigh scattering (single set or per-band)

  • greek_cabannes: Greek coefficients for Cabannes (pure elastic) Rayleigh per band

  • ϖ_Cabannes: Pure elastic (Cabannes) fraction of Rayleigh scattering per band

source
vSmartMOM.CoreRT.AerosolState Type
julia
AerosolState{FT, AO}

Per-band aerosol scattering optics and optical depth profiles. Primary differentiable state for aerosol retrievals.

Fields

  • aerosol_optics: Truncated aerosol optics: aerosol_optics[iBand][iAer]

  • τ_aer: Aerosol optical depth profiles: τ_aer[iBand][iAer, nSpec, iLayer] — 3-D for both the forward and linearized paths, enabling per-wavelength aerosol optical depth within wide spectral bands.

source
vSmartMOM.CoreRT.Optics Type
julia
Optics{FT, RS, AS}

Container for all precomputed optical properties that feed into the RT solver. Groups Rayleigh scattering, aerosol scattering, absorption optical depths, and Rayleigh optical depths.

AD boundary: aerosols and τ_abs hold differentiable state; rayleigh and τ_rayl are typically fixed.

Fields

  • rayleigh: Rayleigh/Cabannes scattering properties

  • aerosols: Aerosol scattering optics and optical depths

  • τ_abs: Absorption optical depth: τ_abs[iBand][nSpec × nLayers]

  • τ_rayl: Rayleigh optical depth: τ_rayl[iBand][nSpec × nLayers]

source
vSmartMOM.CoreRT.OpticsLin Type
julia
OpticsLin{FT}

Linearized (Jacobian) counterpart of Optics. Each field stores derivatives of the corresponding forward-model field with respect to the physical state vector.

Fields

  • τ̇_abs: ∂τ_abs/∂x per band: Vector of arrays [NGas × nSpec × nLayers]

  • τ̇_aer: ∂τ_aer/∂x per band: Vector of arrays [NAer × 7 × nSpec × nLayers]

  • lin_aerosol_optics: Linearized aerosol optics per band per aerosol

source
vSmartMOM.CoreRT.vSmartMOM_Parameters Type
julia
vSmartMOM_Parameters{FT<:Real}

Top-level container for all user-specified model parameters before any derived quantities are computed. Groups radiative-transfer settings (spectral bands, BRDF, quadrature, polarization), observation geometry (SZA, VZA, VAZ), the atmospheric profile (T, p, q), and optional absorption/scattering sub-parameter structs.

Fields

  • spec_bands: Spectral bands — Vector of wavenumber grids, one per band

  • brdf: Surface (Bidirectional Reflectance Distribution Function)

  • quadrature_type: Quadrature type for RT streams (RadauQuad/GaussLegQuad)

  • polarization_type: Type of polarization (I/IQ/IQU/IQUV)

  • max_m: Hard cutoff for maximum number of Fourier moments to loop over

  • Δ_angle: Exclusion angle for forward peak in degrees (legacy — see truncation)

  • l_trunc: Truncation length for legendre terms (scalar for now, can do nBand later)

  • truncation: Phase-function truncation method. Defaults to δBGE(l_trunc, Δ_angle) for backward compatibility; set explicitly to NoTruncation() for canopy-only or smooth-phase-function runs (Sanghavi & Stephens 2015 §2 — the f_tr → 0 limit). The Δ_angle field above is then ignored.

  • depol: Depolarization factor

  • numerics: Numerical-knob parameters (doubling threshold, etc.) — defaults to RTNumericalParameters{FT}() if not specified in YAML.

  • float_type: Float type to use in the RT (Float64/Float32)

  • architecture: Architecture to use for calculations (CPU/GPU)

  • sza: Solar zenith angle [deg]

  • vza: Viewing zenith angles [deg]

  • vaz: Viewing azimuthal angles [deg]

  • obs_alt: Altitude of observer [Pa]

  • T: Temperature Profile [K]

  • p: Pressure Profile [hPa]

  • q: Specific humidity profile

  • profile_reduction_n: Length of profile reduction

  • absorption_params: Optional struct that holds all absorption-related parameters

  • scattering_params: Optional struct that holds all aerosol scattering-related parameters

  • nstreams: Phase D — primary user-facing resolution knob: weighted streams per hemisphere. Public contract: stream_l_cap = 2·nstreams - 1. When nothing, the parser populated max_m/l_trunc from a legacy YAML; new-schema configs set this and may omit max_m/l_trunc.

  • m_max_override: Phase D — explicit per-band Fourier loop bound (order, optional). When set, clamps the trait-aggregator output. Lower hard cap on top of stream_l_cap.

  • stream_l_cap: Phase D — derived projection cap: 2·nstreams - 1 for new schema, or l_trunc for legacy. Internally consumed by the trait aggregator and the truncation-resolver. Always populated; defaults to l_trunc until nstreams is explicitly set.

  • legacy_l_cap_override: Phase D — legacy l_trunc value retained verbatim from YAML when the user explicitly set it. nothing for new-schema configs that derive stream_l_cap from nstreams instead.

source
vSmartMOM.CoreRT.AtmosphericProfile Type
julia
AtmosphericProfile{FT, VMR}

Vertical atmospheric state on a pressure grid, ordered from TOA to BOA.

Stores temperature, pressure (full levels and half levels), humidity, dry and wet vertical column densities, and volume mixing ratios for trace gases. Constructed internally by model_from_parameters from the raw arrays in vSmartMOM_Parameters.

p_full has N levels; p_half has N-1 layer-boundary pressures. T, q, vmr_h2o, vcd_dry, vcd_h2o, and Δz are layer quantities of length N.

Fields

  • T: Temperature Profile

  • p_full: Pressure Profile (Full)

  • q: Specific humidity profile

  • p_half: Pressure Levels

  • vmr_h2o: H2O Volume Mixing Ratio Profile

  • vcd_dry: Vertical Column Density (Dry)

  • vcd_h2o: Vertical Column Density (H2O)

  • vmr: Volume Mixing Ratio of Constituent Gases

  • Δz: Layer height (meters)

source
vSmartMOM.CoreRT.ObsGeometry Type

Observation Geometry (basics)

source
vSmartMOM.CoreRT.QuadPoints Type
julia
QuadPoints{FT}

Gauss or Gauss-Radau quadrature points and weights used for the angular discretisation of the radiative transfer equation. Also stores the cosine of the solar zenith angle (μ₀) and its index within the quadrature grid.

Fields

  • μ₀: μ₀, cos(SZA)

  • iμ₀: Index in quadrature points with sun

  • iμ₀Nstart: Index in quadrature points with sun (in qp_μN)

  • qp_μ: Quadrature points

  • wt_μ: Weights of quadrature points

  • qp_μN: Quadrature points (repeated for polarizations)

  • wt_μN: Weights of quadrature points (repeated for polarizations)

  • Nquad: Total number of quadrature points (weighted streams + zero-weight SZA/VZA output nodes)

  • Nstreams: Number of weighted streams per hemisphere (count of nonzero weights). Public contract: stream_l_cap = 2·Nstreams - 1.

source
vSmartMOM.CoreRT.CompositeLayer Type
julia
CompositeLayer{FT} <: AbstractLayer

Accumulated (composite) layer matrices produced by the interaction step of the adding/doubling RT method. Stores the reflectance (R), transmission (T), and source (J) matrices for the combined atmospheric slab from the top of atmosphere down to the current layer.

Sign convention: = outgoing (upward, decreasing τ), + = incoming (downward, increasing τ).

Fields

  • R⁻⁺::AbstractArray{FT,3}: reflectance from incoming (+) to outgoing (−)

  • R⁺⁻::AbstractArray{FT,3}: reflectance from outgoing (−) to incoming (+)

  • T⁺⁺::AbstractArray{FT,3}: transmission in the incoming (+) direction

  • T⁻⁻::AbstractArray{FT,3}: transmission in the outgoing (−) direction

  • J₀⁺::AbstractArray{FT,3}: source in the incoming (+) direction

  • J₀⁻::AbstractArray{FT,3}: source in the outgoing (−) direction

source
vSmartMOM.CoreRT.AddedLayer Type
julia
AddedLayer{FT} <: AbstractLayer

Single homogeneous layer matrices produced by the elemental/doubling steps of the RT solver. After doubling, these represent a full atmospheric layer that is subsequently combined with the composite layer via the interaction step.

Lower-case field names (r, t, j) distinguish added-layer quantities from composite-layer quantities (R, T, J).

Fields

  • r⁻⁺::AbstractArray{FT,3}: reflectance from incoming (+) to outgoing (−)

  • t⁺⁺::AbstractArray{FT,3}: transmission in the incoming (+) direction

  • r⁺⁻::AbstractArray{FT,3}: reflectance from outgoing (−) to incoming (+)

  • t⁻⁻::AbstractArray{FT,3}: transmission in the outgoing (−) direction

  • j₀⁺::AbstractArray{FT,3}: source in the incoming (+) direction

  • j₀⁻::AbstractArray{FT,3}: source in the outgoing (−) direction

  • temp1, temp2: pre-allocated workspace arrays to avoid allocations

  • temp1_ptr, temp2_ptr: CUDA pointer arrays (ignored on CPU)

source
vSmartMOM.CoreRT.RTNumericalParameters Type
julia
RTNumericalParameters{FT}

Centralised home for tunable numerical knobs that were previously hardcoded in the RT kernels. Lives once on vSmartMOM_Parameters / RTModel, threaded through to the kernels where needed. Designed to grow as more constants are lifted (Glint Legendre expansion cap, etc.).

Fields

  • dτ_max_threshold: Doubling resolution: cap on the elemental-layer optical depth dτ_max = threshold · μ_min, where μ_min is the smallest TRUE (positive-weight) quadrature stream cosine. Smaller values produce finer initial layers (more doublings → more accurate single-scatter at the cost of more roundoff through doubling). Default 0.001 is conservative legacy; raising to ~0.01 reduces doubling iterations.

  • dτ_min_floor: Absolute floor on dτ_max (and hence on dτ_initial), expressed as a multiple of eps(FT). Prevents the doubling discretisation from collapsing below FT precision regardless of geometry. Default 1024·eps(FT) ≈ 1.2e-4 for Float32 / 2.3e-13 for Float64 — the F32 value caps ndoubl around 13–14 for τ_total≤1 (well within Float32 representability); the F64 value is far below any sensible threshold·μ_min so it never activates in practice.

  • blas_threads: BLAS thread cap applied at every rt_run invocation. nothing means leave the BLAS thread setting alone (use whatever LinearAlgebra.BLAS.get_num_threads() returned at session start). Why cap: the batched-GEMM call sites in cpu_batched.jl and the elemental/doubling/interaction kernels operate on small matrices (NSTREAMS·n_stokes ≈ 12-48 per side) tiled across a wide spectral batch. Multi-threaded BLAS coordination dominates the work at that matrix size and serializes against the spectral-batch parallelism. The VLIDORT baseline harness empirically picked 8 as the sweet spot on a 128-thread machine; 1 is the most defensive choice when a single process owns all spectral points and threading happens at the batched outer level. Set via the numerics.blas_threadsYAML key, or programmatically withRTNumericalParameters{FT}(blas_threads = 8).

  • verbose: Verbose output flag. When false (default) rt_run/rt_run_lin suppress the per-call print_timer() dump at the end of the run. Set true (YAML key numerics.verbose: true or programmatically RTNumericalParameters{FT}(verbose = true)) to bring back the timing tree — useful for profiling, noisy for production loops. Per-band Computing profile for X... and AOD at band X... messages were demoted to @debug and are silent unless you set ENV["JULIA_DEBUG"] = "vSmartMOM".

source

Source-term types (SolarBeam, BlackbodySource, SurfaceSIF, SourceSet, NoSource, AD-mode traits, prepare_source / surface_source_contribute! dispatchers) are documented on the Source terms page.

Batch Scene Processing

BatchContext enables efficient multi-scene loop workflows (e.g. ensemble retrievals, parameter sweeps) by caching expensive one-time setup work (Mie, Fourier decomposition, HITRAN parsing) and exposing cheap per-scene update functions.

vSmartMOM.CoreRT.BatchContext Type
julia
BatchContext

Pre-built context for efficient batch radiative-transfer over many atmospheric scenes that share the same spectral configuration, geometry, surface BRDF, aerosol microphysics, and quadrature setup but differ in temperature/pressure profiles, humidity, and/or trace-gas VMRs.

Construct once from a vSmartMOM_Parameters object; then call update_model! before each rt_run invocation.

Example usage

julia
params = parameters_from_yaml("my_config.yaml")
ctx    = BatchContext(params)

for scene in scenes
    update_model!(ctx;
        T      = scene.T,        # length-Nz temperature profile [K]
        p_half = scene.p_half,   # length-(Nz+1) half-level pressures [hPa]
        q      = scene.q,        # length-Nz specific humidity [kg/kg]
        vmr    = scene.vmr)      # Dict{String,Any} — same keys as params.absorption_params.vmr
    R, T = rt_run(ctx.model)
    # ... process R, T ...
end

What may change per scene

  • Temperature profile T [K]

  • Pressure half-levels p_half [hPa]

  • Specific humidity q [kg/kg]

  • Trace-gas VMRs via the vmr keyword dict (same keys as the original params.absorption_params.vmr; adding new species requires a full rebuild)

What requires a full rebuild (new BatchContext)

  • Spectral bands (params.spec_bands)

  • Geometry (SZA, VZA, VAZ, observer altitude)

  • Surface BRDF

  • Polarization type, quadrature type, truncation

  • A different number of aerosols or gas species

Aerosol changes do not require a rebuild: use update_aerosol_loading! for τ_ref / vertical-placement changes (cheap, no Mie recomputation) and update_aerosol_microphysics! for size-distribution / refractive-index changes (reruns Mie for that aerosol and re-derives the Fourier-loop bounds).

Thread safety

One BatchContext per thread. update_model! and rt_run(ctx.model) mutate shared arrays and must not be called concurrently on the same ctx. If you run parallel scenes, create one BatchContext per worker thread (each BatchContext owns its own RTModel with independent mutable arrays).

Fields

  • model: the RTModel that is updated in place by update_model!

  • params: the original vSmartMOM_Parameters used for construction (kept for meta-information such as molecule lists, YAML knobs, float type)

  • absorption_models: cached AtmosphericAbsorption.LineByLineModel objects, one per (band, species) pair — eliminates HITRAN re-parsing per scene

  • h2o_models: cached H₂O LineByLineModel per band (nothing only when the configuration has no absorption_params at all; otherwise the model is cached unconditionally so a scene whose q changes from all-zero to non-zero can apply H₂O line absorption without a rebuild)

  • k_ref: reference-wavelength aerosol extinction coefficients, one per aerosol species (needed for Phase 2 aerosol-loading updates)

  • current_T, current_p_half, current_q, current_vmr: the unreduced scene state that update_model! was last called with (initialised from params at construction). nothing keyword arguments to update_model! fall back to these stored values — never to params — so successive partial updates compose incrementally. Stored already FT-converted so repeated updates do not re-convert or drift. The unreduced state cannot be recovered from model.atmosphere.profile (which is reduced), which is why it lives here.

  • current_τ_ref, current_profile_dist: the current per-aerosol loading state (column optical depth at λ_ref and vertical distribution), initialised from params and written by both update_aerosol_loading! and update_aerosol_microphysics!. update_model!'s τ_aer redistribution reads these so a prior loading update is not silently wiped.

  • n_bands, n_aerosols, Nz: scene-invariant dimension bookmarks

  • profile_reduction_n: reduction target passed to reduce_profile; -1 means no reduction

source
vSmartMOM.CoreRT.update_model! Function
julia
update_model!(ctx::BatchContext;
              T      = nothing,
              p_half = nothing,
              q      = nothing,
              vmr    = nothing)

Update ctx.model in place for a new atmospheric scene.

Only the arguments you supply are updated. nothing for a field means "keep the current scene value" — i.e. the value from the most recent successful update_model! call (or, if none yet, the value the BatchContext was built with). It does not fall back to the original params. This makes successive partial updates compose incrementally:

julia
update_model!(ctx; vmr = B)   # vmr = B, everything else still original
update_model!(ctx; T   = C)   # T = C AND vmr is still B (not reset to original)

The merge is per-field: T, p_half, q, and the vmr override dict are each remembered on the context (ctx.current_T, ctx.current_p_half, ctx.current_q, ctx.current_vmr) and overwritten only by the fields you pass. The remembered state is stored unreduced and already converted to the model's float type (params.float_type), so repeated updates neither re-convert nor drift.

For vmr, the supplied keys are overlaid onto the current override dict (which itself started as params.absorption_params.vmr); keys you do not pass keep their last value. The merged overrides are then layered over the configured defaults exactly as model_from_parameters does.

After this call rt_run(ctx.model) will produce radiances for the new scene.

Keyword arguments

  • T::AbstractVector: Temperature profile [K], length Nz (full levels, TOA to BOA). If profile_reduction_n != -1, pass the unreduced profile length (same as the original params.T).

  • p_half::AbstractVector: Half-level pressures [hPa], length Nz + 1 (or N_orig + 1 before reduction). Must be strictly positive and monotonically increasing (TOA to BOA, i.e. p_half[end] is surface pressure).

  • q::AbstractVector: Specific humidity [kg/kg], length Nz (or N_orig).

  • vmr::Dict{String,Any}: Trace-gas volume mixing ratios. Keys must be a subset of the configured molecules — supplying an unknown species key raises an error (add it to params.absorption_params.vmr and rebuild the context instead). Values may be scalars or length-Nz vectors.

Thread safety

update_model! and rt_run(ctx.model) share mutable arrays. Do not call them concurrently on the same ctx. Use one BatchContext per thread for parallelism.

Example

julia
params = parameters_from_yaml("config.yaml")
ctx    = BatchContext(params)

for scene in scenes
    update_model!(ctx;
        T      = scene.T,
        p_half = scene.p_half,
        q      = scene.q,
        vmr    = Dict("O2" => 0.21, "CH4" => scene.ch4_vmr))
    R, T_trans = rt_run(ctx.model)
end
source
vSmartMOM.CoreRT.update_aerosol_loading! Function
julia
update_aerosol_loading!(ctx::BatchContext, i_aer::Int;
                        τ_ref        = nothing,
                        profile_dist = nothing)

Cheap path — update only the column-integrated optical depth (τ_ref) and/or the vertical pressure distribution (profile_dist) for aerosol species i_aer, using the cached aerosol optics (aerosol_optics) and reference extinction coefficient (ctx.k_ref[i_aer]). No Mie recomputation is performed.

After this call rt_run(ctx.model) produces radiances for the new aerosol loading. All other model state (gas absorption, profile, surface) is unchanged.

Keyword arguments

  • τ_ref::Real: New column optical depth at λ_ref. When nothing, the value stored in params.scattering_params.rt_aerosols[i_aer].τ_ref is kept (only the distribution is updated).

  • profile_dist::Distributions.Distribution: New vertical pressure distribution (a Distributions.jl Distribution object — the same type used in RT_Aerosol.profile). When nothing, the existing distribution is kept.

Cost

O(Nz) per band — evaluates the distribution PDF on the pressure grid and scales the optical depth profile. No Mie, no HITRAN.

What it invalidates

  • model.optics.aerosols.τ_aer[i_band][i_aer, :, :] — all bands (3-D: nSpec × nLayers).

  • Does NOT change aerosol_optics, k_ref, SolverConfig Fourier bounds, gas absorption, or Rayleigh properties.

Example

julia
ctx = BatchContext(params)
# Change τ_ref for aerosol 1 to 0.3, keep vertical distribution
update_aerosol_loading!(ctx, 1; τ_ref = 0.3)
R, T = rt_run(ctx.model)
source
vSmartMOM.CoreRT.update_aerosol_microphysics! Function
julia
update_aerosol_microphysics!(ctx::BatchContext, i_aer::Int, aerosol::Aerosol;
                              τ_ref = nothing)

Expensive path — replace the microphysics of aerosol species i_aer with a new Aerosol (new size distribution and/or refractive index) and recompute all derived quantities via the same Mie code path that model_from_parameters uses.

This updates:

  • model.optics.aerosols.aerosol_optics[i_band][i_aer] for every band

  • ctx.k_ref[i_aer] (the new reference-wavelength extinction coefficient)

  • model.solver.m_max_bands, n_fourier_moments_bands, l_max (in-place via .=) — the critical Fourier-loop re-derivation that prevents silent wrong results when the new particle size changes the length of the Greek- coefficient series.

  • model.optics.aerosols.τ_aer[i_band][i_aer, :, :] for every band (3-D: nSpec × nLayers).

After this call rt_run(ctx.model) gives the same result as building a fresh model with the new aerosol.

Arguments

  • ctx: The BatchContext to update.

  • i_aer: 1-based index of the aerosol species to replace.

  • aerosol: New Aerosol (from Scattering.Aerosol), carrying the new size_distribution, nᵣ, and nᵢ.

Keyword arguments

  • τ_ref::Real: New column optical depth at λ_ref. When nothing, the current scene value ctx.current_τ_ref[i_aer] is kept (i.e. the most recently applied loading, not the original params value).

SolverConfig mutability note

SolverConfig is an immutable struct, but its three Vector fields (m_max_bands, n_fourier_moments_bands, l_max) are mutable Julia arrays and are updated in-place with .=. The scalar fields (l_trunc, Δ_angle, depol, polarization_type, quadrature_type) cannot be changed in-place; they are guaranteed to be unaffected by aerosol microphysics changes since they derive from params, not from per-aerosol optics. If a caller somehow requires a new l_trunc or Δ_angle, a full model_from_parameters rebuild is necessary.

Cost

Full Mie per band (O(n_bands × nquad_radius × size_distribution_points)), i.e. the same cost as the aerosol section of model_from_parameters.

What it invalidates

  • aerosol_optics[i_band][i_aer] — all bands.

  • ctx.k_ref[i_aer].

  • solver.m_max_bands, solver.n_fourier_moments_bands, solver.l_max.

  • τ_aer[i_band][i_aer, :, :] — all bands (3-D: nSpec × nLayers).

Example

julia
ctx = BatchContext(params)
# Save initial state for comparison
R_A, _ = rt_run(ctx.model)

# Replace aerosol 1 with larger particles (reff ~2 μm)
new_aerosol = Aerosol(LogNormal(log(2.0), 0.4), 1.3, 1e-8)
update_aerosol_microphysics!(ctx, 1, new_aerosol; τ_ref = 0.1)
R_B, _ = rt_run(ctx.model)
source

Stream-Level RT Output

vSmartMOM.CoreRT.StreamRTResult Type
julia
StreamRTResult{FT}

Per-Fourier-moment radiative-transfer result at all internal quadrature streams — the output of rt_run_streams. Downstream consumers (e.g. ExoOptics disk integration) reconstruct the Stokes vector at arbitrary (μ_v, μ_0, Δφ) by interpolating over (μ_v, μ_0) and Fourier-summing over m with cos(m·Δφ) / sin(m·Δφ) weights, instead of one rt_run per pixel.

Fields

  • qp_μ :: Vector{FT} — full quadrature mu nodes (length Nquad).

  • iμ₀ :: Int — index into qp_μ of the SZA stream (the closest to μ₀).

  • μ₀ :: FT — cosine of the chosen incident-beam SZA.

  • pol_n :: Int — number of Stokes components (pol_type.n).

  • weight :: Vector{FT} — Fourier weight (0.5/π for m=0; 1/π otherwise) used for each moment by the internal post-processor.

  • R⁻⁺_per_m :: Vector{Array{FT, 3}}(NquadN, NquadN, nSpec) per Fourier moment, where NquadN = Nquad · pol_n. This is the full-stream reflection matrix (stokes-out blocks × stokes-in blocks).

  • J⁻_per_m :: Vector{Array{FT, 3}}(NquadN, 1, nSpec) per Fourier moment, the combined per-source SFI Stokes at all output streams (legacy slot + all per-source slots summed). Use this when you want the SFI-style output without re-running RT.

  • J⁺_per_m :: Vector{Array{FT, 3}} — analog for BOA transmittance.

Recovering rt_run's output

julia
streams = rt_run_streams(model; sources = sources)
# At a single (vza, vaz):
= nearest_point(streams.qp_μ, cosd(vza))
_, istart, iend = get_indices(iμ, pol_type)
R_recovered = zero(rt_run(model; sources)[1][1, :, :])  # (n_stokes, nSpec)
for (mi, m) in enumerate(0:length(streams.J⁻_per_m)-1)
    cosmφ = cosd(m * vaz); sinmφ = sind(m * vaz)
    w_stokes = pol_n == 1 ? streams.weight[mi] * cosmφ :
               streams.weight[mi] *
               Diagonal([cosmφ, cosmφ, sinmφ, sinmφ][1:pol_n])
    for s in 1:nSpec
        R_recovered[:, s] .+= w_stokes * streams.J⁻_per_m[mi][istart:iend, 1, s]
    end
end

A unit test pins the bit-exact agreement of this reconstruction against rt_run for one published-figure geometry.

source
vSmartMOM.CoreRT.rt_run_streams Method
julia
rt_run_streams(model; i_band=1, sources=nothing) -> StreamRTResult

Run the RT solver and return per-Fourier-moment Stokes matrices at all quadrature streams instead of post-processed (vza, vaz) outputs. See StreamRTResult for the data layout and a worked recovery example.

Internally just calls rt_run with a streams_callback that copies composite_layer.R⁻⁺, composite_layer.J₀⁺/⁻, and the combined per-source-slot SFI contributions out of the live layer accumulators once per Fourier moment.

source

Jacobian Parameter Layout

vSmartMOM.CoreRT.ParameterLayout Type
julia
ParameterLayout

Describes the ordering of physical parameters in the Jacobian derivative dimension.

Instead of hardcoding 7*NAer + NGas + NSurf throughout the codebase, all index arithmetic goes through this struct. Each aerosol carries aerosol_params sub-parameters (currently 7: τ_ref, nᵣ, nᵢ, rₘ, σ_g, p₀, σ_p), followed by one slot per gas VMR and one per surface parameter.

Example

julia
layout = ParameterLayout(n_aerosols=1, n_gases=2, n_surface=1)
aerosol_range(layout, 1)   # 1:7
gas_range(layout)          # 8:9
surface_range(layout)      # 10:10
n_total(layout)            # 10
source
vSmartMOM.CoreRT.n_total Function

Total number of retrieval parameters.

source
vSmartMOM.CoreRT.aerosol_range Function

Index range for aerosol iaer (1-based).

source
vSmartMOM.CoreRT.gas_range Function

Index range for all gas VMR parameters.

source
vSmartMOM.CoreRT.surface_range Function

Index range for surface parameters.

source
vSmartMOM.CoreRT.surface_index Function

Index of a specific surface parameter (1-based within the surface block).

source
vSmartMOM.CoreRT.n_layer_params Function

Number of layer-level parameters (aerosol + gas, excluding surface and canopy).

source
vSmartMOM.CoreRT.canopy_range Function

Index range for canopy parameters (LAI, leaf_R, leaf_T, ...).

source