Describing the background gas

Criptic is allows essentially arbitrary descriptions of the background gas through which cosmic rays move. Users can rely on some Pre-defined gas descriptors, but for most realistic applications users will want to provide their own descriptions of the background gas (where “gas” here also includes the magnetic and radiation fields). This section first explains the basic data structure criptic uses to describe background gas (The GasData class), and then explains the class used to return these descriptions (The Gas class). It also explains the Pre-defined gas descriptors gas descriptors that are available.

The GasData class

In criptic, the state of the gas at a single point in space and time is described by a the criptic::gas::GasData class. This is a very simple class that describes the gas compsition. It has the following fields:

  • dx: the characteristic length scale over which the gas state changes at a given point, which is used to control time steps for cosmic ray advances

  • den: total mass density of the gas

  • ionDen: mass density of the ionised component of the gas

  • v: gas velocity

  • B: magnetic field

  • denGrad: gradient of the mass density

  • ionDenGrad: gradient of the ionised mass density

  • vGrad: tensor giving the gradient of the velocity

  • BGrad: tensor giving the gradient of the magnetic field

  • xH0: abundance of neutral atomic hydrogen (H0) per H nucleon

  • xHp: abundance of ionized hydrogen (H+) per H nucleon

  • xHe0: abundance of neutral atomic helium (He0) per H nucleon

  • xHep: abundance of singly ionized helium (He+) per H nucleon

  • xHep2: abundance of doubly ionized helium (He+2) per H nucleon

  • xe: abundance of free electrons per H nucleon

  • Z: mass fraction of elements heavier than He

  • TBB: a vector giving the temperatures of each component of the radiation field

  • WBB: a vector giving the dilution factors of each component of the radiation field

With regard to the abundance quantities (xH0, xHp, etc.): abundances in criptic are measured following the astrochemistry convention of giving an abundance as a number of a given species per H nucleon. Thus for example if there is 1 neutral He atom per 10 H atoms, xHe0 would be 0.1. Note that the abundance of molecular hydrogen (H2) is not explicitly specified as part of GasData; criptic assumes that all hydrogen nuclei that are not in the form of H0 or H+ are in the form of H2, from which it immediately follows that \(x(\mathrm{H}_2) = [1 - x(\mathrm{H}^0) - x(\mathrm{H}^+)]/2\).

With regard to radiation fields: in criptic radiation fields are assumed to be describable as a sum of dilute blackbodies. TBB gives the temperature of each component, and WBB gives the dilution factor.

For convenience, the GasData class defines three methods to set abundances to typical values found in predominantly molecular, atomic, and ionized interstellar regions; these routines are setMolecularComposition, setAtomicComposition, and setIonizedComposition. The abundances these routines enforce are:

Quantity

Ionized composition

Atomic composition

Molecular composition

xH0

0

0.99

0

xHp

1

0.01

0

xHe0

0

0.0955

0.0955

xHep

0

0

0

xHep2

0.0955

0

0

xe

1 + 2 * 0.0955

0.01

1.0e-6

Z

0.0199

0.0199

0.0199

The Gas class

The basic object in criptic used to describe the background gas is the criptic::gas::Gas class. This is a pure virtual class, and user-defined (and pre-defined) gas descriptors are derived from it. The user must instantiate and return a pointer to one of these derived objects in the initGas routine during problem setup – see Initializing the background gas state.

The minimum requirement for a class derived from Gas is that it implement the method gasData, which is a pure virtual method in Gas. The signature for this method is:

virtual GasData gasData(const RealVec &x,
                        const Real t);

Here x is the position at which the gas state is to be returned (an object of type RealVec), and t is the time. The method must return a GasData object in which all the fields listed above have been set.

In addition to this required gasData method, users may wish to provide implementations of three other methods in Gas, which will override the default implementations. The first of these is:

virtual Real dxGhost() const;

