Radiation Transport

The radiation_transport package solves the time-dependent equation of photon radiative transfer with a discrete-ordinates (\(S_N\)) method. It transports the specific intensity along a fixed set of angular directions, couples the radiation field to the material internal energy through absorption and emission, and supports grey or multigroup frequency resolution. Two solver variants are provided: an explicit sub-cycled integrator and an implicit Jacobi iteration. Opacities are supplied per material (Chapter Materials and Equations of State).

Governing Equations

Radiative Transfer Equation

The time evolution of the frequency-dependent specific intensity \(I_\nu\) is governed by the transport equation

\[\frac{\partial I_\nu}{\partial t} + c\,\vec{n}\!\cdot\!\nabla I_\nu = c\left(j_\nu - \alpha_\nu I_\nu\right),\]

where \(c\) is the speed of light, \(\vec{n}\) is a unit vector defining the photon propagation direction, and \(j_\nu\) and \(\alpha_\nu\) are the frequency-dependent emissivity and absorptivity, respectively.

Multigroup Formulation

In the multigroup formalism the frequency domain is divided into \(N_\nu\) bins by endpoints \(\nu_0,\nu_1,\dots,\nu_{N_\nu}\), with \(\nu_0 = 0\) and \(\nu_{N_\nu}=\infty\) covering all of frequency space. Integrating the transport equation over group \(f\), with frequency bounds \([\nu_{f-1},\nu_f)\), gives

\[\frac{\partial I_f}{\partial t} + c\,\vec{n}\!\cdot\!\nabla I_f = c\left(j_f - \alpha_f I_f\right),\]

where the subscript \(f\) denotes a quantity integrated over the group (e.g. \(I_f = \int_{\nu_{f-1}}^{\nu_f} I_\nu\,\mathrm{d}\nu\) is the frequency-integrated specific intensity), and the group absorptivity \(\alpha_f\) is a group-mean average.

Assuming a static background medium (material mass density \(\rho\), temperature \(T\)), local thermodynamic equilibrium (LTE), and isotropic elastic scattering, the group transport equation expands to

\[\frac{\partial I_f}{\partial t} + c\,\vec{n}\!\cdot\!\nabla I_f = c\left[\sigma_{s,f}\left(J_f - I_f\right) + \sigma_{a,f}\left(\varepsilon_f - I_f\right)\right],\]

where \(\sigma_{a,f}\) and \(\sigma_{s,f}\) are the group-mean absorption and scattering coefficients of the cell. In a multi-material cell these are aggregated from the per-material opacities as given in Section Multi-Material Opacities; for a single material \(m\) they reduce to \(\sigma_{a,f}=\rho_m\kappa_{a,f,m}\) and \(\sigma_{s,f}=\rho_m\kappa_{s,f,m}\) in terms of the specific opacities \(\kappa_{a,f,m}\), \(\kappa_{s,f,m}\). The group mean intensity over solid angle \(\Omega\) is

\[J_f = \frac{1}{4\pi}\int I_f\,\mathrm{d}\Omega ,\]

and is related to the group radiation energy density by \(E_f = \tfrac{4\pi}{c} J_f = \tfrac{1}{c}\int I_f\,\mathrm{d}\Omega\). The emission coefficient \(\varepsilon_f\) is proportional to the integral of the Planck function \(B(\nu,T)\) over the group band,

\[\begin{split}\varepsilon_f &= \frac{c}{4\pi}\int_{\nu_{f-1}}^{\nu_f} B(\nu,T)\,\mathrm{d}\nu, \qquad\text{where}\\ B(\nu,T) &= \frac{8\pi h\nu^3}{c^3}\, \frac{1}{\exp\!\left(h\nu/[kT]\right) - 1}.\end{split}\]

For a single group with \([\nu_0,\nu_{N_\nu}) \to [0,\infty)\) (i.e. “grey”), \(\varepsilon_f\) reduces to \(\varepsilon_{\text{grey}} = c\,a\,T^4/[4\pi]\), where \(a\) is the radiation constant. The band integrals are evaluated in closed form using polylogarithms.

