Radiation
Introduction
Castro has three radiation solvers:
SingleGroupSolver: this solver does not have radiation pressure. It is pure hydro plus radiation diffusion. This is only applicable when the medium is optically thick and the pressure is small.
SGFLDSolver: this is the gray flux-limited diffusion radiation hydrodymamics solver. Here the radiation pressure is separate from the gas pressure, and both pressures participate in the Riemann solver.
MGFLDSolver: this is the multigroup flux-limited diffusion radiation hydrodynamics solver. As with the gray solver, radiation pressure contributes to the pressure in the Riemann solver. Here a number of energy groups are used to represent the radiation field, and the opacity can be frequency-dependent.
The gray solver has a comoving frame mode and a mixed frame mode, whereas the MG solver uses the comoving frame approach. More details about the formulation and algorithm can be found in the series of Castro papers.
Getting Started
Getting the Code
The Castro radiation solver is part of the main Castro git repo,
so you already have all the Castro code and problem setups
to exercise radiation. The only other requirement is a copy
of the Hypre library. Hypre provides the algebraic multigrid
solvers used by the implicit radiation update. You can get
a copy at https://github.com/hypre-space/hypre (the minimum
supported release version is 2.23.0). Their install
instructions describe what to do; we recommend using the autotools
and GNU Make build. On HPC clusters, you typically want to build
with the same compiler you’re using to build Castro, and you also
want to make sure that the options you’re using for Castro are
compatible with the Hypre options, in particular when it comes to
USE_MPI
, USE_OMP
, and USE_CUDA
.
As an example, to build Hypre on Summit with MPI and CUDA, you
should load the gcc/7.4.0
and spectrum-mpi
modules and
then do the following from the Hypre src/
directory,
replacing /path/to/Hypre/install
with the target location
where you want the Hypre files to be installed.
CUDA_HOME=$OLCF_CUDA_ROOT HYPRE_CUDA_SM=70 CXX=mpicxx CC=mpicc FC=mpifort ./configure --prefix=/path/to/Hypre/install --with-MPI --with-cuda --enable-unified-memory
make install
Then, when you are building Castro, you would build with
USE_MPI=TRUE
and USE_CUDA=TRUE
.
Castro looks for Hypre in the environment variable HYPRE_DIR
,
which you should point to the install directory you chose above.
Other than that, the only difference for builds with radiation
is that you must set USE_RAD=TRUE
.
Microphysics: EOS, Network, and Opacity
EOS
Castro provides several types of equation of state (EOS), including gamma-law and Helmholtz. To use the gamma-law EOS, set
EOS_DIR := gamma_law
in the GNUmakefile.
The original Helmholtz EOS for stellar interiors includes a radiation contribution. However, for radiation hydrodynamics calculations, the radition contribution should be taken out of EOS because radiation has been treated in other places. To use Helmholtz EOS, we will use the version in Microphysics, as with the pure hydrodynamics code, but this will interpret the RADIATION preprocessor variable and disable the radiation portion of the EOS. If you have your own EOS, you can put it in Microphysics.
There is also an artificial EOS that is used for several test cases called
EOS_DIR := rad_power_law
This EOS should only be used for pure radiation-diffusion tests (i.e.
castro.do_hydro = 0
). It defines the specific heat as a power law,
\[c_v = \mathrm{const}\ \rho^m T^{-n}\]
Network
The radiation solver uses the same networks as we saw for pure hydro, so nothing needs to change here. Again, if you are not modeling reactions, then the general_null network can be used to define the appropriate composition for your problem.
Opacity
The most commonly used opacity setup is
where \(\kappa\) is either the Planck or Rosseland absorption coefficients, \(\rho\) is density, \(T\) is temperature, \(\nu\) is frequency, and \(m\), \(n\) and \(p\) are constants. For the gray solver, \(p = 0\). If (25) is sufficient, set
Opacity_dir := rad_power_law
in your GNUmakefile. See § 3.3.1 for instructions on how to configure the parameters used for this opacity setup. If you would prefer a different opacity mechanism, you will need to create your own opacity module by creating a new directory in the Microphysics/opacity directory, creating the same set of subroutines that the others have.
Some notes:
Here, \(\kappa\) has units of \(\mathrm{cm}^{-1}\). Some papers or texts may instead have an implicit density factor in \(\kappa\), yielding units \(\mathrm{cm}^2~\mathrm{g}^{-1}\).
Castro allows for two temperatures (different radiation and gas temperature, so \(E_\mathrm{r} \ne a T_\mathrm{gas}^4\)). Correspondingly, Castro cares about both the Planck mean, \(\kappa_P\), and Rosseland mean, \(\kappa_R\), opacities—these have different weightings.
If we set \(\kappa_P \Delta x \gg 1\) (\(\kappa_P\) is really large), then the two temperatures become the same.
If we set \(\kappa_P = \kappa_R\), then we can see how different the two temperatures are.
In an optically thick medium, we would not expect the two temperatures to be very different.
Opacity Parameters
The parameters describing the opacity include:
For the Planck opacity of the form in (25), the following parameters set the coefficient and exponents. These are set via the
opacity
namespace in the inputs file.opacity.const_kappa_p
must be set positive to be used.opacity.const_kappa_p = -1.0
opacity.kappa_p_exp_m = 0.0
opacity.kappa_p_exp_n = 0.0
opacity.kappa_p_exp_p = 0.0
For the Rosseland opacity of the form in (25), the following parameters set the coefficient and exponents. These are set via the
opacity
namespace in the inputs file.opacity.const_kappa_r
must be set positive to be used.opacity.const_kappa_r = -1.0
opacity.kappa_r_exp_m = 0.0
opacity.kappa_r_exp_n = 0.0
opacity.kappa_r_exp_p = 0.0
For the scattering coefficient of the form in (25), the following parameters set the coefficient and exponents. These are set via the
opacity
namespace in the inputs file.opacity.const_scatter = 0.0
opacity.scatter_exp_m = 0.0
opacity.scatter_exp_n = 0.0
opacity.scatter_exp_p = 0.0
Since the formula above, (25), is non-physical and singular, we must set some floors in practice to prevent numerical issues. We have one floor for the opacity, which is applied to both the Planck and Rosseland opacities, and we also have a temperature floor.
opacity.kappa_floor = 1.d-50
opacity.rad_temp_floor = 0.0
radiation.do_kappa_stm_emission = 0
If it is 1, correction for stimulated emission is applied to Planck mean as follows
\[\kappa = \mathrm{const}\ \rho^{m} T^{-n} \nu^{p} \left [1-\exp{\left (-\frac{h\nu}{k T} \right )} \right ].\]
Note that the unit for opacities is \(\mathrm{cm}^{-1}\). For the gray solver, the total opacity in the diffusion coefficient is the sum of kappa_r and scattering, whereas for the MG solver, there are two possibilities. If const_kappa_r is greater than 0, then the total opacity is set by kappa_r alone, otherwise the total opacity is the sum of kappa_p and scattering.
Radiation Solver Physics
In this section, we list some radiation related parameters that you can set in an inputs file. Here are some important parameters:
radiation.SolverType:
Set it to 5 for the gray solver, and 6 for the MG solver.
castro.do_hydro
Usually you want to set it to 1. If it is set to 0, hydro will be turned off, and the calculation will only solve radiation diffusion equation.
castro.do_radiation
If it is 0, the calculation will be pure hydro.
Below are more parameters. For each parameter, the default value is on the right-hand side of the equal sign.
Verbosity and I/O
radiation.v = 0
Verbosity
radiation.verbose = 0
Verbosity
radiation.plot_lambda = 0
If 1, save flux limiter in plotfiles.
radiation.plot_kappa_p = 0
If 1, save Planck mean opacity in plotfiles.
radiation.plot_kappa_r = 0
If 1, save Rosseland mean opacity in plotfiles.
radiation.plot_lab_Er = 0
If 1, save lab frame radiation energy density in plotfiles. This flag is ignored when the mixed-frame gray solver is used.
radiation.plot_com_flux = 0
If 1, save comoving frame radiation flux in plotfiles.
radiation.plot_lab_flux = 0
If 1, save lab frame radiation flux in plotfiles.
Flux Limiter and Closure
radiation.limiter = 2
Possible values are:
0: No flux limiter
2: Approximate limiter of Levermore & Pomraning
12: Bruenn’s limiter
22: Larsen’s square root limiter
32: Minerbo’s limiter
radiation.closure = 3
Possible values are:
0: \(f = \lambda\), where \(f\) is the scalar Eddington factor and \(\lambda\) is the flux limiter.
1: \(f = \frac{1}{3}\)
2: \(f = 1 - 2 \lambda\)
3: \(f = \lambda + (\lambda R)^2\), where \(R\) is the radiation Knudsen number.
4: \(f = \frac{1}{3} + \frac{2}{3} (\frac{F}{cE})^2\), where \(F\) is the radiation flux, \(E\) is the radiation energy density, and \(c\) is the speed of light.
Note the behavior of the radiative flux in the optically thin and optically thick limits. The flux limiter, \(\lambda = \lambda(R)\), where
Regardless of the limiter chosen, when we are optically thick, \(\chi_R \rightarrow \infty\), \(R \rightarrow 0\), and \(\lambda \rightarrow 1/3\). The radiative flux then becomes
And when we are optically thin, \(\chi_R \rightarrow 0\), \(R \rightarrow \infty\), and \(\lambda \rightarrow 1/R = \chi_R E_r^{(0)}/{|\nabla E_r^{0}|}\), and the radiative flux then becomes
See Krumholz et al. 2007 for some discussion on this.
Boundary Conditions
The following parameters are for the radiation boundary in the diffusion equation. They do not affect hydrodynamic boundaries.
radiation.lo_bc
This sets the action to take at the lower edge of the domain in each coordinate direction. Possible values are:
101 Dirichlet:
Specify the radiation energy density on the boundary. For gray radiation, this could be \(E_r = a T^4\).
For multigroup radiation, Castro stores the energy density as \(\mathrm{erg}~\mathrm{cm}^{-3}\), so the total radiation energy can be found by simply summing over the groups. So if you want to set the radiation BCs using the Planck function, you simply multiply by the group width—see Exec/radiation_tests/RadSphere/Tools/radbc.f90 for an example.
102 Neumann:
Here, you specify the radiation flux on the boundary. For gray radiation, this is the expression given in the gray Castro paper (Eq. 7, 8),
\[F_r = - \frac{c\lambda}{\kappa_R} \nabla E_r\]where \(\lambda\) is the flux limiter.
Note that if your boundary represents an incoming flux through a vacuum (like stellar irradiation), then \(\kappa \rightarrow 0\), leaving
\[F_r = -c E_r\](see § 4.2) in that case.
104 Marshak (vacuum):
Here, you specify the incident flux and the outside is a vacuum. This differs from the Neumann condition because there is also a flux coming from inside, for the net flux across the boundary is different than the incident flux.
105 Sanchez-Pomraning:
This is a modified form of the Marshak boundary condition that works with FLD. This is like the Marshak condition, but \(\lambda = 1/3\) is not assumed inside the boundary (optical thickness).
radiation.hi_bc
See radiation.lo_bc.
radiation.lo_bcflag = 0 0 0
If it is 0, bcval is used for that dimension, otherwise subroutine rbndry in RadBndry_1d.f90 is called to set boundary conditions.
radiation.hi_bcflag = 0 0 0
See radiation.lo_bcflag
radiation.lo_bcval = 0.0 0.0 0.0
The actual value to impose for the boundary condition type set by radiation.lo_bc. This parameter is interpreted differently depending on the boundary condition:
Dirchlet: Dirichlet value of rad energy density
Neumann: inward flux of rad energy
Marshak: incident flux
Sanchez-Pomraning: incident flux
radiation.hi_bcval = 0.0 0.0 0.0
See radiation.lo_bcval
Convergence
For the gray solver, there is only one iteration in the scheme, whereas for the MG solver, there are two iterations with an inner iteration embedded inside an outer iteration. In the following, the iteration in the gray solver will also be referred as the outer iteration for convenience. The parameters for the inner iteration are irrelevant to the gray solver.
- radiation.maxiter = 50
- Maximal number of outer iteration steps.
- radiation.miniter = 1
- Minimal number of outer iteration steps.
- radiation.reltol = 1.e-6
- Relative tolerance for the outer iteration.
- radiation.abstol = 0.0
- Absolute tolerance for the outer iteration.
- radiation.maxInIter = 30
- Maximal number of inner iteration steps.
- radiation.minInIter = 1
- Minimal number of inner iteration steps.
- radiation.relInTol = 1.e-4
- Relative tolerance for the inner iteration.
- radiation.absInTol = 0.0
- Absolute tolerance for the inner iteration.
- radiation.convergence_check_type = 0
- For the MG solver only. This specify the way of checking the convergence of an outer iteration. Possible values are
0: Check \(T\), \(Y_e\), and the residues of the equations for \(\rho e\) and \(\rho Y_e\)
1: Check \(\rho e\)
2: Check the residues of the equations for \(\rho e\) and \(\rho Y_e\)
3: Check \(T\) and \(Y_e\)
Parameters for Gray Solver
- radiation.comoving = 1
- Do we use the comoving frame approach?
- radiation.Er_Lorentz_term = 1
- If the mixed-frame approach is taken, this parameter decides whether Lorentz transformation terms are retained.
- radiation.delta_temp = 1.0
- This is used in computing numerical derivativas with respect to \(T\). So it should be a small number compared with \(T\), but not too small.
- radiation.update_limiter = 1000
- Stop updating flux limiter after update_limiter iteration steps.
- radiation.update_planck = 1000
- Stop updating Planck mean opacity after update_planck iteration steps.
- radiation.update_rosseland = 1000
- Stop updating Rosseland mean opacity after update_rosseland iteration steps.
Grouping in the MG Solver
We provide two methods of setting up groups based upon logarithmic spacing. In both methods, you must provide:
- radiation.nGroups
- Number of groups.
- radiation.lowestGroupHz
- Frequency of the lower bound for the first group.
In addition, if the parameter groupGrowFactor is provided, then the first method will be used, otherwise the second method will be used. In the first way, you must also provide firstGroupWidthHz (the width of the first group). The width of other groups is set to be groupGrowFactor times the width of its immediately preceding group. In the second way, you must provide highestGroupHz as the upper bound of the last group. It should be noted that lowestGroupHz can be 0 in the first method, but not the second method. However, when we compute the group-integrated Planck function, the lower bound for the first group and the upper bound for the last group are assumed to be 0 and \(\infty\), respectively.
Parameters for MG Solver
- radiation.delta_e_rat_dt_tol = 100.0
- Maximally allowed relative change in \(e\) during one time step.
- radiation.delta_T_rat_dt_tol = 100.0
- Maximally allowed relative change in \(T\) during one time step.
- radiation.delta_Ye_dt_tol = 100.0
- Maximally allowed absolute change in \(Y_e\) during one tim estep.
- radiation.fspace_advection_type = 2
- Possible value is 1 or 2. The latter is better.
- radiation.integrate_Planck = 1
- If 1, integrate Planck function for each group. For the first group, the lower bound in the integration is assumed to be 0 no matter what the grouping is. For the last group, the upper bound in the integration is assumed to be \(\infty\).
- radiation.matter_update_type = 0
- How to update matter. 0 is proabaly the best.
- radiation.accelerate = 2
- The inner iteration of the MG solver usually requires an acceleration scheme. Choices are
0: No acceleration
1: Local acceleration
2: Gray acceleration
- radiation.skipAccelAllowed = 0
- If it is set to 1, skip acceleration if it does not help.
- radiation.n_bisect = 1000
- Do bisection for the outer iteration after n_bisec iteration steps.
- radiation.use_dkdT = 1
- If it is 1, \(\frac{\partial \kappa}{\partial T}\) is retained in the Jacobi matrix for the outer (Newton) iteration.
- radiation.update_opacity = 1000
- Stop updating opacities after update_opacity outer iteration steps.
- radiation.inner_update_limiter = 0
- Stop updating flux limiter after inner_update_limiter inner iteration steps. If it is 0, the limiter is lagged by one outer iteration. If it is -1, the limiter is lagged by one time step. If the inner iteration has difficulty in converging, setting this parameter it to -1 can help. Since the flux limiter is only a kludge, it is justified to lag it.
Linear System Solver
There are a number of choices for the linear system solver. The performance of the solvers usually depends on problems and the computer. So it is worth trying a few solvers to find out which one is best for your problem and computer.
radsolve.level_solver_flag: the linear solver in Hypre to use. The available choices are:
0: SMG
1: PFMG (\(\ge\) 2-d only)
100: AMG using ParCSR ObjectType
102: GMRES using ParCSR ObjectType
103: GMRES using SStruct ObjectType
104: GMRES using AMG as preconditioner
109: GMRES using Struct SMG/PFMG as preconditioner
150: AMG using ParCSR ObjectType
1002: PCG using ParCSR ObjectType
1003: PCG using SStruct ObjectType
As a general rule, the SMG is the most stable solver, but is usually the slowest. The asymmetry in the linear system comes from the adaptive mesh, so the PFMG should be your first choice. Note: in you cannot use PFMG.
Setting this to 109 (GMRES using Struct SMG/PFMG as preconditioner) should work reasonably well for most problems.
radsolve.maxiter (default: 40): Maximal number of iteration in Hypre.
radsolve.reltol (default: 1.e-10): Relative tolerance in Hypre
radsolve.abstol (default: 0): Absolute tolerance in Hypre
radsolve.v (default: 0): Verbosity
radsolve.verbos (default: 0): Verbosity
habec.verbose (default: 0): Verbosity for level_solver_flag \(<\) 100
hmabec.verbose (default: 0): Verbosity for level_solver_flag \(>=\) 100
Output
Gray Solver
For the gray radiation solver, the radiation energy density is stored in plotfiles as rad. Note that this quantity has units of \(\mathrm{erg~cm^{-3}}\), which is different that the specify internal energy of the gas \(\mathrm{erg~g^{-1}}\).