This method is required to be defined for any class derived from Gas for which the gas properties are well-defined only over a finite volume (for example, because the gas data are coming from a simulation with a finite domain size). In this case, the problem geometry will generally be restricted to the range over which the gas data are defined (see Geometry parameters), but, as in any hydrodynamic simulation, criptic needs there to be a ghost region outside the region of valid data where calls to gasData will not generate non-sensical results. The routine dxGhost returns the size of this ghost region. The CartesianGrid class (see Pre-defined gas descriptors) provides an example of a class derived from Gas that uses the dxGhost routine.

The second optional method in Gas is the frame method, which has the signature:

virtual void frame(const RealVec &x,
                   const Real t,
                   RealVec& v,
                   TNBBasis& tnb) const;

This method takes as input the position and time, exactly as gasData, but rather than returning the full gas state it only returns the gas velocity v and the local TNB basis defined by the magnetic field tnb; the latter is a struct of type TNBBasis, which holds the three unit vectors, tnb.eT, tnb.eN, and tnb.eB, that define the TNB basis at the input position; the three vectors correspond to the tangent, normal, and binormal basis vectors, respectvely. The parent Gas class provides an implementation of frame that uses the data returned by gasData to compute the TNB basis. However, since this requires computing the full gas state and then carrying out some vector algebra to derive the TNB basis vectors from it, depending on how the gas state is calculated it may be more computationally efficient to compute the velocity and basis vectors directly. Overriding this method provides a way to do so. The UniformGas class (see Pre-defined gas descriptors) provides an example of a class derived from Gas that does this.

The third virtual method in Gas that derived classes may choose to override is:

virtual void updateState(const Real t,
                         Real& tNext);

This method is called at the end of every time step, and can be used to modify the state of the background gas (e.g., to implement a background gas that moves or changes over time). The default implementation of updateState does nothing. The input argument t is the time at the end of the current step in which updateState has been called, and the argument tNext is the time to which the simulation will be advanced after the next time step. Note that users are free to modify tNext (for example to reduce the time step in order to resolve some event occuring in the background gas), but that such modifications should generally involve only reductions in tNext, not increases, as the latter can reduce simulation accuracy. See CartesianTimeInterp for an example of a class that uses updateState.

Pre-defined gas descriptors

While most users will want to set up their own background gas states, criptic does include a few simple defaults. These are:

  • UniformGas, which represents a uniform, infinite medium

  • CartesianGrid, which represents a gas whose properties are stored on a Cartesian grid

  • CartesianTimeInterp, representing a gas whose properties are stored as a series of Cartesian grids representing snapshots of the gas state uniformly spaced in time

  • CartesianTimeInterpFLASH, a specialization of CartesianTimeInterp in which the snapshots storing the data come from an isotheral turbulence simulation run with the FLASH code

The UniformGas class reads the parameter file and uses the parameters gas.density, gas.ionDensity, gas.magField, gas.velocity, gas.dx, gas.TBB, and gas.WBB to set the corresponding fields in the GasData at all positions. Users can also set the abundances by manually specifying gas.xH0, gas.xHp, etc., or can invoke the setIonizedComposition, setAtomicComposition, or setMolecularComposition methods to set the abundances by setting the keyword gas.comp to ionized, atomic, or molecular.

The CartesianGrid class reads the parameter gas.n_grid from the parameter file, which is a triple of three integers specifying the number of cells in the grid; the edges of the grid are assumed to coincide with the problem domain boundaries (see Geometry parameters). The class then provides an operator CartesianGrid::operator() that can be used to access the values of cells. Users can use this operator to initialize the values in grid cells. The LossRates example problem in Src/Prob in the criptic repository provides an example of how to do this.

The CartesianTimeInterp class is itself a pure virtual class, which provides a framework for interpolating in a Cartesian grid in space and time. It reads gas.n_grid from the parameter file exactly as for CartesianGrid, and also reads the parameters gas.dt and gas.n_slice, which give the time interval between slices and the number of time slices, respectively; the first time slice is assumed to be at time 0. To use this class, users must create a derived class that implements the pure virtual method loadData, which loads in a time slice as a CartesianGrid and provides a pointer to it. The CartesianTimeInterpFLASH class provides an example of such a derived class.