CDR plasma model
The CDR plasma model resides in /Physics/CdrPlasma
and describes plasmas in the drift-diffusion approximation.
This physics model also includes the following subfolders:
/Physics/CdrPlasma/PlasmaModel
which contains various implementation of some plasma models that we have used./Physics/CdrPlasma/TimeSteppers
contains various algorithms for advancing the equations of motion./Physics/CdrPlasma/CellTaggers
contains various algorithms for flagging cells for refinement and coarsening./Physics/CdrPlasma/python
contains Python source files for quickly setting up new applications.
In the CDR plasma model we are solving
The above equations must be supported by additional boundary conditions on electrodes and insulating surfaces.
Radiative transport can be done either in the diffusive approximation or by means of Monte Carlo methods. Diffusive RTE methods involve solving
where \(\Psi\) is the isotropic photon density, \(\kappa\) is an absorption length and \(\eta\) is an isotropic source term. I.e., \(\eta\) is the number of photons produced per unit time and volume. The time dependent term can be turned off and the equation can be solved stationary.
The module also supports discrete photons where photon transport and absorption is done by sampling discrete photons. In general, discrete photon methods incorporate better physics (like shadows) They can easily be adapted to e.g. scattering media. They are, on the other hand, inherently stochastic which implies that some extra caution must be exercised when integrating the equations of motion.
The coupling that is (currently) available in chombo-discharge
is
where \(F\) is the boundary flux on insulators or electrodes (which must be separately implemented).
chombo-discharge
works by embedding the equations above into an abstract C++ framework (see CdrPlasmaPhysics) that the user must implement or reuse existing pieces of, and then compile into an executable.
Simulation quick start
New problems that use the CdrPlasma
physics model are best set up by using the Python tools provided with the module.
Navigate to $DISCHARGE_HOME/Physics/CdrPlasma`
and set up the problem with.
To see the list of available options type
cd $DISCHARGE_HOME/Physics/CdrPlasma
./setup.py --help
The following options are helpful for setting up the problem:
base_dir
The base directory where the application will be placed. Defaults to$DISCHARGE_HOME/MyApplications
.app_name
The application name. The application will be put inbase_dir/app_name
.geometry
The geometry to be used. The geometry must be one of the ones provided in$DISCHARGE_HOME/Geometries
(users can also provide their own models).physics
The plasma physics model. This must be one of the folders/class in$DISCHARGE_HOME/Physics/CdrPlasma/PlasmaModel
(users can also provide their own models). Defaults toCdrPlasmaJSON
(see JSON interface).time_stepper
Time integrator. This must derive fromCdrPlasmaStepper
and must be one of the time steppers in$DISCHARGE_HOME/Physics/CdrPlasma/TimeSteppers
. The default integrator isCdrPlasmaGodunovStepper
.cell_tagger
Cell tagger This must derive fromCdrPlasmaTagger
and must be one of the cell taggers in$DISCHARGE_HOME/Physics/CdrPlasma/CellTaggers
.
For example, to set up a geometry-less that does not use AMR, do
cd $DISCHARGE_HOME
./setup.py -app_name=MyApplication
Solvers
This module uses the following solvers:
Advection-diffusion-reaction solver, CdrSolver.
Electrostatics solvers, FieldSolver.
Radiative transfer solver (either Monte-Carlo or continuum approximation), RtSolver.
Surface charge solver, see Surface ODE solver.
CdrPlasmaPhysics
CdrPlasmaPhysics is an abstract class which represents the plasma physics for the CDR plasma module, i.e. it provides the coupling functions in Eq. 8.
The source code for the class resides in /Physics/CdrPlasma/CD_CdrPlasmaPhysics.H
.
Note that the entire class is an interface, whose implementations are used by the time integrators that advance the equations.
There are no default input parameters for CdrPlasmaPhysics, as users must generally implement their own kinetics. The class exists solely for providing the integrators with the necessary fundamentals for filling solvers with the correct quantities at the same time, for example filling source terms and drift velocities.
A successful implementation of CdrPlasmaPhysics has the following:
Instantiated a list of CdrSpecies. These become Convection-Diffusion-Reaction solvers and contain initial conditions and basic transport settings for the convection-diffusion-reaction solvers.
Instantiated a list RtSpecies. These become Radiative transfer solvers and contain metadata for the radiative transport solvers.
Implemented the core functionality that couple the solvers together.
chombo-discharge
automatically allocates the specified number of convection-diffusion-reaction and radiative transport solvers from the list of species the is intantiated.
For information on how to interface into the CDR solvers, see CdrSpecies.
Likewise, see RtSpecies for how to interface into the RTE solvers.
Implementation of the core functionality is comparatively straightforward, but can lead to boilerplate code. For this reason we also provide an implementation layer JSON interface that provides a plug-and-play interface for specifying the plasma physics.
API
The API for CdrPlasmaPhysics
is as follows:
virtual Real computeAlpha(const RealVect a_E) const = 0;
virtual void advanceReactionNetwork(Vector<Real>& a_cdrSources,
Vector<Real>& a_rteSources,
const Vector<Real> a_cdrDensities,
const Vector<RealVect> a_cdrGradients,
const Vector<Real> a_rteDensities,
const RealVect a_E,
const RealVect a_pos,
const Real a_dx,
const Real a_dt,
const Real a_time,
const Real a_kappa) const = 0;
virtual Vector<RealVect> computeCdrDriftVelocities(const Real a_time,
const RealVect a_pos,
const RealVect a_E,
const Vector<Real> a_cdrDensities) const = 0;
virtual Vector<Real> computeCdrDiffusionCoefficients(const Real a_time,
const RealVect a_pos,
const RealVect a_E,
const Vector<Real> a_cdrDensities) const = 0;
virtual Vector<Real> computeCdrElectrodeFluxes(const Real a_time,
const RealVect a_pos,
const RealVect a_normal,
const RealVect a_E,
const Vector<Real> a_cdrDensities,
const Vector<Real> a_cdrVelocities,
const Vector<Real> a_cdrGradients,
const Vector<Real> a_rteFluxes,
const Vector<Real> a_extrapCdrFluxes) const = 0;
virtual Vector<Real> computeCdrDielectricFluxes(const Real a_time,
const RealVect a_pos,
const RealVect a_normal,
const RealVect a_E,
const Vector<Real> a_cdrDensities,
const Vector<Real> a_cdrVelocities,
const Vector<Real> a_cdrGradients,
const Vector<Real> a_rteFluxes,
const Vector<Real> a_extrapCdrFluxes) const = 0;
virtual Vector<Real> computeCdrDomainFluxes(const Real a_time,
const RealVect a_pos,
const int a_dir,
const Side::LoHiSide a_side,
const RealVect a_E,
const Vector<Real> a_cdrDensities,
const Vector<Real> a_cdrVelocities,
const Vector<Real> a_cdrGradients,
const Vector<Real> a_rteFluxes,
const Vector<Real> a_extrapCdrFluxes) const = 0;
virtual Real initialSigma(const Real a_time, const RealVect a_pos) const = 0;
The above code blocks do the following:
computeAlpha
computes the Townsend ionization coefficient. This is used by the cell tagger.advanceReactionNetwork
provides the coupling \(S = S(t, \mathbf{x}, \mathbf{E}, \nabla\mathbf{E}, n, \nabla n, \Psi)\).computeCdrDriftVelocities
provides the coupling \(\mathbf{v} = \mathbf{v}\left(t, \mathbf{x}, \mathbf{E}, n\right)\).computeCdrDiffusionCoefficients
provides the coupling \(D = \mathbf{v}\left(t, \mathbf{x}, \mathbf{E}, n\right)\).computeCdrElectrodeFluxes
provides the coupling \(F = F(t, \mathbf{x}, \mathbf{E}, n)\) on electrode EBs.computeCdrDielectricFluxes
provides the coupling \(F = F(t, \mathbf{x}, \mathbf{E}, n)\) on dielectric EBs.computeCdrDomainFluxes
provides the coupling \(F = F(t, \mathbf{x}, \mathbf{E}, n)\) on domain sides.
For a fully documented API, see the doxygen API.
Below, we include a brief overview of how CdrPlasmaPhysics
can be directly implemented.
Note that direct implements like these tend to become boilerplate, we also include an interface which implements these functions with pre-defined rules, see JSON interface.
Initializing species
In the constructor, the user should define the advected/diffused species and the radiative transfer species.
These are stored in vectors Vector<RefCountedPtr<CdrSpecies> > m_CdrSpecies
and Vector<RefCountedPtr<RtSpecies> > m_RtSpecies
.
Each species in these vectors become a convection-diffusion-reaction solver or a radiative transfer solver.
See CdrSpecies and RtSpecies for details on how to implement these.
Defining drift velocities
To set the drift velocities, implement computeCdrDriftVelocities
– this will set the drift velocity \(\mathbf{v}\) in the CDR equations:
Vector<RealVect> computeCdrDriftVelocities(const Real a_time,
const RealVect a_pos,
const RealVect a_E,
const Vector<Real> a_cdrDensities) const {
return Vector<RealVect>(m_numCdrSpecies, a_E);
}
This implementation is set the advection velocity equal to \(\mathbf{E}\). For a full plasma simulation, there will also be mobilities involved, which the user is reponsible for obtaining.
Defining diffusion coefficients
To set the diffusion coefficients, implement computeCdrDiffusionCoefficients
– this will set the diffusion coefficient \(D\) in the CDR equations:
Vector<Real> computeCdrDiffusionCoefficients(const Real a_time,
const RealVect a_pos,
const RealVect a_E,
const Vector<Real> a_cdrDensities) const {
return Vector<Real>(m_numCdrSpecies, 1.0);
}
This sets \(D = 1\) for all species involved.
Defining chemistry terms
To set the source terms \(S\), implement advanceReactionNetwork
.
This routine should set the reaction terms for both the CDR equations and the radiative transfer equations.
Note
For the radiative transfer equations we set the isotropic source term \(\eta\) which is the number of ionizing photons produced per unit volume and time.
virtual void advanceReactionNetwork(Vector<Real>& a_cdrSources,
Vector<Real>& a_rteSources,
const Vector<Real> a_cdrDensities,
const Vector<RealVect> a_cdrGradients,
const Vector<Real> a_rteDensities,
const RealVect a_E,
const RealVect a_pos,
const Real a_dx,
const Real a_dt,
const Real a_time,
const Real a_kappa) const {
a_cdrSources = Vector<Real>(m_numCdrSpecies, 1.0);
a_rteSources = Vector<Real>(m_numRteSpecies, 1.0);
}
The above code will set \(S = \eta = 1\) for all species.
We point out that in the plasma module the source terms are always used in the form
where \(S\) is the source term obtained from advanceReactionNetwork
.
This implies that it is possible to define fully implicit integrators directly in advanceReactionNetwork
.
For example, if the reactive problem consisted only of \(\partial_t n = -\frac{n}{\tau}\), one could form a reactive integrator with the implicit Euler rule by first computing \(n^{k+1} = \frac{n^k}{1 + \Delta t/\tau}\) and then linearizing \(S = \frac{n^{k+1} - n^k}{\Delta t}\).
Fluxes at electrode boundaries
To set the fluxes \(F\) on electrode EBs, implement computeCdrElectrodeFluxes
.
Note that the fluxes \(F\) are those occuring in a finite-volume context; i.e. the total injected or extracted mass.
Vector<Real> computeCdrElectrodeFluxes(const Real a_time,
const RealVect a_pos,
const RealVect a_normal,
const RealVect a_E,
const Vector<Real> a_cdrDensities,
const Vector<Real> a_cdrVelocities,
const Vector<Real> a_cdrGradients,
const Vector<Real> a_rteFluxes,
const Vector<Real> a_extrapCdrFluxes) const {
return Vector<Real>(m_numCdrSpecies, 0.0);
}
The input variable a_extrapCdrFluxes
are cell-centered fluxes extrapolated to the EBs.
Fluxes at dielectric boundaries
To set the fluxes \(F\) on dielectric EBs, implement computeCdrDielectricFluxes
.
Note that the fluxes \(F\) are those occuring in a finite-volume context; i.e. the total injected or extracted mass.
Vector<Real> computeCdrDielectricFluxes(const Real a_time,
const RealVect a_pos,
const RealVect a_normal,
const RealVect a_E,
const Vector<Real> a_cdrDensities,
const Vector<Real> a_cdrVelocities,
const Vector<Real> a_cdrGradients,
const Vector<Real> a_rteFluxes,
const Vector<Real> a_extrapCdrFluxes) const {
return Vector<Real>(m_numCdrSpecies, 0.0);
}
The input variable a_extrapCdrFluxes
are cell-centered fluxes extrapolated to the EBs.
Fluxes at domain boundaries
To set the fluxes \(F\) on dielectric EBs, implement computeCdrDielectricFluxes
.
Note that the fluxes \(F\) are those occuring in a finite-volume context; i.e. the total injected or extracted mass.
Vector<Real> computeCdrDomainFluxes(const Real a_time,
const RealVect a_pos,
const int a_dir,
const Side::LoHiSide a_side,
const RealVect a_E,
const Vector<Real> a_cdrDensities,
const Vector<Real> a_cdrVelocities,
const Vector<Real> a_cdrGradients,
const Vector<Real> a_rteFluxes,
const Vector<Real> a_extrapCdrFluxes) const {
return Vector<Real>(m_numCdrSpecies, 0.0);
}
The input variable a_extrapCdrFluxes
are cell-centered fluxes extrapolated to the domain sides.
Setting initial surface charge
To set the initial surface charge on dielectric boundaries, implement
Real initialSigma(const Real a_time, const RealVect a_pos) const{
return 0.0;
}
Time discretizations
Here, we discuss two discretizations of Eq. 7. Firstly, note that there are two layers to the time integrators:
A pure class
CdrPlasmaStepper
which inherits fromTimeSteppers
but does not implement anadvance
method. This class simply provides the base functionality for more easily developing time integrators.CdrPlasmaStepper
contains methods that are necessary for coupling the solvers, e.g. calling the CdrPlasmaPhysics methods at the correct time.Implementations of
CdrPlasmaPhysics
, which implement theadvance
method and can thus be used for advancing models.
The supported time integrators are located in $DISCHARGE_HOME/CdrPlasma/TimeSteppers
.
There are two integrators that are commonly used.
A Godunov operator splitting with either explicit or implicit diffusion. This integrator also supports semi-implicit formulations.
A spectral deferred correction (SDC) integrator with implicit diffusion. This integrator is an implicit-explicit.
Briefly put, the Godunov operator is our most stable integrator, while the SDC integrator is our most accurate integrator.
Godunov operator splitting
The CdrPlasmaGodunovStepper
implements CdrPlasmaStepper
and defines an operator splitting method between charge transport and plasma chemistry.
It has a formal order of convergence of one.
The source code is located in $DISCHARGE_HOME/Physics/CdrPlasma/TimeSteppers/CdrPlasmaGodunovStepper
.
Warning
Splitting the terms yields splitting errors which can dominate for large time steps. Typically, the operator splitting discretization is not suitable for large time steps.
The basic advancement routine for CdrPlasmaGodunovStepper
is as follows:
Advance the charge transport \(\phi^k \rightarrow \phi^{k+1}\) with the source terms set to zero.
Compute the electric field.
Advance the plasma chemistry over the same time step using the field computed above I.e., advance \(\partial_t\phi = S\) over a time step \(\Delta t\).
Advance the radiative transport part. This can also involve discrete photons.
The transport/field steps can be done in various ways: The following transport algorithms are available:
Euler, where everything is advanced with the Euler rule.
Semi-implicit, where the Euler field/transport step is performed with an implicit coupling to the electric field.
In addition, diffusion can be treated
Explicitly, where all diffusion advances are performed with an explicit rule.
Implicitly, where all diffusion advances are performed with an implicit rule.
Automatically, where diffusion advances are performed with an implicit rule only if time steps dictate it, and explicitly otherwise.
Note
When setting up a new problem with the Godunov time integrator, the default setting is to use automatic diffusion and a semi-implicit coupling. These settings tend to work for most problems.
Specifying transport algorithm
To specify the transport algorithm, modify the flag CdrPlasmaGodunovStepper.transport
, and set it to semi_implicit
or euler
.
Everything else is an error.
Note that for the Godunov integrator, it is possible to center the advective discretization at the half time step. That is, the advancement algorithm is
where \(n^{k+1/2}\) is obtained by also including transverse slopes (i.e., extrapolation in time). See Trebotich and Graves [2015] for details. Note that the formal order of accuracy is still one, but the accuracy of the advective discretization is increased substantially.
Specifying diffusion
To specify how diffusion is treated, modify the flag CdrPlasmaGodunovStepper.diffusion
, and set it to auto
, explicit
, or implicit
.
In addition, the flag CdrPlasmaGodunovStepper.diffusion_thresh
must be set to a number.
When diffusion is set to auto
, the integrator switches to implicit diffusion when
where \(\Delta t_{\textrm{A}}\) is the advection-only limited time step and \(\Delta t_{\textrm{AD}}\) is the advection-diffusion limited time step.
Note
When there are multiple species being advected and diffused, the integrator will perform extra checks in order to maximize the time steps for the other species.
Time step limitations
The basic time step limitations for the Godunov integrator are:
Manually set maximum and minimum time steps
Courant-Friedrichs-Lewy conditions, either on advection, diffusion, or both.
The dielectric relaxation time.
The user is responsible for setting these when running the simulation. Note when the semi-implicit scheme is used, it is not necessary to restrict the time step by the dielectric relaxation time.
Spectral deferred corrections
The CdrPlasmaImExSdcStepper
uses implicit-explicit (ImEx) spectral deferred corrections (SDCs) to advance the equations.
This integrator implements the advance
method for CdrPlasmStepper
, and is a high-order method with implicit diffusion.
SDC basics
First, we provide a quick introduction to the SDC procedure. Given an ordinary differential equation (ODE) as
the exact solution is
Denote an approximation to this solution by \(\widetilde{u}(t)\) and the correction by \(\delta(t) = u(t) - \widetilde{u}(t)\). The measure of error in \(\widetilde{u}(t)\) is then
Equivalently, since \(u = \widetilde{u} + \delta\), we can write
This yields
This is called the correction equation. The goal of SDC is to iteratively solve this equation in order to provide a high-order discretization.
The ImEx SDC method in chombo-discharge
uses implicit diffusion in the SDC scheme.
Coupling to the electric field is always explicit.
The user is responsible for specifying the quadrature nodes, as well as setting the number of sub-intervals in the SDC integration and the number of corrections.
In general, each correction raises the discretization order by one.
Time step limitations
The ImEx SDC integrator is limited by
The dielectric relaxation time.
An advective CFL conditions.
In addition to this, the user can specify maximum/minimum allowed time steps.
JSON interface
Since implementations of CdrPlasmaPhysics are usually boilerplate, we provide a class CdrPlasmaJSON
which can initialize and parse various types of initial conditions and reactions from a JSON input file.
This class is defined in $DISCHARGE_HOME/Physics/PlasmaModels/CdrPlasmaJSON
.
CdrPlasmaJSON
is a full implementation of CdrPlasmaPhysics
which supports the definition of various species (neutral, plasma species, and photons) and methods of coupling them.
We expect that CdrPlasmaJSON
provides the simplest method of setting up a new plasma model.
It is also comparatively straightforward to extend the class with further required functionality.
In the JSON interface, the radiative transfer solvers always solve for the number of photons that lead to photoionization events. This means that the interpretation of \(\Psi\) is the number of photoionization events during the previous time step. This is true for both continuum and discrete radiative transfer models.
Usage
To use this plasma model, use -physics CdrPlasmaJSON
when setting up a new plasma problem (see Simulation quick start).
When CdrPlasmaJSON
is instantiated, the constructor will parse species, reactions, initial conditions, and boundary conditions from a JSON file that the user provides.
In addition, users can parse transport data or reaction rates from tabulated ASCII files that they provide.
To specify the input plasma kinetics file, include
Specifying input file
CdrPlasmaJSON
will read a JSON file specified by the input variable CdrPlasmaJSON.chemistry_file
.
Discrete photons
There are two approaches when using discrete photons, and both rely on the user setting up the application with the Monte Carlo photon solver (rather than continuum solvers). For an introduction to the particle radiative transfer solver, see Monte Carlo sampling.
The user must use one of the following:
Set the following class options:
CdrPlasmaJSON.discrete_photons = true McPhoto.photon_generation = deterministic McPhoto.source_type = number
When specifying
CdrPlasmaJSON.discrete_photons = true
,CdrPlasmaJSON
will do a Poisson sampling of the number of photons that are generated in each cell and put this in the radiative transfer solvers’ source terms. This means that the radiative transfer solver source terms contain the physical number of photons generated in one time step. To turn off sampling inside the radiative transfer solver, we specifyMcPhoto.photon_generation = stochastic
and setMcPhoto.source_type = number
to let the solver know that the source contains the number of physical photons.Alternatively, set the following class options:
CdrPlasmaJSON.discrete_photons = false McPhoto.photon_generation = stochastic McPhoto.source_type = volume_rate
In this case the
CdrPlasmaJSON
class will fill the solver source terms with the volumetric rate, i.e. the number of photons produced per unit volume and time. WhenMcPhoto
generates the photons it will compute the number of photons generated in a cell through Poisson sampling \(n = P\left(S_\gamma\Delta V\Delta t\right)\) where \(P\) indicates a Poisson sampling operator.
Fundamentally, the two approaches differ only in where the Poisson sampling is performed. With the first approach, plotting the radiative transfer solver source terms will show the number of physical photons generated. In the second approach, the source terms will show the volume photo-generation rate.
Gas law and neutral background
General functionality
To include the gas law and neutral species, include a JSON object gas
with the field law
specified.
Currently, law
can be either ideal
, troposphere
, or table
.
The purpose of the gas law is to set the temperature, pressure, and neutral density of the background gas. In addition, we specify the neutral species that are used through the simulation. These species are not stored on the mesh; we only store function pointers to their temperature, density, and pressure.
It is also possible to include a field plot
which will then include the temperature, pressure, and density in plot files.
Ideal gas
To specify an ideal gas law, specify ideal gas law as follows:
{"gas":
{
"law": "ideal",
"temperature": 300,
"pressure": 1
}
}
In this case the gas pressure and temperatures will be as indicated, and the gas number density will be computed as
where \(p^\prime\) is the pressure converted to Pascals.
Note that the input temperature should be specified in Kelvin, and the input pressure in atmospheres.
Troposphere
It is also possible to specify the pressure, temperature, and density to be functions of tropospheric altitude. In this case one must specify the extra fields
molar mass
For specifying the molar mass (in \(\textrm{g}\cdot\textrm{mol}^{-1}\)) of the gas.gravity
Gravitational acceleration \(g\).lapse rate
Temperature lapse rate \(L\) in units of \(\textrm{K}/\textrm{m}\).
In this case the gas temperature pressure, and number density are computed as
For example, specification of tropospheric conditions can be included by
{"gas":
{
"law": "troposphere",
"temperature": 300,
"pressure": 1,
"molar_mass": 28.97,
"gravity": 9.81,
"lapse_rate": 0.0065,
"plot": true
}
}
Tabulated
To specify temperature, density, and pressure as function of altitude, set law
to table
and incldue the following fields:
file
For specifying which file we read the data from.height
For specifying the column where the height is stored (in meters).temperature
For specifying the column where the temperature (in Kelvin) is stored.pressure
For specifying the column where the pressure (in Pascals) is stored.density
For specifying the column where the density (in \(\textrm{kg}\cdot\textrm{m}^{-3}\)) is stored.molar mass
For specifying the molar mass (in \(\textrm{g}\cdot\textrm{mol}^{-1}\)) of the gas.min height
For setting the minimum altitude in thechombo-discharge
internal table.max height
For setting the minimum altitude in thechombo-discharge
internal table.res height
For setting the height resolution in thechombo-discharge
internal table.
For example, assume that our file MyAtmosphere.dat
contains the following data:
# z [m] rho [kg/m^3] T [K] p [Pa]
0.0000000E+00 1.2900000E+00 2.7210000E+02 1.0074046E+05
1.0000000E+03 1.1500000E+00 2.6890000E+02 8.8751220E+04
2.0000000E+03 1.0320000E+00 2.6360000E+02 7.8074784E+04
3.0000000E+03 9.2860000E-01 2.5690000E+02 6.8466555E+04
4.0000000E+03 8.3540000E-01 2.4960000E+02 5.9844569E+04
If we want to truncate this data to altitude \(z \ in[1000\,\textrm{m}, 3000\,\textrm{m}]\) we specify:
{"gas":
{
"law": "table",
"file": "ENMSIS_Atmosphere.dat",
"molar mass": 28.97,
"height": 0,
"temperature": 2,
"pressure": 3,
"density": 1,
"min height": 1000,
"max height": 3000,
"res height": 10
}
}
Neutral species background
Neutral species are included by an array neutral species
in the gas
object.
Each neutral species must have the fields
name
Species namemolar fraction
Molar fraction of the species.
If the molar fractions do not add up to one, they will be normalized.
Warning
Neutral species are not tracked on the mesh. They are simply stored as functions that allow us to obtain the (spatially varying) density, temperature, and pressure for each neutral species. If a neutral species needs to be tracked on the mesh (through e.g. a convection-diffusion-reaction solver) it must be defined as a plasma species. See Plasma species.
For example, a standard nitrogen-oxygen atmosphere will look like:
{"gas":
{
"law": "ideal",
"temperature": 300,
"pressure": 1,
"plot": true,
"neutral species":
[
{
"name": "O2",
"molar_fraction": 0.2
},
{
"name": "N2",
"molar_fraction": 0.8
}
]
}
Plasma species
The list of plasma species is included by an array plasma species
.
Each entry must have the entries
name
(string) For identifying the species name.Z
(integer) Species charge number.mobile
(true/false) Mobile species or not.diffusive
(true/false) Diffusive species or not.
Optionally, the field initial data
, can be included for providing initial data to the species
Details are discussed further below.
For example, a minimum version would look like
{"plasma species":
[
{"name": "N2+", "Z": 1, "mobile": false, "diffusive": false},
{"name": "O2+", "Z": 1, "mobile": false, "diffusive": false},
{"name": "O2-", "Z": -1, "mobile": false, "diffusive": false}
]
}
Initial data
Initial data can be provided with
Function based densities.
Computational particles (deposited using a nearest-grid-point scheme).
Density functions
To provide initial data one include initial data
for each species.
Currently, the following fields are supported:
uniform
For specifying a uniform background density. Simply the fielduniform
and a density (in units of \(m^{-3}\))gauss2
for specifying Gaussian seeds \(n = n_0\exp\left(-\frac{\left(\mathbf{x}-\mathbf{x_0}\right)^2}{2R^2}\right)\).gauss2
is an array where each array entry must containradius
, for specifying the radius \(R\):amplitude
, for specifying the amplitude \(n_0\).position
, for specifying the seed position \(\mathbf{x}\).
The position must be a 2D/3D array.
gauss2
for specifying Gaussian seeds \(n = n_0\exp\left(-\frac{\left(\mathbf{x}-\mathbf{x_0}\right)^4}{2R^4}\right)\).gauss4
is an array where each array entry must containradius
, for specifying the radius \(R\):amplitude
, for specifying the amplitude \(n_0\).position
, for specifying the seed position \(\mathbf{x}\).
The position must be a 2D/3D array.
height profile
For specifying a height profile along \(y\) in 2D, and \(z\) in 3D. To include it, prepare an ASCII files with at least two columns. The height (in meters) must be specified in one column and the density (in units of \(m^{-3}\)) in another. Internally, this data is stored in a lookup table (see Chap:LookupTable1D). Required fields arefile
, for specifying the file.height
, for specifying the column that stores the height.density
, for specifying the column that stores the density.min height
, for trimming data to a minimum height.max height
, for trimming data to a maximum height.res height
, for specifying the resolution height in thechombo-discharge
lookup tables.
In addition, height and density columns can be scaled in the internal tables by including
scale height
for scaling the height data.scale density
for scaling the density data.
Note
When multiple initial data fields are specified, chombo-discharge
takes the superposition of all of them.
Initial particles
Initial particles can be included with the initial particles
field.
The current implementation supports
uniform
For drawing initial particles randomly distributed inside a box. The user must specify the two cornerslo corner
andhi corner
that indicate the spatial extents of the box, and thenumber
of computational particles to draw. The weight is specified by a fieldweight
. For example:{"plasma species": [ { "name": "e", "Z": -1, "mobile": true, "diffusive": true, "initial particles": { "uniform": { "lo corner": [0,0,0], "hi corner": [1,1,1], "number": 100, "weight": 1.0 } } } ] }
sphere
For drawing initial particles randomly distributed inside a sphere. Mandatory fields arecenter
for specifying the sphere center.radius
for specifying the sphere radius.number
for the number of computational particles.weight
for the initial particle weight.
{"plasma species": [ { "name": "e", "Z": -1, "mobile": true, "diffusive": true, "initial particles": { "sphere": { "center": [0,0,0], "radius": 1.0, "number": 100, "weight": 1.0 } } } ] }
copy
For using an already initialized particle distribution. The only mandatory fields iscopy
, e.g.
Complex example
For example, a species with complex initial data that combines density functions with initial particles can look like:
{"plasma species":
[
{
"name": "N2+",
"Z": 1,
"mobile": false,
"diffusive": false,
"initial data": {
"uniform": 1E10,
"gauss2" :
[
{
"radius": 100E-6,
"amplitude": 1E18,
"position": [0,0,0]
},
{
"radius": 200E-6,
"amplitude": 2E18,
"position": [1,0,0]
}
],
"gauss4":
[
{
"radius": 300E-6,
"amplitude": 3E18,
"position": [0,1,0]
},
{
"radius": 400E-6,
"amplitude": 4E18,
"position": [0,0,1]
}
],
"height profile": {
"file": "MyHeightProfile.dat",
"height": 0,
"density": 1,
"min height": 0,
"max height": 100000,
"res height": 10,
"scale height": 100,
"scale density": 1E6
}
},
"initial particles": {
"sphere": {
"center": [0,0,0],
"radius": 1.0,
"number": 100,
"weight": 1.0
}
}
}
]
}
Mobilities
If a species is specified as mobile, the mobility is set from a field mobility
, and the field lookup
is used to specify the method for computing it.
Currently supported are:
Constant mobility.
Function-based mobility, i.e. \(\mu = \mu(E,N)\).
Tabulated mobility, i.e. \(\mu = \mu(E,N)\).
The cases are discussed below.
Constant mobility
Setting lookup
to constant
lets the user set a constant mobility.
If setting a constant mobility, the field value
is also required.
For example:
{"plasma species":
[
{"name": "e", "Z": -1, "mobile": true, "diffusive": false,
"mobility": {
"lookup" : "constant",
"value": 0.05,
}
}
]
}
Function-based mobility
Setting lookup
to function E/N
lets the user set the mobility as a function of the reduced electric field.
When setting a function-based mobility, the field function
is also required.
Supported functions are:
ABC
, in which case the mobility is computed as\[\mu(E) = A \frac{E^B}{N^C}.\]The fields
A
,B
, andC
must also be specified. For example:{"plasma species": [ {"name": "e", "Z": -1, "mobile": true, "diffusive": false, "mobility": { "lookup" : "function E/N", "function": "ABC", "A": 1, "B": 1, "C": 1 } } ] }
Tabulated mobility
Specifying lookup
to table E/N
lets the user set the mobility from a tabulated value of the reduced electric field.
BOLSIG-like files can be parsed by specifying the header which contains the tabulated data, and the columns that identify the reduced electric field and mobilities.
This data is then stored in a lookup table, see Chap:LookupTable1D.
For example:
{"plasma species":
[
{"name": "e", "Z": -1, "mobile": true, "diffusive": false,
"mobility": {
"lookup" : "table E/N",
"file": "transport_file.txt",
"header": "# Electron mobility (E/N, mu*N)",
"E/N ": 0,
"mu*N": 1,
"min E/N": 10,
"max E/N": 1000,
"points": 100,
"spacing": "exponential",
"dump": "MyMobilityTable.dat"
}
}
]
}
In the above, the fields have the following meaning:
file
The file where the data is found. The data must be stored in rows and columns.header
, the contents of the line preceding the table data.E/N
, the column that contains \(E/N\).mu*N
, the column that contains \(\mu\cdot E\).min E/N
, for trimming the data range.max E/N
, for trimming the data range.points
, for specifying the number of points in the lookup table.spacing
, for specifying how to regularize the table.dump
, an optional argument (useful for debugging) which will write the table to file.
Note that the input file does not need regularly spaced or sorted data. For performance reasons, the tables are always resampled, see Chap:LookupTable1D.
Diffusion coefficients
Setting the diffusion coefficient is done exactly in the same was as the mobility.
If a species is diffusive, one must include the field diffusion
as well as lookup
.
For example, the JSON input for specifying a tabulated diffusion coefficient is done by
{"plasma species":
[
{"name": "e", "Z": -1, "mobile": false, "true": false,
"diffusion": {
"lookup" : "table E/N",
"file": "transport_file.txt",
"header": "# Electron diffusion coefficient (E/N, D*N)",
"E/N ": 0,
"D*N": 1,
"min E/N": 10,
"max E/N": 1000,
"points": 1000,
"spacing": "exponential"
}
}
]
}
Temperatures
Plasma species temperatures can set by including a field temperature
for the plasma species.
Warning
If the temperature
field is omitted, the species temperature will be set to the gas temperature.
Constant temperature
To set a constant temperature, include the field temperature
and set lookup
to constant and specify the temperature through the field value
as follows:
{"plasma species":
[
{
"name": "O2",
"Z": 0,
"mobile": false,
"true": false,
"temperature": {
"lookup": "constant",
"value": 300
}
}
]
}
Tabulated temperature
To include a tabulated temperature \(T = T(E,N)\), set lookup
to table E/N
.
The temperature is then computed as
where \(\epsilon\) is the energy and \(k_{\textrm{B}}\) is the Boltzmann constant.
The following fields are required:
file
for specifying which file the temperature is stored.header
for specifying where in the file the temperature is stored.E/N
for specifying in which column we find \(E/N\).eV
for specifying in which column we find the species energy (in units of electron volts).min E/N
for trimming the data range.max E/N
for trimming the data range.points
for setting the number of points in the lookup table.spacing
for setting the grid point spacing type.dump
for writing the final table to file.
For a further explanation to these fields, see Mobilities.
A complete example is:
{"plasma species":
[
{
"name": "e",
"Z": -1,
"mobile": true,
"true": true,
"temperature": {
"lookup": "table E/N",
"file": "transport_data.txt",
"header": "# Electron mean energy (E/N, eV)",
"E/N": 0,
"eV": 1,
"min E/N": 10,
"max E/N": 1000,
"points": 1000,
"spacing": "exponential",
"dump": "MyTemperatureTable.dat"
}
}
]
}
Photon species
As for the plasma species, photon species (for including radiative transfer) are included by an array photon species
.
For each species, the required fields are
name
For setting the species name.kappa
For specifying the absorption coefficient.
Currently, kappa
can be either
constant
Which lets the user set a constant absorption coefficient.helmholtz
Computes the absorption coefficient as\[\kappa = \frac{p_X\lambda}{\sqrt{3}}\]where \(\lambda\) is a specified input parameter and \(p_X\) is the partial pressure of some species \(X\).
stochastic A
which samples a random absorption coefficient as\[\kappa = K_1 \left(\frac{K_2}{K_1}\right)^{\frac{f-f1}{f2-f1}}.\]Here, \(f_1\) and \(f_2\) are frequency ranges, \(K_1\) and \(K_2\) are absorption coefficients, and \(f\) is a stochastically sampled frequency. Note that this method is only sensible when using discrete photons.
Constant absorption coefficients
When specifying a constant absorption coefficient, one must include a field value
as well.
For example:
{"photon species":
[
{
"name": "UVPhoton",
"kappa": "constant",
"value": 1E4
}
]
}
Helmholtz absorption coefficients
The interface for the Helmholtz-based absorption coefficients are inspired by Bourdon et al. [2007] approach for computing photoionization. This method only makes sense if doing a Helmholtz-based reconstruction of the photoionization profile as a relation:
where
\(S_\gamma\) is the number of photoionization events per unit volume and time.
\(A\) is a model coefficient.
\(\frac{p_q}{p + p_q}\) is a quenching factor.
\(\xi\) is a photoionization efficiency.
\(\nu\) is a relative excitation efficiency.
\(S_i\) is the electron impact ionization source term.
Since the radiative transfer solver is based on the Eddington approximation, the Helmholtz reconstruction can be written as
where the absorption coefficient is set as
The photogeneration source term is still
but the photoionization term is
Note that the photoionization term is, in principle, not an Eddington approximation. Rather, the Eddington-like equations occur here through an approximation of the exact integral solution to the radiative transfer problem. In the pure Eddington approximation, on the other hand, \(\Psi\) represents the total number of ionizing photons per unit volume, and we would have \(S_\gamma = \frac{\Psi}{\Delta t}\) where \(\Delta t\) is the time step.
When specifying the kappa
field as helmholtz
, the absorption coefficient is computed as
where \(p_X\) is the partial pressure of a species \(X\) and \(\lambda\) is the same input parameter as in the Helmholtz reconstruction.
These are specified through fields neutral
and lambda
as follows:
{"photon species":
[
{
"name": "UVPhoton",
"kappa": "helmholtz",
"lambda": 0.0415,
"neutral": "O2"
}
]
}
This input will set \(\kappa\left(\mathbf{x}\right) = \frac{p_{\textrm{O}_2}\left(\mathbf{x}\right)\lambda}{\sqrt{3}}\).
Note
The source term \(\eta\) is specified when specifying the plasma reactions, see Plasma reactions.
Stochastic sampling
Setting the kappa
field to stochastic A
will stochastically sample the absorption length from
where \(K_1 = p_X\chi_{\textrm{min}}\), \(K_1 = p_X\chi_{\textrm{max}}\), and \(f_1\) and \(f_2\) are frequency ranges. Like above, \(p_X\) is the partial pressure of some species \(X\). Note that all input parameters are given in SI units.
Stochastic sampling of the absorption length only makes sense when using discrete photons – this particular method is inspired by the method in Chanrion and Neubert [2008]. For example:
{"photon species":
[
{
"name": "UVPhoton",
"kappa": "stochastic A",
"neutral": "O2",
"f1": 2.925E15,
"f2": 3.059E15,
"chi min": 2.625E-2,
"chi max": 1.5
}
]
}
Plasma reactions
Plasma reactions are reactions between charged and neutral species and are written in the form
Importantly, the left hand side of the reaction can only consist of charged or neutral species. It is not permitted to put a photon species on the left hand side of these reactions; photo-ionization is handled separately by another set of reaction types (see Photo-reactions). However, photon species can appear on the left hand side of the equation.
When specifying reactions in this form, the reaction rate is computed as
When computing the source term for some species \(X\), we subtract \(R\) for each time \(X\) appears on the left hand side of the reaction and add \(R\) for each time \(X\) appears on the right-hand side of the reaction.
Specifying reactions
Reactions of the above type are handled by a JSON array plasma reactions
, with required fields:
reaction
(string) containing the reaction process.lookup
(string) for determining how to compute the reaction rate.
{"plasma reactions":
[
{
"reaction": "e + O2 -> e + e + O2+",
"lookup": "constant",
"rate": 1E-30
}
]
}
This adds a reaction \(\textrm{e} + \textrm{O}_2 \rightarrow \textrm{e} + \textrm{e} + \textrm{O}_2^+\) to the reaction set. We compute
and set
Some caveats when setting the reaction string are:
Whitespace are separators. For example,
O2+e
will be interpreted as a species with string identifierO2+e
, butO2 + e
will interpreted as a reaction betweenO2
ande
.The reaction string must contain a left and right hand side separated by
->
. An error will be thrown if this symbol can not be found.The left-hand must consist only of neutral or plasma species. If the left-hand side consists of species that are not neutral or plasma species, an error will be thrown.
The right-hand side can consist of either neutral, plasma species, or photon species. Otherwise, an error will be thrown.
The reaction string will be checked for charge conservation.
Note that if a reaction involves a right-hand side that is not otherwise tracked, the user should omit the species from the right-hand side altogether. For example, if we have a model which tracks the species \(e\) and \(\textrm{O}_2^+\) but we want to include the dissociative recombination reaction \(e + \textrm{O}_2^+ \rightarrow O + O\), this reaction should be added to the reaction with an empty right-hand side:
{"plasma reactions":
[
{
"reaction": "e + O2 -> e + e + O2+",
"lookup": "constant",
"rate": 1E-30
},
{
"reaction": "e + O2+ -> ",
"lookup": "constant",
"rate": 1E-30
}
]
}
Wildcards
Reaction specifiers may include the wildcard @
which is a placeholder for another species.
The wildcards must be specified by including a JSON array @
of the species that the wildcard is replaced by.
For example:
{"plasma reactions":
[
{
"reaction": "N2+ + N2 + @ -> N4+ + @",
"@": ["N2", "O2"],
"lookup": "constant",
"rate": 1E-30
}
]
}
The above code will add two reactions to the reaction set: \(N_2 + N_2 + N_2 \rightarrow N_4^+ + N_2\) and \(N_2 + N_2 + \textrm{O}_2 \rightarrow N_4^+ + \textrm{O}_2\). It is not possible to set different reaction rates for the two reactions.
Specifying reaction rates
Constant reaction rates
To set a constant reaction rate for a reaction, set the field lookup
to "constant"
and specify the rate.
For example:
{"plasma reactions":
[
{
"reaction": "e + O2 -> e + e + O2+",
"lookup": "constant",
"rate": 1E-30
}
]
}
Single-temperature rates
functionT A
To set a rate dependent on a single species temperature in the form \(k(T) = c_1T^{c_2}\), setlookup
tofunctionT A
. The user must specify the species from which we compute the temperature \(T\) by including a fieldT
. The constants \(c_1\) and \(c_2\) must also be included.For example, in order to add a reaction \(e + \textrm{O}_2 \rightarrow \varnothing\) with rate \(k = 1.138\times 10^{-11}T_{\textrm{e}}^{-0.7}\) we can add the following:
{"plasma reactions": [ { "reaction": "e + M+ ->", "lookup": "functionT A", "T": "e", "c1": 1.138 "c2": -0.7 } ] }
Two-temperature rates
functionT1T2 A
To set a rate dependent on two species temperature in the form \(k(T_1, T_2) = c_1\left(T_1/T_2\right)^{c_2}\), setlookup
tofunctionT1T2 A
. The user must specify which temperatures are involved by specifying the fieldsT1
,T2
, as well as the constants through fieldsc1
andc2
. For example, to include the reaction \(e + \textrm{O}_2 + \textrm{O}_2 \rightarrow \textrm{O}_2^- + O2\) in the set, with this reaction having a rate\[k = 2.4\times 10^{-41}\left(\frac{T_{\textrm{O}_2}}{T_e}\right),\]we add the following:
{"plasma reactions": [ { "reaction": "e + O2 + O2 -> O2- + O2", "lookup": "functionT1T2 A", "T1": "O2", "T2": "e", "c1": 2.41E-41, "c2": 1 } ] }
Townsend ionization and attachment
To set standard Townsend ionization and attachment reactions, set lookup
to alpha*v
and eta*v
, respectively.
This will compute the rate constant \(k = \alpha \left|\mathbf{v}\right|\) where \(\mathbf{v}\) is the drift velocity of some species.
To specify the species one includes the field species
.
For example, to include the reactions \(e \rightarrow e + e + M^+\) and \(e \rightarrow M^-\) one can specify the reactions as
{"plasma reactions":
[
{
"reaction": "e -> e + e + M+",
"lookup": "alpha*v",
"species": "e"
},
{
"reaction": "e -> M-",
"lookup": "eta*v",
"species": "e"
}
]
}
Tabulated rates
To set a tabulated rate with \(k = k(E,N)\), set the field lookup
to table E/N
and specify the file, header, and data format to be used.
For example:
{"plasma reactions":
[
{
"reaction": "e + O2 -> e + e + O2+",
"lookup": "table E/N",
"file": "transport_file.txt",
"header": "# O2 ionization (E/N, rate/N)",
"E/N ": 0,
"rate/N": 1,
"min E/N": 10,
"max E/N": 1000,
"spacing": "exponential",
"points": 1000,
"plot": true,
"dump": "O2_ionization.dat"
}
]
}
The file
field specifies which field to read the reaction rate from, while header
indicates where in the file the reaction rate is found.
The file parser will read the files below the header line until it reaches an empty line.
The fields E/N
and rate/N
indicate the columns where the reduced electric field and reaction rates are stored.
The final fields min E/N
, max E/N
, and points
are formatting fields that trim the range of the data input and organizes the data along a table with points
entries.
As with the mobilities (see Mobilities), the spacing
argument determines whether or not the internal interpolation table uses uniform or exponential grid point spacing.
Finally, the dump
argument will tell chombo-discharge
to dump the table to file, which is useful for debugging or quality assurance of the tabulated data.
Modifying reactions
Collisional quenching
To quench a reaction, include a field qenching_pressure
and specify the quenching pressure (in atmospheres).
When computing reaction rates, the rate for the reaction will be modified as
where \(p^q\) is the quenching pressure and \(p = p(\mathbf{x})\) is the gas pressure.
Important
The quenching pressure should be specified in Pascal.
For example:
{"plasma reactions":
[
{
"reaction": "e + N2 -> e + N2 + Y",
"lookup": "table E/N",
"file": "transport_file.txt",
"header": "# N2 ionization (E/N, rate/N)",
"E/N ": 0,
"rate/N": 1,
"min E/N": 10,
"max E/N": 1000,
"points": 1000,
"spacing": "exponential",
"quenching pressure": 4000
}
]
}
Reaction efficiencies
To modify a reaction efficiency, include a field efficiency
and specify it.
This will modify the reaction rate as
where \(\nu\) is the reaction efficiency. For example:
{"plasma reactions":
[
{
"reaction": "e + N2 -> e + N2 + Y",
"lookup": "table E/N",
"file": "transport_file.txt",
"header": "# N2 ionization (E/N, rate/N)",
"E/N ": 0,
"rate/N": 1,
"min E/N": 10,
"max E/N": 1000,
"points": 1000,
"spacing": "exponential",
"efficiency": 0.6
}
]
}
Scaling reactions
Reactions can be scaled by including a scale
argument to the reaction.
This works exactly like the efficiency
field outlined above.
Energy correction
Occasionally, it can be necessary to incorporate an energy correction to models, accounting e.g. for electron energy loss near strong gradients.
The JSON interface supports the correction in Soloviev and Krivtsov [2009].
To use it, include an (optional) field soloviev
and specify correction
and species
.
For example:
{"plasma reactions":
[
{
"reaction": "e + N2 -> e + N2 + Y",
"lookup": "table E/N",
"file": "transport_file.txt",
"header": "# N2 ionization (E/N, rate/N)",
"E/N ": 0,
"rate/N": 1,
"min E/N": 10,
"max E/N": 1000,
"points": 1000,
"spacing": "exponential",
"efficiency": 0.6,
"soloviev": {
"correction": true,
"species": "e"
}
}
]
}
When this energy correction is enabled, the rate coefficient is modified as
where \(s\) is the species specified in the soloviev
field, \(n_s\) is the density and \(D_s\) and \(\mu_s\) are diffusion and mobility coefficients.
We point out that the correction factor is restricted such that the reaction rate is always non-negative.
Note that this correction makes sense when rates are dependent only on the electric field, see Soloviev and Krivtsov [2009].
Note
When using the energy correction, the specifies species must be both mobile and diffusive.
Plotting reactions
It is possible to have CdrPlasmaJSON
include the reaction rates in the HDF5 output files by including a field plot
as follows:
{"plasma reactions":
[
{
"reaction": "e + O2 -> e + e + O2+",
"plot": true,
"lookup": "constant",
"rate": 1E-30,
}
]
}
Plotting the reaction rate can be useful for debugging or analysis. Note that it is, by extension, also possible to add useful data to the I/O files from reactions that otherwise do not contribute to the discharge evolution. For example, if we know the rate \(k\) for excitation of nitrogen to a specific excited state, but do not otherwise care about tracking the excited state, we can add the reaction as follows:
{"plasma reactions":
[
{
"reaction": "e + N2 -> e + N2",
"plot": true,
"lookup": "constant",
"rate": 1E-30,
}
]
}
This reaction is a dud in terms of the discharge evolution (the left and right hand sides are the same), but it can be useful for plotting the excitation rate.
Note
This functionality should be used with care because each reaction increases the I/O load.
Warnings and caveats
Note that the JSON interface always computes reactions as if they were specified by the deterministic reaction rate equation
where the fluid source term for any reaction \(r\) is \(S_r = k_r n_j n_k n_l\ldots\). Caution should always be exercised when defining a reaction set.
Higher-order reactions
Usually, many rate coefficients depend on the output of other software (e.g., BOLSIG+) and the scaling of rate coefficients is not immediately obvious. This is particularly the case for three-body reactions with BOLSIG+ that may require scaling before running the Boltzmann solver (by scaling the input cross sections), or after running the Boltzmann solver, in which case the rate coefficients themselves might require scaling. In any case the user should investigate the cross-section file that BOLSIG+ uses, and figure out the required scaling.
Important
For two-body reactions, e.g. \(A + B\rightarrow \varnothing\) the rate coefficient must be specified in units of \(\textrm{m}^3\textrm{s}^{-1}\), while for three-body reactions \(A + B + C\rightarrow\varnothing\) the rate coefficient must have units of \(\textrm{m}^6\textrm{s}^{-1}\).
For three-body reactions the units given by BOLSIG+ in the output file may or may not be incorrect (depending on whether or not the user scaled the cross sections).
Townsend coefficients
Townsend coefficients are not fundamentally required for specifying the reactions, but as with the higher-order reactions some of the output rates for three-body reactions might be inconsistently represented in the BOLSIG+ output files. For example, some care might be required when using the Townsend attachment coefficient for air when the reaction \(\textrm{e} + \textrm{O}_2 + \textrm{O}_2\rightarrow \textrm{O}_2^- + \textrm{O}_2\) is included because the rate constant might require proper scaling after running the Boltzmann solver, but this scaling is invisible to the BOLSIG+’s calculation of the attachment coefficient \(\eta/N\).
Warning
The JSON interface does not guard against inconsistencies in the user-provided chemistry, and provision of inconsistent \(\eta/N\) and attachment reaction rates are quite possible.
Photo-reactions
Photo-reactions are reactions between charged/neutral and photons in the form
where species \(A, B, \ldots\) are charged and neutral species and \(\gamma\) is a photon. The left hand side can contain only one photon species, and the right-hand side can not contain a photon species. In other words, two-photon absorption is not supported, and photons that are absorbed on the mesh cannot become new photons. This is not a fundamental limitation, but a restriction imposed by the JSON interface.
Specifying reactions
Reactions of the above type are handled by a JSON array photo reactions
, with required fields:
reaction
(string) containing the reaction process.lookup
(string) for determining how to compute the reaction rate.
For example:
{"photo reactions":
[
{"reaction": "Y + O2 -> e + O2+"},
]
}
The rules for specifying reaction strings are the same as for the plasma reactions, see Plasma reactions. Wildcards also apply, see Wildcards.
Default behavior
Since the radiative transfer solvers solve for the number of ionizing photons, the CDR solver source terms are incremented by
where \(\Psi\) is the number of ionizing photons per unit volume (i.e., the solution \(\Psi\)).
Helmholtz reconstruction
When performing a Helmholtz reconstruction the photoionization source term is
To modify the source term for consistency with Helmholtz reconstruction specify the field helmholtz
with variables
A
. the \(A\) coefficient.lambda
. the \(\lambda\) coefficient. This value will also be specified in the photon species, but it is not retrieved automatically.neutral
. The neutral species for which we obtain the partial pressure.
For example:
{"photo reactions":
[
{
"reaction": "Y + O2 -> e + O2+",
"helmholtz": {
"A": 1.1E-4,
"lambda": 0.0415,
"neutral": "O2"
}
}
]
}
Scaling reactions
Photo-reactions can be scaled by including a scale
argument.
For example, to completely turn off the photoreaction above:
{"photo reactions":
[
{
"reaction": "Y + O2 -> e + O2+",
"helmholtz": {
"A": 1.1E-4,
"lambda": 0.0415,
"neutral": "O2"
},
"scale": 0.0
}
]
}
EB boundary conditions
Boundary conditions on the embedded boundary are included by the fields
electrode reactions
, for specifying secondary emission on electrodes.dielectric reactions
, for specifying secondary emission on dielectrics.
To include secondary emission, the user must specify a reaction string in the form \(A \rightarrow B\), and also include an emission rate. Currently, we only support constant emission rates (i.e., secondary emission coefficients). This is likely to change in the future.
The following points furthermore apply:
By default, standard outflow boundary conditions. When
electrode reactions
ordielectric reactions
are specified, the user only controls the inflow back into the domain.Wildcards can appear on the left hand side of the reaction.
If one specifies \(A + B \rightarrow C\) for a surface reaction, this is the same as specifying two reactions \(A \rightarrow C\) and \(B\rightarrow C\). The same emission coefficient will be used for both reactions.
Both photon species and plasma species can appear on the left hand side of the reaction.
Photon species can not appear on the right-hand side of the reaction; we do not include surface sources for photoionization.
To scale reactions, include a modifier
scale
.
For example, the following specification will set secondary emission efficiencies to \(10^{-3}\):
{"electrode reactions":
[
{ "reaction": "@ -> e",
"@": ["N2+", "O2+", "N4+", "O4+", "O2+N2"],
"lookup": "constant",
"value": 1E-4
}
],
"dielectric reactions":
[
{ "reaction": "@ -> e",
"@": ["N2+", "O2+", "N4+", "O4+", "O2+N2"],
"lookup": "constant",
"value": 1E-3
}
]
Domain boundary conditions
TODO.