The frequency group structure (\(N_\nu\) and the group boundaries in Hz) is not an input of the radiation package: it is owned by the materials package and resolved from the <materials> block, the opacity tables, or a grey default, exactly as described in Section Frequency Group Structure. The radiation package reads the resolved structure from the materials package at initialization, so the transport and the opacities always share one group grid.

Stored Intensity and Energy Density

For efficiency the transported field ccrad::intensity stores a scaled intensity that absorbs a factor of \(4\pi/c\) relative to \(I_f\), so that the group radiation energy density is recovered directly as a weighted sum over the discrete directions,

\[E_f = \sum_{a} w_a\,I_{f,a},\]

where \(I_{f,a}\) is the stored intensity in direction \(a\) and the angular quadrature weights \(w_a\) are normalized to \(\sum_a w_a = 1\). The streaming term is discretized with a Rusanov flux weighted by the local optical depth (controlled by beta and taumax), so the scheme transitions smoothly between the optically thin (transport) and optically thick (diffusion) limits. In reduced-dimension curvilinear geometries (1D spherical, 2D cylindrical) an additional angular-flux divergence term (ccrad::divfa) accounts for the rotation of \(\vec{n}\) along curved streaming paths; it is compiled in only for those coordinate systems.

Angular Discretization

The unit sphere of directions is discretized into \(N_{\text{ang}}\) ordinates, each carrying a solid-angle weight. Two quadratures are available, both refined by a single level \(n_{\text{level}}\) (nlevel): a nearly uniform geodesic grid built by subdividing an icosahedron, with \(N_{\text{ang}} = 10\,n_{\text{level}}^2 + 2\), and a latitude–longitude product grid with \(n_\theta = 2\,n_{\text{level}}\) polar and \(n_\phi = 4\,n_{\text{level}}\) azimuthal bins (\(N_{\text{ang}} = 8\,n_{\text{level}}^2\)). In curvilinear geometries, where latitude–longitude is the default, symmetry reduces the azimuthal grid: 2D cylindrical spans only \(\phi\in[0,\pi)\) with \(n_\phi = 2\,n_{\text{level}}\) (\(N_{\text{ang}} = 4\,n_{\text{level}}^2\)), and 1D spherical uses \(n_\phi = 1\) (\(N_{\text{ang}} = 2\,n_{\text{level}}\)). The geodesic grid may be rotated to avoid alignment with the spatial mesh.

Multi-Material Opacities

For \(q\in\{a,s\}\), the Amagat closure evaluates each material’s specific opacity at its material density and volume-averages the resulting coefficients,

\[\sigma^{\mathrm{A}}_{q,f} = \sum_m f_m\rho_m\,\kappa_{q,f,m}(\rho_m,T).\]

The homogeneous closure instead evaluates each material’s specific opacity at its partial density \(f_m\rho_m\),

\[\sigma^{\mathrm{H}}_{q,f} = \sum_m f_m\rho_m\,\kappa_{q,f,m}(f_m\rho_m,T).\]

RIOT blends these closures with \(\chi=\texttt{mix_frac}\),

\[\sigma_{q,f} = (1-\chi)\sigma^{\mathrm{A}}_{q,f} + \chi\sigma^{\mathrm{H}}_{q,f}.\]

The PTE-consistent Amagat closure (\(\chi=0\)) is the default; \(\chi=1\) selects the homogeneous closure.

Matter–Radiation Coupling

When coupling is enabled (coupling), energy exchanged with the radiation field is removed from (or added to) the material internal energy, conserving total energy,

\[\frac{\partial E_{\text{mat}}}{\partial t} = -\,\frac{\partial E_{\text{rad}}}{\partial t}, \qquad E_{\text{rad}} = \sum_f E_f .\]

