Skip to content

3a · Gas Absorption — building τ_abs ​

For: users who care how spectral gas-absorption optical depth is computed; HITRAN power users; retrieval developers tuning line-shape choices.

Prev: 3 · Layer Optical Properties · Next: 3b · Mie & Rayleigh

This page covers one of the four arrays the layer-optics pipeline produces: — gas-absorption optical depth as a function of wavenumber and atmospheric layer.

What this page produces ​

For each spectral grid point (cm⁻¹) and each atmospheric layer :

where is the absorption cross-section and is the column number density of the absorbing species in the layer. Once computed, is added to the scattering optical depth as    in Concepts/03c.

AtmosphericAbsorption.jl is the only supported path going forward

The production RT path (model_from_parameters → rt_run) now delegates line-by-line absorption to the external AtmosphericAbsorption.jl package (AtmosphericAbsorption.load_lines + LineByLineModel; TIPS-2021 partition functions). The diagram and prose below describe the underlying physics — the same line-shape equations apply — but make_hitran_model is not on the rt_run call path since this merge. The internal line-by-line model (make_hitran_model / HitranModel, used with read_hitran and absorption_cross_section) is deprecated in 2.2 (a one-time notice on first use lists the AtmosphericAbsorption calls) and will be removed in 3.0; new direct σ(ν, T, p) and ABSCO workflows should use AtmosphericAbsorption.jl. YAML LUTfiles accept OCO-2 ABSCO HDF files and AtmosphericAbsorption .absco tables (save_absco_lut), as well as vSmartMOM JLD2 tables from make_interpolation_model; AtmosphericAbsorption's own interpolation tables (build_interpolation_model/save_interpolation_model) are not read by the 2.x loader.

HITRAN line-by-line ​

The HITRAN line list is the primary source for molecular absorption parameters. For historical context, the legacy internal Absorption module exposes:

  • read_hitran(...) to read a HitranTable from a HITRAN-format file.

  • make_hitran_model(...) to build a HitranModel carrying the line list, broadening selector, and complex-error-function (CEF) choice.

  • compute_absorption_cross_section(model, grid, p, T) to evaluate on a wavenumber grid.

Each line in the HITRAN table contributes through its strength , center wavenumber , lower-state energy , half-widths for self- and air-broadening (, ), pressure-shift coefficient, and a temperature exponent. The sum over lines is computed on the spectral grid via a batched kernel (see below).

Line-shape families ​

Three line shapes are supported:

ShapePhysical regimeForm
Doppler (Gaussian)low pressure, hot gas   
Lorentzhigh pressure (collision-broadened)   
Voigt (convolution)mixed 

Voigt is the universal choice for atmospheric retrievals — it covers the transition between Doppler-dominated upper atmosphere and Lorentz-dominated lower atmosphere. It is evaluated through the complex error function (Faddeyeva function w(z)); vSmartMOM provides multiple CEF implementations including a GPU-friendly Humlicek-style approximation (src/Absorption/complex_error_functions.jl).

   HITRAN line list  ──→  make_hitran_model  ──┐
                                                │
   Spectral grid ν                              ▼
   Layer p, T, VMR  ─────────────────→  compute_absorption_cross_section
                                                │
                                                ▼
                                        σ(ν, T, p)
                                                │
                                                ▼
                                  τ_abs(ν, z) = σ · N(z)
                                                │
                                                ▼
                                   Layer optics  (Concepts 3)

The standalone Absorption module's GPU kernel ​

The internal Absorption module exposes a direct σ(ν, T, p) API (read_hitran / make_hitran_model / absorption_cross_section) backed by a KernelAbstractions Voigt kernel. This is the path used by the Tutorial on Absorption and by code that needs custom grids or cross-section comparisons; make_hitran_model is deprecated in 2.2 (see the warning above).

RT pipeline note: model_from_parameters → rt_run computes LBL gas absorption internally via AtmosphericAbsorption.jl (TIPS-2021), not through the kernel shown below. The description here applies to the standalone Absorption module only.

Because the line-shape sum is a per-grid-point reduction over thousands of contributing lines, it parallelizes trivially across the spectral grid — exactly the workload pattern of the RT solver. The Voigt kernel from src/Absorption/compute_absorption_cross_section.jl:316–332:

