Units and constants

The default unit system in Celeritas is CGS with centimeter (cm), gram (g), second (s), gauss (G), and kelvin (K) all having a value of unity. With these definitions, densities can be defined in natural units of \(\mathrm{g}/\mathrm{cm}^3\), and macroscopic cross sections are in units of \(\mathrm{cm}^{-1}\). See the units documentation for more descriptions of the core unit system and the exactly defined values for SI units such as tesla.

Celeritas defines constants from a few different sources. Mathematical constants are defined as truncated floating point values. Some physical constants such as the speed of light, Planck’s constant, and the electron charge, have exact numerical values as specified by the SI unit system [BureauIdPeMesures19]. Other physical constants such as the atomic mass unit and electron radius are derived from experimental measurements in CODATA 2018. Because the reported constants are derived from regression fits to experimental data points, some exactly defined physical relationships (such as the fine structure \(\alpha = \frac{e^2}{2 \epsilon_0 h c}\) are only approximate.

Unlike Geant4 and the CLHEP unit systems, Celeritas avoids using “natural” units in its definitions. Although a natural unit system makes some expressions easier to evaluate, it can lead to errors in the definition of derivative constants and is fundamentally in conflict with consistent unit systems such as SI. To enable special unit systems in harmony with the native Celeritas unit system, the Quantity class stores quantities in another unit system with a compile-time constant that allows their conversion back to native units. This allows, for example, particles to represent their energy as MeV and charge as fractions of e but work seamlessly with a field definition in native (macro-scale quantity) units.

Quantity

Celeritas supports multiple simultaneous unit systems (e.g., atomic scale/natural units working with a macro-scale but consistent unit system) using the Quantity class and helper functions.

template<class UnitT, class ValueT = decltype(UnitT::value())>
class Quantity

A numerical value tagged with a unit.

A quantity is a value expressed in terms of the given unit. Storing values in a different unit system can help with some calculations (e.g. operating in natural unit systems) by avoiding numerical multiplications and divisions by large constants. It can also make debugging easier (numeric values are obvious).

Example usage by physics class, where charge is in units of q_e+, and mass and momentum are expressed in atomic natural units (where m_e = 1 and c = 1).

using MevEnergy   = Quantity<Mev>;
using MevMass     = Quantity<UnitDivide<Mev, CLightSq>>;
using MevMomentum = Quantity<UnitDivide<Mev, CLight>>;

A relativistic equation that operates on these quantities can do so without unnecessary floating point operations involving the speed of light:

real_type eval = value_as<MevEnergy>(energy); // Natural units
MevMomentum momentum{std::sqrt(eval * eval
                               + 2 * value_as<MevMass>(mass) * eval)};
The resulting quantity can be converted to the native Celeritas unit system with native_value_from, which multiplies in the constant value of ElMomentumUnit:
real_type mom = native_value_from(momentum);

When using a Quantity from another part of the code, e.g. an imported unit system, use the quantity free function rather than .value() in order to guarantee consistency of units between source and destination.

An example unit class would be:

struct DozenUnit
{
    static constexpr int value() { return 12; }
    static constexpr char const* label() { return "dozen"; }
};

The label is used solely for outputting to JSON.

Note

The Quantity is designed to be a simple “strong type” class, not a complex mathematical class. To operate on quantities, you must use value_as (to operate within the Quantity’s unit system) or native_value_from (to operate in the Celeritas native unit system), use the resulting numeric values in your mathematical expressions, then return a new Quantity class with the resulting value and correct type.

Template Parameters:
  • UnitT – unit tag class

  • ValueT – value type

template<class Q>
Q celeritas::native_value_to(typename Q::value_type value) noexcept

Create a quantity from a value in the Celeritas unit system.

This function can be used for defining a constant for use in another unit system (typically a “natural” unit system for use in physics kernels).

constexpr LightSpeed c = native_value_to<LightSpeed>(constants::c_light);
assert(c.value() == 1);
template<class UnitT, class ValueT>
auto celeritas::native_value_from(Quantity<UnitT, ValueT> quant) noexcept

Convert the given quantity into the native Celeritas unit system.

assert(native_value_from(Quantity<CLight>{1}) == 2.998e10 *
centimeter/second);
template<class Q, class SrcUnitT, class ValueT>
auto celeritas::value_as(Quantity<SrcUnitT, ValueT> quant) noexcept -> ValueT

Use the value of a Quantity.

The redundant unit type in the function signature is to make coupling safer across different parts of the code and to make the user code more readable.

assert(value_as<LightSpeed>(LightSpeed{1}) == 1);
auto celeritas::zero_quantity() noexcept

Get a zero quantity (analogous to nullptr).

auto celeritas::max_quantity() noexcept

Get a quantitity greater than any other numeric quantity.

auto celeritas::neg_max_quantity() noexcept

Get a quantitity less than any other numeric quantity.

An example quantity uses \(2\pi\) as the unit type to allow integral values for turns. Using a Quantity also allows us to override the sincos function to use sincospi under the hood for improved precision.

using celeritas::Turn = Quantity<TwoPi, real_type>

Quantity denoting a full turn.

Turns are a useful way of representing angles without the historical arbitrariness of degrees or the roundoff errors of radians. See, for example, https://www.computerenhance.com/p/turns-are-better-than-radians .

void celeritas::sincos(Turn r, real_type *sinv, real_type *cosv)

Special overrides for math functions for more precise arithmetic

Units

namespace units

Units in Celeritas for macro-scale quantities.

Celeritas can be configured at build time to use different unit systems for better compatibility with external libraries and applications. The CELERITAS_UNITS CMake variable can be set to one of the following:

  • CELERITAS_UNITS_CGS (default): use Gaussian CGS units

  • CELERITAS_UNITS_SI: use SI units

  • CELERITAS_UNITS_CLHEP: use the Geant4 high energy physics system (a mix of macro-scale and atomic-scale units)

The following units have numerical values of 1 in the default Celeritas system (Gaussian CGS) and are often seen in unit tests:

  • cm for standard unit of length

  • s for standard unit of time

  • g for standard unit of mass

  • G for standard unit of field strength

Unless otherwise specified, this unit system is used for input and output numerical values. They are meant for macro-scale quantities coupling the different code components of Celeritas.

See also:

  • Constants.hh for constants defined in this unit system

  • physics/base/Units.hh for unit systems used by the physics

Additionally:

  • radians are used for measures of angle (unitless)

  • steradians are used for measures of solid angle (unitless)

    Todo:

    If we’re serious about supporting single-precision arithmetic, we should define a helper class that stores the constant as full precision but when multiplied by a single/double is truncated to that precision. Otherwise, if real_type is single-precision, then we lose accuracy in places like the GeantImporter where everything is double precision.

Note

This system of units should be fully consistent so that constants can be precisely defined. (E.g., you cannot define both MeV as 1 and Joule as 1.) To express quantities in another system of units, such as MeV and “natural” units, use the Quantity class.

Quantities for atomic scale/natural units

using ElementaryCharge = Quantity<EElectron>
using MevEnergy = Quantity<Mev>
using LogMevEnergy = Quantity<LogMev>
using MevMass = Quantity<MevPerCsq>
using MevMomentum = Quantity<MevPerC>
using MevMomentumSq = Quantity<UnitProduct<MevPerC, MevPerC>>
using LightSpeed = Quantity<CLight>
using AmuMass = Quantity<Amu>

Quantities for manual input and/or test harnesses

using BarnXs = Quantity<Barn>
using CmLength = Quantity<Centimeter>
using InvCmXs = Quantity<UnitInverse<Centimeter>>
using InvCcDensity = Quantity<InvCentimeterCubed>
using MolCcDensity = Quantity<MolPerCentimeterCubed>
using GramCcDensity = Quantity<GramPerCentimeterCubed>
using FieldTesla = Quantity<Tesla>

Type aliases for unit system traits

using CgsTraits = UnitSystemTraits<UnitSystem::cgs>
using SiTraits = UnitSystemTraits<UnitSystem::si>
using ClhepTraits = UnitSystemTraits<UnitSystem::clhep>
using NativeTraits = UnitSystemTraits<UnitSystem::native>

Units with numerical value defined to be 1 for CGS

constexpr real_type centimeter = 1

Length.

constexpr real_type gram = 1

Mass.

constexpr real_type second = 1

Time.

constexpr real_type gauss = 1

Field strength.

constexpr real_type kelvin = 1

Temperature.

Exact unit transformations to SI units

constexpr real_type meter = 100 * centimeter
constexpr real_type kilogram = 1000 * gram
constexpr real_type tesla = 10000 * gauss

Exact unit transformations using SI unit definitions

constexpr real_type newton = kilogram * meter / (second * second)
constexpr real_type joule = newton * meter
constexpr real_type coulomb = kilogram / (tesla * second)
constexpr real_type ampere = coulomb / second
constexpr real_type volt = joule / coulomb
constexpr real_type farad = coulomb / volt

CLHEP units

constexpr real_type millimeter = real_type(0.1) * centimeter
constexpr real_type nanosecond = real_type(1e-9) * second

Other common units

constexpr real_type micrometer = real_type(1e-4) * centimeter
constexpr real_type nanometer = real_type(1e-7) * centimeter
constexpr real_type femtometer = real_type(1e-13) * centimeter
constexpr real_type barn = real_type(1e-24) * centimeter * centimeter

Functions

template<class F>
constexpr decltype(auto) visit_unit_system(F &&func, UnitSystem sys)

Expand a macro to a switch statement over all possible unit system types.

This helper function is meant for processing user input to convert values to the native unit system. It is not a CELER_FUNCTION because unit conversion should be done only during preprocessing on the CPU.

Constants

namespace constants

Mathematical, numerical, and physical constants.

Some of the physical constants listed here are exact numerical values: see the International System of Units, 9th ed. (2019), for definition of constants and how they relate to the different units.

Celeritas

CLHEP

Notes

a0_bohr

Bohr_radius

Bohr radius

alpha_fine_structure

fine_structure_const

atomic_mass

amu

Not the same as 1/avogadro

eps_electric

epsilon0

Vacuum permittivity

h_planck

h_Planck

k_boltzmann

k_Boltzmann

mu_magnetic

mu0

Vacuum permeability

na_avogadro

Avogadro

[1/mol]

r_electron

classic_electr_radius

Classical electron radius

kcd_luminous

[none]

Lumens per Watt

lambdabar_electron

electron_Compton_length

Reduced Compton wavelength

stable_decay_constant

[none]

Decay for a stable particle

In the CLHEP unit system, the value of the constant e_electron is defined to be 1 and coulomb is derivative from that. To avoid floating point arithmetic issues that would lead to the “units” and “constants” having different values for it, a special case redefines the value for CLHEP.

Some experimental physical constants are derived from the other physical constants, but for consistency and clarity they are presented numerically with the units provided in the CODATA 2018 dataset. The Constants.test.cc unit tests compare the numerical value against the derivative values inside the celeritas unit system. All experimental values include the final (ususally two) imprecise digits; their precision is usually on the order of \( 10^{-11} \).

Physical constants with <em>exact</em> value as defined by SI

constexpr real_type c_light = 299792458. * units::meter / units::second
constexpr real_type h_planck = 6.62607015e-34 * units::joule * units::second
constexpr real_type k_boltzmann = 1.380649e-23 * units::joule / units::kelvin
constexpr real_type na_avogadro = 6.02214076e23
constexpr real_type kcd_luminous = 683

Exact derivative constants

constexpr real_type hbar_planck = h_planck / (2 * pi)

Experimental physical constants from CODATA 2018

constexpr real_type a0_bohr = 5.29177210903e-11 * units::meter
constexpr real_type alpha_fine_structure = 7.2973525693e-3
constexpr real_type atomic_mass = 1.66053906660e-24 * units::gram
constexpr real_type electron_mass = 9.1093837015e-28 * units::gram
constexpr real_type proton_mass = 1.67262192369e-24 * units::gram
constexpr real_type eps_electric = 8.8541878128e-12 * units::farad / units::meter
constexpr real_type mu_magnetic = 1.25663706212e-6 * units::newton / (units::ampere * units::ampere)
constexpr real_type r_electron = 2.8179403262e-15 * units::meter
constexpr real_type rinf_rydberg = 10973731.568160 / units::meter
constexpr real_type eh_hartree = 4.3597447222071e-18 / units::meter
constexpr real_type lambdabar_electron = 3.8615926796e-13 * units::meter

Other constants

constexpr real_type stable_decay_constant = 0

Mathemetical constants (truncated)

constexpr real_type pi = 3.14159265358979323846
constexpr real_type euler = 2.71828182845904523536
constexpr real_type sqrt_two = 1.41421356237309504880
constexpr real_type sqrt_three = 1.73205080756887729353

Variables

constexpr real_type e_electron = 1

Special case for CLHEP: electron charged is unity by definition.