The exchange is treated implicitly: an advanced material temperature \(T^{n+1}\) is found by a non-linear root solve (tolerance troot_tol, iteration cap troot_max_iter) balancing the emission, absorption, and the change in material energy over the step. This keeps the strong emission/absorption coupling stable at large optical depth. The feedback onto the fluid energy can be suppressed independently with affect_fluid (e.g. to advance the radiation field against a fixed matter state), and the advanced-temperature solve itself can be bypassed with fixed_temp_rhs.

Solvers

Two integrators advance the transport equation. Radiation transport is enabled by setting radiation_transport = true in the <physics> block (Section Enabling Physics: the <physics> Block); the solver is then chosen in the <radiation_transport> block by do_explicit and do_jacobi. Both default to false, and RIOT requires that exactly one be enabled — it is an error to set both or neither.

Radiation transport solvers.

Solver

Description

do_explicit

Sub-cycled explicit integrator (Runge–Kutta), with an optical-depth-weighted Rusanov streaming flux.

do_jacobi

Iterative implicit (Jacobi) solver; robust at large optical depth, iterated to a residual threshold.

Input Parameters

Radiation transport requires hydrodynamics and is incompatible with the ionization package, with sparse physics (Chapter Sparse Physics), and with the P1 radiation diffusion package (Chapter Radiation Diffusion (P1)), which provides an alternative radiation model — at most one of the two may be enabled. Because sparse_physics defaults to true, a radiation run must set it false explicitly in the <physics> block.

Parameters are organized into a shared <radiation_transport> block and three nested blocks. The shared block holds everything common to both solvers (CFL, coupling, angular grid, unit overrides); the chosen solver’s algorithm-specific parameters live in <radiation_transport/explicit> or <radiation_transport/jacobi>; the radiation initial state is set in <radiation_transport/init>; and the drive boundary condition is configured in <radiation_transport/drive>.

Solver selection and shared parameters in the <radiation_transport> block.

Parameter

Type

Default

Description

do_explicit

bool

false

Use the explicit sub-cycled integrator.

do_jacobi

bool

false

Use the implicit Jacobi solver. Exactly one of these two must be true.

cfl

Real

0.8

CFL number for the transport update.

coupling

bool

true

Enable the emission/absorption/scattering source.

affect_fluid

bool

=coupling

Feed the radiation source back onto the fluid energy (requires coupling).

fixed_temp_rhs

bool

false

Skip the advanced-temperature solve in the source term.

beta

Real

geom.

Weight on the local optical depth in the Rusanov flux (\(1.0\) in Cartesian, \(0.0\) in curvilinear geometries).

taumax

Real

large

Cap on the optical depth used in the Rusanov flux (default \(\approx\) Real max).

troot_tol

Real

1e-8

Tolerance for the non-linear temperature root find.

troot_max_iter

int

25

Maximum iterations for the temperature root find.

fixed_pgen_opac

bool

false

Fix opacities to the values set in the problem generator.

mix_frac

Real

0.0

Mixture interpolation from the PTE-consistent Amagat closure (0) to the homogeneous closure (1).

opac_rho_min

Real

0.0

Density floor for opacity evaluations.

opac_temp_min

Real

0.0

Temperature floor for opacity evaluations.

units_override

bool

false

Use a custom (non-CGS) unit system for testing.

c, arad, kb, h

Real

1.0

Speed of light, radiation, Boltzmann, and Planck constants (only when units_override).

The beta, taumax, troot_tol, and troot_max_iter parameters are read only when coupling is true.

Angular-grid parameters (in the <radiation_transport> block).

Parameter

Type

Default

Description

angular_mesh

string

geom.

Angular quadrature: geodesic (Cartesian default) or latlon (curvilinear default).

nlevel

int

1

Angular refinement level for either quadrature (see Angular Discretization).

fv_fix

bool

true

Use solid-angle-averaged (finite-volume) direction cosines.

rotate_geo

int

1

Geodesic rotation: 0 none, 1 automatic, 2 user angles.

zpole, ppole

Real

NaN

Manual geodesic rotation angles (used when rotate_geo = 2).

The explicit solver adds sub-cycling controls:

Parameters in the <radiation_transport/explicit> block.

Parameter

Type

Default

Description

