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:
The resulting quantity can be converted to the native Celeritas unit system withreal_type eval = value_as<MevEnergy>(energy); // Natural units MevMomentum momentum{std::sqrt(eval * eval + 2 * value_as<MevMass>(mass) * eval)};
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) 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 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 .
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, 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 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)
- 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
Exact unit transformations using SI unit definitions
CLHEP units
-
constexpr real_type millimeter = real_type(0.1) * centimeter
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 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 <em>exact</em> value as defined by SI
-
constexpr real_type na_avogadro = 6.02214076e23
-
constexpr real_type kcd_luminous = 683
Experimental physical constants from CODATA 2018
-
constexpr real_type alpha_fine_structure = 7.2973525693e-3
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.
-
constexpr real_type na_avogadro = 6.02214076e23