julia
@kernel function line_shape_batch!(A, @Const(grid), @Const(ν_arr), @Const(γ_d_arr),
                                   @Const(γ_l_arr), @Const(y_arr), @Const(S_arr),
                                   @Const(istart_arr), @Const(istop_arr),
                                   N_lines, ::Voigt, CEF)
    I = @index(Global, Linear)
    FT = eltype(A)
    acc = zero(FT)
    ν_i = FT(grid[I])
    @inbounds for j in 1:N_lines
        if istart_arr[j] <= I <= istop_arr[j]
            acc += FT(S_arr[j]) * FT(cSqrtLn2divSqrtPi) / FT(γ_d_arr[j]) *
                   real(w(CEF, FT(cSqrtLn2) / FT(γ_d_arr[j]) * (ν_i - FT(ν_arr[j]))
                            + im * FT(y_arr[j])))
        end
    end
    @inbounds A[I] += acc
end

@Const(...) declares the input arrays as read-only — KernelAbstractions uses this to enable backend-specific optimizations (constant-memory caching on CUDA, etc.). @index(Global, Linear) extracts the spectral index. The kernel runs identically on CPU, CUDA, and Metal via the same KA dispatch as the RT kernels. See Concepts/07 for the backend story. Production absorption through AtmosphericAbsorption is, however, experimental and not yet supported on Metal; see the GPU page.

The window istart_arr[j] ... istop_arr[j] is the wavenumber sub-range where line j contributes non-negligibly — pre-computed to avoid evaluating distant lines.

Reusing loaded tables across retrieval trials ​

A parameter template may own gigabytes of absorption lookup tables. When those tables are fixed, use copy_parameters to give each trial its own mutable state while sharing the table storage:

julia
trial = copy_parameters(template; share_luts=true)
grid = FixedPressureGrid()   # or FixedAltitudeGrid()
trial.p = surface_pressure_interfaces(grid, template.p, new_surface_pressure)
model, lin_model = model_from_parameters(LinMode(), trial; vertical_grid=grid)

The same grid convention must rebuild the interfaces and select the surface-pressure tangents; see FixedPressureGrid and FixedAltitudeGrid.

Atmospheric profiles, gas VMRs, aerosols, surfaces, and the LUT container lists are copied. The loaded gas and H₂O tables remain shared and must be treated as read-only, including their coefficients, grids and mutable metadata. Replacing a table entry in a trial's list does not alter the template. Absorption optical depths are still recomputed for each trial's pressure, temperature and abundance; this is storage reuse, not reuse of state-dependent opacities. The default copy_parameters(template) and ordinary deepcopy(template) copy table storage too.

Where τ_abs enters the layer-optics pipeline ​

After the kernel produces per layer, multiplication by column number density (and summation across species in the same layer) gives . This is wrapped in a CoreAbsorptionOpticalProperties and added to the layer-optics build chain:

julia
# inside compEffectiveLayerProperties.jl:363 (paraphrased)
combo = rayleigh + sum(aerosols)                       # τ_scat, ϖ, Z accumulated
final = combo + CoreAbsorptionOpticalProperties(τ_abs) # τ_λ = τ_abs + τ_scat,
                                                        # ϖ_λ = τ_scat·ϖ / τ_λ

The + overload for (CoreScatteringOpticalProperties, CoreAbsorptionOpticalProperties) is what bumps and rescales . Crucially, it does not change the doubling count — see Concepts/03c for the scattering-vs-total τ split that makes this work.

Code anchors ​

ConceptSource
HITRAN parsersrc/Absorption/read_hitran.jl
Absorption typessrc/Absorption/types.jl
Cross-section computationsrc/Absorption/compute_absorption_cross_section.jl:32–332
Line-shape kernel (@kernel)src/Absorption/compute_absorption_cross_section.jl:316–332
Complex error functionssrc/Absorption/complex_error_functions.jl
Constants & TIPS partition functionsrc/Absorption/constants/

For practical HITRAN data management — downloading line lists, switching between HITRAN editions, caching — see the HITRAN Data Management page in Resources.

Hands-on tutorials ​

Runnable examples with Plotly figures:

References ​

  • Gordon et al. (2017, 2022, 2024), HITRAN database releases. JQSRT.

  • Humlíček (1979, 1982), Optimized computation of the Voigt and complex probability functions, JQSRT 21:309 and 27:437.

  • Faddeyeva, V. N. & Terentiev, N. M. (1961), Tables of the probability integral for complex argument. (Original w(z) definition.)

  • Crib sheet: docs/dev_notes/theory_references.md §F.