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 [Bureau International des Poids et Mesures, 2019]. Other physical constants such as the atomic mass unit and electron radius are derived from experimental measurements in CODATA 2018 [Tiesinga et al., 2021]. Because the reported constants are derived from regression fits to experimental data points, some exactly defined physical relationships (such as the fine structure constant \(\alpha = \frac{e^2}{2 \epsilon_0 h c}\)) are only approximate.
Unlike Geant4 and the CLHEP unit systems [Lönnblad, 1994], 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 inconsistencies with other macro-scale unit systems such as SI. To harmonize special unit systems 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>
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, real_type>; using MevMass = RealQuantity<UnitDivide<Mev, CLightSq>>; using MevMomentum = RealQuantity<UnitDivide<Mev, CLight>>;
Note the use of the
RealQuantity
type alias (below).A relativistic equation that operates on these quantities can do so without unnecessary floating point operations involving the speed of light:
The resulting quantity can be converted to the native Celeritas unit system withreal_type e_mev = value_as<MevEnergy>(energy); // Natural units MevMomentum momentum{std::sqrt(e_mev * e_mev + 2 * value_as<MevMass>(mass) * e_mev)};
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
value_as
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 diagnostic purposes.
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) ornative_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 UnitT>
using celeritas::RealQuantity = Quantity<UnitT, real_type>¶ Type alias for a quantity that uses compile-time precision.
-
template<class Q, class T>
Q celeritas::native_value_to(T 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).
An extra cast may be needed when mixing
float
,double
, andceleritas::Constant
.
-
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 typeless zero quantity.
The zero quantity can be compared against any Quantity.
-
auto celeritas::max_quantity() noexcept¶
Get a typeless 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 .
- Todo:
Template on real type and template the functions below.
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 unitsCELERITAS_UNITS_SI
: use SI unitsCELERITAS_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, the user-selected 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 systemphysics/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)
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 = RealQuantity<EElectron>
-
using MevEnergy = RealQuantity<Mev>
-
using MevMass = RealQuantity<MevPerCsq>
-
using MevMomentum = RealQuantity<MevPerC>
-
using MevMomentumSq = RealQuantity<UnitProduct<MevPerC, MevPerC>>
-
using LightSpeed = RealQuantity<CLight>
-
using AmuMass = RealQuantity<Amu>
Quantities for manual input and/or test harnesses
-
using BarnXs = RealQuantity<Barn>
-
using CmLength = RealQuantity<Centimeter>
-
using InvCmXs = RealQuantity<UnitInverse<Centimeter>>
-
using InvCcDensity = RealQuantity<InvCentimeterCubed>
-
using MolCcDensity = RealQuantity<MolPerCentimeterCubed>
-
using GramCcDensity = RealQuantity<GramPerCentimeterCubed>
-
using FieldTesla = RealQuantity<Tesla>
Units with numerical value defined to be 1 for CGS
-
constexpr Constant centimeter = {1}
Length.
-
constexpr Constant gram = {1}
Mass.
-
constexpr Constant second = {1}
Time.
-
constexpr Constant gauss = {1}
Field strength.
-
constexpr Constant kelvin = {1}
Temperature.
Exact unit transformations to SI units
-
constexpr Constant meter = 100 * centimeter
Exact unit transformations using SI unit definitions
CLHEP units
-
constexpr Constant millimeter = Constant{0.1} * centimeter
Other common units
-
constexpr Constant micrometer = Constant{1e-4} * centimeter
-
constexpr Constant nanometer = Constant{1e-7} * centimeter
-
constexpr Constant femtometer = Constant{1e-13} * centimeter
-
constexpr Constant barn = Constant{1e-24} * centimeter * centimeter
Typedefs
-
using LogMevEnergy = RealQuantity<LogMev>
Special faux quantity for overloading cross section calculation.
Constants¶
-
class Constant¶
Full-precision floating point constant with automatic precision demotion.
We want two behaviors from constants in Celeritas:
They don’t accidentally promote runtime arithmetic from single to double precision when compiling at a lower precision. This incurs a substantial performance penalty on GPU.
We can use their full double-precision values when we need to: either in templated code or when interacting with other libraries. (For example, float(pi) > pi which can lead to errors in Geant4.)
This class stores a full-precision (double) value as its “real type” and defines explicit conversion operators that allow it to automatically convert to a lower-precision or real-precision type.
Operations with a floating point value returns a value of that precision (performed at that precision level); operations with integers return a full-precision Constant; and operations with Constants return a Constant.
-
namespace constants
Mathematical, numerical, and physical constants.
Some of the physical constants listed here are exact numerical values: see Bureau International des Poids et Mesures [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 andcoulomb
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 exact value as defined by SI
-
constexpr Constant na_avogadro = {6.02214076e23}
-
constexpr Constant kcd_luminous = {683}
Experimental physical constants from CODATA 2018
Other constants
-
constexpr int stable_decay_constant = {0}
Mathemetical constants (truncated)
-
constexpr Constant pi = {3.14159265358979323846}
-
constexpr Constant sqrt_pi = {1.77245385090551602730}
-
constexpr Constant euler = {2.71828182845904523536}
-
constexpr Constant sqrt_euler = {1.64872127070012814685}
-
constexpr Constant sqrt_two = {1.41421356237309504880}
-
constexpr Constant sqrt_three = {1.73205080756887729353}
Variables
-
constexpr Constant e_electron = {1}
Special case for CLHEP: electron charged is unity by definition.
-
constexpr Constant na_avogadro = {6.02214076e23}