integrator

string

rk2

Time integrator for sub-cycling: rk1, rk2, or rk3.

dt_ratio_hyperbolic

Real

-1.0

Limit the global step to cfl\(\times\)this\(\times\min(\Delta x)/c\); \(-1\) lets radiation sub-cycle without limiting the global step.

verbose

int

0

Diagnostic verbosity (0–3; 3 adds root-find failures).

The Jacobi solver adds iteration and timestep controls:

Parameters in the <radiation_transport/jacobi> block.

Parameter

Type

Default

Description

niter_limit

int

1000

Maximum Jacobi iterations per step.

niter_min

int

geom.

Minimum iterations per step, even if err_thr is already met (default 0 in Cartesian, \(\sim\) the angular-mesh diameter in curvilinear geometries).

err_thr

Real

1e-8

Residual threshold for convergence.

per_group_residual

bool

false

Additionally require each group’s relative residual to meet err_thr_group.

err_thr_group

Real

err_thr

Per-group residual threshold.

per_group_residual_floor

Real

1e-3

Floor on a group’s residual denominator, as a fraction of the all-group total.

split_g1

bool

true

Split the Jacobi coefficient into positive/negative parts for robustness.

dt_ratio_hyperbolic

Real

1e4

Limit the global step to a multiple of the hyperbolic step; \(-1\) disables this controller.

verbose

int

0

Diagnostic verbosity (0–3; higher levels report per-iteration residuals, subcycling, and root-find failures).

Convergence Subcycling

The Jacobi solver performs a single global implicit solve over the whole mesh each step, with the opacities lagged from the start of the step. This is a demanding nonlinear problem, and RIOT provides an escape hatch for the rare case in which an individual solve truly goes off the rails — its residual growing or stalling rather than settling. When a solve is judged to be diverging, it is discarded and the operator-split step is retried from the pristine start-of-step state with the timestep divided by reduce_factor, repeating (reducing further as needed) until each subinterval completes and the full step is covered. It is a robustness backstop rather than part of the normal solve, and it is off by default.

Subcycling is distinct from the ordinary iteration count. Reaching niter_limit is not divergence: a solve that iterates smoothly and is simply cut off at the iteration cap is accepted and committed as usual. A solve is flagged as diverging only when its residual becomes non-finite, or — when the stall detector is enabled — when it fails to improve on its best residual so far for ndiverge_limit consecutive iterations. If subcycling is disabled (nreduce_limit = 0) or the reduction budget is exhausted, a genuinely diverging solve aborts the run.

Convergence-subcycling parameters (in the <radiation_transport/jacobi> block).

Parameter

Type

Default

Description

nreduce_limit

int

0

Maximum number of timestep reductions permitted on divergence; \(0\) disables subcycling (a diverging solve aborts).

reduce_factor

int

2

Integer factor by which the subcycle timestep is divided at each reduction (\(>1\)).

ndiverge_limit

int

-1

Consecutive non-improving iterations that count as divergence and trigger a reduction; \(-1\) disables the stall detector, so only a non-finite residual fails a solve.

Initialization

The radiation field’s initial state is chosen in the <radiation_transport/init> block.

Parameters in the <radiation_transport/init> block.

Parameter

Type

Default

Description

initialization

string

thermal

Initial radiation field: thermal (in equilibrium with the matter, \(E=aT^4\)), zero (empty), or none (leave the problem-generator-set intensity untouched).

Boundary Conditions

By default the radiation intensity inherits the same face boundary conditions as the rest of the mesh (ix1_bc …, Chapter Developer’s guide). Any face may instead be given a drive condition — a prescribed incoming radiation field, either a uniform temperature or a tabulated series of prescribed group radiation energy densities — by naming it in the <radiation_transport/drive> block.

Parameters in the <radiation_transport/drive> block.

Parameter

Type

Default

Description

ix1_bc …ox3_bc

string

default

Per-face selector; set to drive to impose the drive condition on that face.

drive_source

string

constant

Drive source: constant (uniform trad_bc) or table (time series from drive_filename).

