How to Use ArtEmis, ArtTrans, and ArtReflect Classes for Radiative Transfer in ExoJAX
Instantiate ArtEmisPure, ArtTransPure, or ArtReflectPure from exojax.rt with pressure grids and solver specifications, then call run() with optical depth matrices and atmospheric parameters to compute emission, transmission, or reflection spectra via JAX-accelerated kernels.
The ExoJAX library (hajimekawahara/exojax) provides a high-performance toolkit for exoplanet atmospheric modeling built on JAX. The Art family of classes—ArtEmisPure, ArtTransPure, and ArtReflectPure—offers unified interfaces for one-dimensional radiative transfer (RT), inheriting common atmospheric geometry and grid management from the base ArtCommon class in src/exojax/rt/common.py.
Understanding the Art Common Base Class
All three RT engines extend ArtCommon (src/exojax/rt/common.py), which handles:
- Pressure-layer construction:
pressure_top,pressure_btm, andnlayerdefine the atmospheric grid. - Geometry helpers:
atmosphere_height()calculates physical heights for transmission chord geometry. - Wavenumber grid storage:
nu_grid(in cm⁻¹) is stored for spectral calculations.
This shared foundation ensures that opacity calculators providing dtau (optical-depth matrices) can feed identical atmospheric descriptions into any of the three RT modes.
Computing Emission Spectra with ArtEmisPure
Use ArtEmisPure (src/exojax/rt/emis.py, lines 19–35) for self-luminous atmospheres such as hot Jupiters or brown dwarfs.
Constructor and Solver Selection
from exojax.rt.emis import ArtEmisPure
art_emis = ArtEmisPure(
pressure_top=1e-8, # bar
pressure_btm=1e2, # bar
nlayer=100,
nu_grid=nu_grid, # wavenumber grid in cm⁻¹ (optional)
rtsolver="ibased", # "ibased", "fbased2st", or "ibased_linsap"
nstream=8, # Gaussian quadrature streams
)
The rtsolver parameter selects the numerical kernel. The class validates inputs via validate_rtsolver() (lines 56–62), ensuring nstream=2 when using the flux-based fbased2st solver, while intensity-based solvers like ibased accept higher stream counts.
Running the Emission Calculation
Call run() with the optical depth matrix and temperature profile:
emission_spectrum = art_emis.run(dtau, temperature_profile)
This method builds the Planck source function (piBarr from src/exojax/rt/planck.py) and dispatches to JAX kernels such as rtrun_emis_ibased in src/exojax/rt/rtransfer.py.
Correlated-k (CKD) Mode
For opacity databases using the correlated-k method, use run_ckd():
emission_ckd = art_emis.run_ckd(dtau_ckd, temperature_profile, weights, nu_bands)
Calculating Transmission Spectra with ArtTransPure
ArtTransPure (src/exojax/rt/trans.py, lines 13–34) computes wavelength-dependent transit radii for transiting exoplanets.
Geometry and Integration Setup
from exojax.rt.trans import ArtTransPure
art_trans = ArtTransPure(
pressure_top=1e-8,
pressure_btm=1e2,
nlayer=100,
integration="simpson", # "simpson" or "trapezoid"
)
The integration parameter maps to specific JAX kernels: "simpson" selects rtrun_trans_pureabs_simpson while "trapezoid" selects rtrun_trans_pureabs_trapezoid in src/exojax/rt/rtransfer.py.
Computing the Transit Radius
The run() method returns the square of the transit radius normalized by the bottom radius:
transit_radius_sq = art_trans.run(
dtau,
temperature_profile,
mean_molecular_weight,
radius_btm,
gravity_btm
)
Chord optical depths are computed internally using geometry helpers from src/exojax/rt/chord.py.
CKD Support
Transmission supports CKD via:
trans_ckd = art_trans.run_ckd(
dtau_ckd,
temperature_profile,
mean_molecular_weight,
radius_btm,
gravity_btm,
weights
)
Simulating Reflected Light with ArtReflectPure
ArtReflectPure (src/exojax/rt/reflect.py, lines 16–34) handles reflected-light calculations where atmospheric scattering dominates over thermal emission.
Scattering Configuration
Currently, only the Toon hemispheric-mean flux-adding solver is implemented:
from exojax.rt.reflect import ArtReflectPure
art_reflect = ArtReflectPure(
pressure_top=1e-8,
pressure_btm=1e2,
nlayer=100,
nu_grid=nu_grid,
rtsolver="fluxadding_toon_hemispheric_mean",
)
Running the Reflection Model
Unlike emission, reflection requires scattering parameters and incident stellar flux:
reflected_spectrum = art_reflect.run(
dtau,
single_scattering_albedo,
asymmetric_parameter,
surface_reflectivity,
incoming_flux
)
The solver (rtrun_reflect_fluxadding_toonhm in src/exojax/rt/rtransfer.py) computes the transmission factor applied to incoming_flux, with no internal thermal source term.
Complete Workflow Example
This minimal example demonstrates using the same optical depth matrix for all three calculations:
import jax.numpy as jnp
from exojax.rt.emis import ArtEmisPure
from exojax.rt.trans import ArtTransPure
from exojax.rt.reflect import ArtReflectPure
# Setup grid and dummy opacity (replace with real opacity calculator)
N_layer, N_nu = 100, 2000
nu_grid = jnp.linspace(2000., 2500., N_nu)
dtau = jnp.full((N_layer, N_nu), 0.01) # Optical depth matrix
temperature = jnp.linspace(1500., 500., N_layer)
# 1. Emission spectrum
art_emis = ArtEmisPure(1e-8, 1e2, N_layer, nu_grid, "ibased", nstream=8)
emission = art_emis.run(dtau, temperature)
# 2. Transmission spectrum
art_trans = ArtTransPure(1e-8, 1e2, N_layer, integration="simpson")
mean_mmw = jnp.full(N_layer, 2.33) # g/mol
radius_btm = 7.1492e9 # cm (Jupiter radius)
gravity_btm = 2.5e3 # cm/s²
transmission_sq = art_trans.run(dtau, temperature, mean_mmw, radius_btm, gravity_btm)
# 3. Reflected spectrum
single_scatter = jnp.full_like(dtau, 0.9)
asym_param = jnp.full_like(dtau, 0.0)
surface_refl = jnp.full(N_nu, 0.3)
incoming_flux = jnp.ones(N_nu)
art_reflect = ArtReflectPure(1e-8, 1e2, N_layer, nu_grid, "fluxadding_toon_hemispheric_mean")
reflection = art_reflect.run(dtau, single_scatter, asym_param, surface_refl, incoming_flux)
# Convert to NumPy if needed
import numpy as np
emission_np = np.array(emission)
Key Source Files and Architecture
| File | Purpose |
|---|---|
src/exojax/rt/common.py |
Base class ArtCommon – pressure grids, geometry, and shared utilities. |
src/exojax/rt/emis.py |
Emission engine ArtEmisPure (lines 19–77) and solver registry. |
src/exojax/rt/trans.py |
Transmission engine ArtTransPure (lines 13–48) and integration schemes. |
src/exojax/rt/reflect.py |
Reflection engine ArtReflectPure (lines 16–34) for scattered light. |
src/exojax/rt/rtransfer.py |
Low-level JAX kernels (rtrun_emis_*, rtrun_trans_*, rtrun_reflect_*). |
src/exojax/rt/chord.py |
Chord optical depth geometry for transmission calculations. |
src/exojax/rt/planck.py |
Planck function utilities (piBarr) for thermal emission. |
The architecture flows from ArtCommon (atmospheric scaffolding) through class-specific wrappers to optimized JAX kernels in rtransfer.py.
Summary
- ArtEmisPure: Instantiate with
rtsolver="ibased"or"fbased2st"to compute thermal emission spectra viarun(dtau, temperature). - ArtTransPure: Use
integration="simpson"or"trapezoid"to calculate(radius/radius_btm)²viarun(dtau, temperature, mmw, radius_btm, gravity). - ArtReflectPure: Configure with
rtsolver="fluxadding_toon_hemispheric_mean"to model reflected light viarun(dtau, single_scattering_albedo, asym_param, surface_refl, incoming_flux). - All classes support CKD mode via
run_ckd()variants accepting pre-tabulated optical depths and Gaussian quadrature weights. - Operations are JAX JIT-compiled; first calls incur compilation overhead while subsequent calls execute on GPU/TPU with automatic differentiation support.
Frequently Asked Questions
What solvers are available for ArtEmisPure and how do I choose between them?
ArtEmisPure supports three solvers defined in set_capable_rtsolvers() (lines 56–62 of emis.py): "ibased" (intensity-based n-stream), "fbased2st" (flux-based 2-stream), and "ibased_linsap". Use "ibased" for high accuracy with nstream=8 or higher, or "fbased2st" for faster calculations requiring only 2 streams. The validator ensures parameter consistency before dispatching to the appropriate JAX kernel.
How does ArtTransPure calculate the transit radius geometry?
The class uses atmosphere_height() inherited from ArtCommon to convert pressure layers into physical altitudes, then computes chord optical depths through the planetary limb using the integration method specified ("simpson" or "trapezoid"). The run() method returns the squared ratio of the effective transit radius to the bottom radius, accounting for the atmospheric scale height derived from mean_molecular_weight, temperature, and gravity_btm.
Can I use the same optical depth matrix for emission, transmission, and reflection calculations?
Yes. The dtau matrix (shape [nlayer, ngrid] or [nlayer, ngrid, ncg] for CKD) represents pure absorption and is physics-agnostic regarding the RT mode. You can compute dtau once—using opacity calculators like OpaPremodit or OpaCKD—and pass identical arrays to ArtEmisPure.run(), ArtTransPure.run(), and ArtReflectPure.run(), though reflection additionally requires scattering albedo and asymmetry parameters.
What is the difference between intensity-based and flux-based solvers in emission calculations?
Intensity-based solvers ("ibased") integrate specific intensity over discrete angles using Gaussian quadrature, providing angular-resolved output suitable for limb-darkening studies. Flux-based solvers ("fbased2st") solve the diffusion equation for hemispheric mean fluxes, requiring only 2 streams (nstream=2) and offering computational efficiency for disk-integrated planetary spectra. Choose intensity-based for detailed angular dependence and flux-based for rapid forward-modeling in retrievals.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →