Quick start
This page shows minimal working examples for each backend. The User guide explains every configuration option in detail.
All backends share the same mental model:
Build a configuration object describing the atmosphere (number of layers, number of quadrature streams, optical depths, single-scattering albedos, phase-function moments, boundary conditions, and source terms).
Call
solve(single spectral point) orsolve_batch(a whole spectrum).Read the fluxes and mean intensities out of the result, indexed by interface from the top of the atmosphere (index
0) to the surface (indexnum_layers).
C++: a solar problem
#include "adding_doubling.hpp"
// A 5-layer atmosphere with 8-stream quadrature.
adrt::ADConfig cfg(5, 8);
cfg.solar_flux = 1.0;
cfg.solar_mu = 0.5; // cos(solar zenith angle)
cfg.surface_albedo = 0.3;
cfg.allocate();
for (int l = 0; l < 5; ++l) {
cfg.delta_tau[l] = 0.2;
cfg.single_scat_albedo[l] = 0.9;
}
cfg.setHenyeyGreenstein(0.7);
adrt::RTOutput result = adrt::solve(cfg);
// result.flux_up[0] -> upward flux at the top of the atmosphere
// result.flux_down[5] -> downward flux at the surface
C++: a thermal problem
adrt::ADConfig cfg(10, 8);
cfg.use_thermal_emission = true;
cfg.wavenumber_low = 500.0; // cm^-1
cfg.wavenumber_high = 1500.0;
cfg.allocate();
for (int l = 0; l <= 10; ++l)
cfg.temperature[l] = 250.0 + 10.0 * l; // level temperatures [K]
for (int l = 0; l < 10; ++l) {
cfg.delta_tau[l] = 0.3;
cfg.single_scat_albedo[l] = 0.0; // pure absorption
}
adrt::RTOutput result = adrt::solve(cfg);
By default the surface emits at the bottom level temperature and the model top
emits downward at temperature[0]. Both boundaries can be decoupled,
following the DisORT convention:
cfg.surface_temperature = 320.0; // skin temperature, distinct from temperature[num_layers]
cfg.top_temperature = 0.0; // cold space: no downwelling at TOA
JAX: single wavenumber
from src_jax import ADConfig, solve
cfg = ADConfig()
cfg.num_layers = 5
cfg.num_quadrature = 8
cfg.solar_flux = 1.0
cfg.solar_mu = 0.5
cfg.surface_albedo = 0.3
cfg.allocate()
for l in range(5):
cfg.delta_tau[l] = 0.2
cfg.single_scat_albedo[l] = 0.9
cfg.set_henyey_greenstein(0.7)
result = solve(cfg)
# result.flux_up[0] -> upward flux at TOA
# result.flux_down[5] -> downward flux at BOA
JAX: batched across a spectrum
import numpy as np
from src_jax import BatchConfig, solve_batch
bcfg = BatchConfig()
bcfg.num_wavenumbers = 1000
bcfg.num_layers = 50
bcfg.num_quadrature = 8
bcfg.num_moments_max = 16
bcfg.surface_albedo = 0.1
bcfg.solar_flux = 1.0 # optional solar beam
bcfg.solar_mu = 0.5
delta_tau = np.random.uniform(0.01, 0.5, (1000, 50))
ssa = np.full((1000, 50), 0.9)
pmom = np.zeros((50, 16)) # shared across wavenumbers
for l in range(50):
for m in range(16):
pmom[l, m] = 0.7 ** m # Henyey-Greenstein g = 0.7
planck = np.zeros((1000, 51)) # zero = no thermal emission
flux_up, flux_down = solve_batch(bcfg, delta_tau, ssa, pmom, planck)
# flux_up.shape -> (1000,) TOA upward flux per wavenumber
# flux_down.shape -> (1000,) TOA downward flux per wavenumber
CUDA: batched host convenience call
#include "cuda_solver.cuh"
adrt::cuda::BatchConfig cfg;
cfg.num_wavenumbers = 4096;
cfg.num_layers = 60;
cfg.num_quadrature = 8;
cfg.num_moments_max = 16;
cfg.surface_albedo = 0.1;
// Flat SoA arrays: array[wav * nlay + layer], etc.
auto res = adrt::cuda::solveBatchHost(
cfg, delta_tau, single_scat_albedo,
phase_moments, /*shared=*/true,
planck_levels);
// res.flux_up[w], res.flux_down[w], res.flux_direct[w]
See Backends & API reference for the full API of each backend.