trad_bc

Real

0.0

Uniform radiation temperature (K) injected by driven faces (constant mode).

drive_filename

string

—

ASCII table for table mode: column 0 is time (s), columns 1…ngroups are group energy densities \(E_g\) (erg/cm3).

force_upwind_flux_bc

bool

true

Zero the boundary opacity to force a purely upwind flux at a driven face; if false, copy the interior opacity.

Opacities are a material property, not a radiation input: absorption and scattering models are selected per material in each material’s opacity block (opac_a, opac_s), and the frequency group structure on which the transport runs is likewise owned by the materials package. Both are documented in the materials chapter — the opacity models in Section Opacity Models and the group structure in Section Frequency Group Structure.

Registered Fields

The package registers the radiation fields in the table below under the ccrad:: prefix. The stored intensity is the transported field, carrying one component per (group, angle) pair; recall it absorbs the \(4\pi/c\) factor so that \(E_f = \sum_a w_a I_{f,a}\). The remaining fields are derived opacities, moments, and per-solver scratch. Every field also carries the OperatorSplit flag and a per-solver user flag; the set differs between the two solvers, as noted below.

Principal fields registered by the radiation package.

Field

Symbol

Components

Metadata / description

ccrad::intensity

\(I_{f,a}\)

\(N_\nu N_{\text{ang}}\)

Cell, Independent, FillGhost, Intensive, Conserved, OperatorSplit; stored intensity per group and angle (\(4\pi/c\)-scaled). The explicit solver adds WithFluxes; the Jacobi solver registers linear prolongation/restriction ops instead.

ccrad::aa

\(\sigma_{a,f}\)

\(N_\nu\)

Cell, Derived, OneCopy, FillGhost, OperatorSplit; cell absorption coefficient.

ccrad::ss

\(\sigma_{s,f}\)

\(N_\nu\)

Cell, Derived, OneCopy, FillGhost, OperatorSplit; cell scattering coefficient.

ccrad::moments

\(E_f\)

\(N_\nu\)

Cell, Derived, OneCopy, OperatorSplit; group radiation energy density and moments.

ccrad::s1, s2, s3

—

\(N_\nu\)

Cell, Derived, OneCopy, OperatorSplit; auxiliary moment/source scratch (both solvers).

ccrad::divfa

—

\(N_\nu N_{\text{ang}}\)

Cell, Derived, OneCopy, OperatorSplit; angular-flux divergence. Explicit solver only, and only in curvilinear geometries.

ccrad::tauw

—

\(N_\nu\)

Cell, Derived, OneCopy, OperatorSplit; optical-depth weight (Jacobi solver only).

ccrad::temperature

\(T^{n+1}\)

1

Cell, Derived, OneCopy, OperatorSplit; advanced temperature (Jacobi solver only).

Example

A grey, geodesic-grid transport run using the implicit Jacobi solver, coupled to a fixed (non-advecting) fluid, with a power-law absorption opacity on material 0 — the structure of a Marshak-wave problem:

riot.input("physics", hydro=True, radiation_transport=True,
           fixed_fluid=True, sparse_physics=False)

riot.input("material0", label="mat0",
           eos_type="IdealGas", Gamma=1.5, Cv=8.61733e10,
           opac_a="powerlaw",       # absorption opacity model
           kappa0_a=1.56272e22,     # coefficient
           kappa_Tpower_a=-3.0)     # Kramers-like temperature power

riot.input("radiation_transport",
           do_jacobi=True,          # select the implicit solver
           nlevel=1,                # geodesic grid: 12 angles
           coupling=True,
           affect_fluid=True,       # let radiation heat the matter
           beta=5.0)

riot.input("radiation_transport/jacobi",
           err_thr=1.0e-4, niter_limit=200,
           dt_ratio_hyperbolic=5.0e4)

# A hot radiating wall driving the inner-x1 face:
riot.input("radiation_transport/drive", ix1_bc="drive", trad_bc=1.0)
riot.input("radiation_transport/init", initialization="zero")