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, and nlayer define 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 via run(dtau, temperature).
  • ArtTransPure: Use integration="simpson" or "trapezoid" to calculate (radius/radius_btm)² via run(dtau, temperature, mmw, radius_btm, gravity).
  • ArtReflectPure: Configure with rtsolver="fluxadding_toon_hemispheric_mean" to model reflected light via run(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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →