# How to Use ArtEmis, ArtTrans, and ArtReflect Classes for Radiative Transfer in ExoJAX

> Master radiative transfer in ExoJAX! Learn to use ArtEmis, ArtTrans, and ArtReflect classes for emission, transmission, and reflection spectra with JAX-accelerated kernels. Get accurate exoplanet atmospheric data.

- Repository: [Hajime Kawahara/exojax](https://github.com/hajimekawahara/exojax)
- Tags: how-to-guide
- Published: 2026-03-03

---

**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`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/common.py).

## Understanding the Art Common Base Class

All three RT engines extend **`ArtCommon`** ([`src/exojax/rt/common.py`](https://github.com/hajimekawahara/exojax/blob/main/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`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/emis.py), lines 19–35) for self-luminous atmospheres such as hot Jupiters or brown dwarfs.

### Constructor and Solver Selection

```python
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:

```python
emission_spectrum = art_emis.run(dtau, temperature_profile)

```

This method builds the Planck source function (`piBarr` from [`src/exojax/rt/planck.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/planck.py)) and dispatches to JAX kernels such as `rtrun_emis_ibased` in [`src/exojax/rt/rtransfer.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/rtransfer.py).

### Correlated-k (CKD) Mode

For opacity databases using the correlated-k method, use `run_ckd()`:

```python
emission_ckd = art_emis.run_ckd(dtau_ckd, temperature_profile, weights, nu_bands)

```

## Calculating Transmission Spectra with ArtTransPure

**`ArtTransPure`** ([`src/exojax/rt/trans.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/trans.py), lines 13–34) computes wavelength-dependent transit radii for transiting exoplanets.

### Geometry and Integration Setup

```python
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`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/rtransfer.py).

### Computing the Transit Radius

The `run()` method returns the square of the transit radius normalized by the bottom radius:

```python
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`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/chord.py).

### CKD Support

Transmission supports CKD via:

```python
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`](https://github.com/hajimekawahara/exojax/blob/main/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:

```python
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:

```python
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`](https://github.com/hajimekawahara/exojax/blob/main/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:

```python
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`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/common.py) | Base class `ArtCommon` – pressure grids, geometry, and shared utilities. |
| [`src/exojax/rt/emis.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/emis.py) | Emission engine `ArtEmisPure` (lines 19–77) and solver registry. |
| [`src/exojax/rt/trans.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/trans.py) | Transmission engine `ArtTransPure` (lines 13–48) and integration schemes. |
| [`src/exojax/rt/reflect.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/reflect.py) | Reflection engine `ArtReflectPure` (lines 16–34) for scattered light. |
| [`src/exojax/rt/rtransfer.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/rtransfer.py) | Low-level JAX kernels (`rtrun_emis_*`, `rtrun_trans_*`, `rtrun_reflect_*`). |
| [`src/exojax/rt/chord.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/rt/chord.py) | Chord optical depth geometry for transmission calculations. |
| [`src/exojax/rt/planck.py`](https://github.com/hajimekawahara/exojax/blob/main/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`](https://github.com/hajimekawahara/exojax/blob/main/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`](https://github.com/hajimekawahara/exojax/blob/main/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.