Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:54:49

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2020-2024 UT-Battelle, LLC, and other Celeritas developers.
0003 // See the top-level COPYRIGHT file for details.
0004 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0005 //---------------------------------------------------------------------------//
0006 //! \file corecel/math/Quantity.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <type_traits>
0011 
0012 #include "corecel/Macros.hh"
0013 #include "corecel/Types.hh"
0014 
0015 #include "detail/QuantityImpl.hh"
0016 
0017 namespace celeritas
0018 {
0019 //---------------------------------------------------------------------------//
0020 /*!
0021  * A numerical value tagged with a unit.
0022  * \tparam UnitT  unit tag class
0023  * \tparam ValueT value type
0024  *
0025  * A quantity is a value expressed in terms of the given unit. Storing values
0026  * in a different unit system can help with some calculations (e.g. operating
0027  * in natural unit systems) by avoiding numerical multiplications and divisions
0028  * by large constants. It can also make debugging easier (numeric values are
0029  * obvious).
0030  *
0031  * Example usage by physics class, where charge is in units of q_e+, and
0032  * mass and momentum are expressed in atomic natural units (where m_e = 1 and c
0033  * = 1).
0034  * \code
0035    using MevEnergy   = Quantity<Mev>;
0036    using MevMass     = Quantity<UnitDivide<Mev, CLightSq>>;
0037    using MevMomentum = Quantity<UnitDivide<Mev, CLight>>;
0038    \endcode
0039  *
0040  * A relativistic equation that operates on these quantities can do so without
0041  * unnecessary floating point operations involving the speed of light:
0042  * \code
0043    real_type eval = value_as<MevEnergy>(energy); // Natural units
0044    MevMomentum momentum{std::sqrt(eval * eval
0045                                   + 2 * value_as<MevMass>(mass) * eval)};
0046    \endcode
0047  * The resulting quantity can be converted to the native Celeritas unit system
0048  * with `native_value_from`, which multiplies in the constant value of
0049  * ElMomentumUnit:
0050  * \code
0051    real_type mom = native_value_from(momentum);
0052  * \endcode
0053  *
0054  * When using a Quantity from another part of the code, e.g. an imported unit
0055  * system, use the \c quantity free function rather than \c .value() in order
0056  * to guarantee consistency of units between source and destination.
0057  *
0058  * An example unit class would be:
0059  * \code
0060     struct DozenUnit
0061     {
0062         static constexpr int value() { return 12; }
0063         static constexpr char const* label() { return "dozen"; }
0064     };
0065    \endcode
0066  *
0067  * The label is used solely for outputting to JSON.
0068  *
0069  * \note The Quantity is designed to be a simple "strong type" class, not a
0070  * complex mathematical class. To operate on quantities, you must use
0071  * `value_as`
0072  * (to operate within the Quantity's unit system) or `native_value_from` (to
0073  * operate in the Celeritas native unit system), use the resulting numeric
0074  * values in your mathematical expressions, then return a new Quantity class
0075  * with the resulting value and correct type.
0076  */
0077 template<class UnitT, class ValueT = decltype(UnitT::value())>
0078 class Quantity
0079 {
0080   public:
0081     //!@{
0082     //! \name Type aliases
0083     using value_type = ValueT;
0084     using unit_type = UnitT;
0085     //!@}
0086 
0087   public:
0088     //! Construct with default (zero)
0089     constexpr Quantity() = default;
0090 
0091     //! Construct with value in celeritas native units
0092     explicit CELER_CONSTEXPR_FUNCTION Quantity(value_type value) noexcept
0093         : value_(value)
0094     {
0095     }
0096 
0097     //! Construct implicitly from a unitless quantity
0098     template<detail::QConstant QC>
0099     CELER_CONSTEXPR_FUNCTION Quantity(detail::UnitlessQuantity<QC>) noexcept
0100         : value_(detail::get_constant<ValueT>(QC))
0101     {
0102     }
0103 
0104     //!@{
0105     //! Access the underlying numeric value, discarding units
0106 #define CELER_DEFINE_QACCESS(FUNC, QUAL)                          \
0107     CELER_CONSTEXPR_FUNCTION value_type QUAL FUNC() QUAL noexcept \
0108     {                                                             \
0109         return value_;                                            \
0110     }
0111 
0112     CELER_DEFINE_QACCESS(value, &)
0113     CELER_DEFINE_QACCESS(value, const&)
0114 #undef CELER_DEFINE_QACCESS
0115     //!@}
0116 
0117     //! Access the underlying data for more efficient loading from memory
0118     CELER_CONSTEXPR_FUNCTION value_type const* data() const { return &value_; }
0119 
0120   private:
0121     value_type value_{};
0122 };
0123 
0124 //---------------------------------------------------------------------------//
0125 //! \cond
0126 #define CELER_DEFINE_QUANTITY_CMP(TOKEN)                           \
0127     template<class U, class T, class T2>                           \
0128     CELER_CONSTEXPR_FUNCTION bool operator TOKEN(                  \
0129         Quantity<U, T> lhs, Quantity<U, T2> rhs) noexcept          \
0130     {                                                              \
0131         return lhs.value() TOKEN rhs.value();                      \
0132     }                                                              \
0133     template<class U, class T, detail::QConstant QC>               \
0134     CELER_CONSTEXPR_FUNCTION bool operator TOKEN(                  \
0135         Quantity<U, T> lhs, detail::UnitlessQuantity<QC>) noexcept \
0136     {                                                              \
0137         return lhs.value() TOKEN detail::get_constant<T>(QC);      \
0138     }                                                              \
0139     template<class U, class T, detail::QConstant QC>               \
0140     CELER_CONSTEXPR_FUNCTION bool operator TOKEN(                  \
0141         detail::UnitlessQuantity<QC>, Quantity<U, T> rhs) noexcept \
0142     {                                                              \
0143         return detail::get_constant<T>(QC) TOKEN rhs.value();      \
0144     }                                                              \
0145     namespace detail                                               \
0146     {                                                              \
0147     template<detail::QConstant C1, detail::QConstant C2>           \
0148     CELER_CONSTEXPR_FUNCTION bool                                  \
0149     operator TOKEN(detail::UnitlessQuantity<C1>,                   \
0150                    detail::UnitlessQuantity<C2>) noexcept          \
0151     {                                                              \
0152         return static_cast<int>(C1) TOKEN static_cast<int>(C2);    \
0153     }                                                              \
0154     }
0155 
0156 //!@{
0157 //! Comparison for Quantity
0158 CELER_DEFINE_QUANTITY_CMP(==)
0159 CELER_DEFINE_QUANTITY_CMP(!=)
0160 CELER_DEFINE_QUANTITY_CMP(<)
0161 CELER_DEFINE_QUANTITY_CMP(>)
0162 CELER_DEFINE_QUANTITY_CMP(<=)
0163 CELER_DEFINE_QUANTITY_CMP(>=)
0164 //!@}
0165 
0166 #undef CELER_DEFINE_QUANTITY_CMP
0167 
0168 //!@{
0169 //! Math operator for Quantity
0170 template<class U, class T, class T2>
0171 CELER_CONSTEXPR_FUNCTION auto
0172 operator+(Quantity<U, T> lhs, Quantity<U, T2> rhs) noexcept -> decltype(auto)
0173 {
0174     return Quantity<U, std::common_type_t<T, T2>>{lhs.value() + rhs.value()};
0175 }
0176 
0177 template<class U, class T, class T2>
0178 CELER_CONSTEXPR_FUNCTION auto
0179 operator-(Quantity<U, T> lhs, Quantity<U, T2> rhs) noexcept -> decltype(auto)
0180 {
0181     return Quantity<U, std::common_type_t<T, T2>>{lhs.value() - rhs.value()};
0182 }
0183 
0184 template<class U, class T>
0185 CELER_CONSTEXPR_FUNCTION auto
0186 operator-(Quantity<U, T> q) noexcept -> Quantity<U, T>
0187 {
0188     return Quantity<U, T>{-q.value()};
0189 }
0190 
0191 template<class U, class T, class T2>
0192 CELER_CONSTEXPR_FUNCTION auto
0193 operator*(Quantity<U, T> lhs, T2 rhs) noexcept -> decltype(auto)
0194 {
0195     return Quantity<U, std::common_type_t<T, T2>>{lhs.value() * rhs};
0196 }
0197 
0198 template<class T, class U, class T2>
0199 CELER_CONSTEXPR_FUNCTION auto
0200 operator*(T rhs, Quantity<U, T2> lhs) noexcept -> decltype(auto)
0201 {
0202     return Quantity<U, std::common_type_t<T, T2>>{rhs * lhs.value()};
0203 }
0204 
0205 template<class U, class T, class T2>
0206 CELER_CONSTEXPR_FUNCTION auto
0207 operator/(Quantity<U, T> lhs, T2 rhs) noexcept -> decltype(auto)
0208 {
0209     return Quantity<U, std::common_type_t<T, T2>>{lhs.value() / rhs};
0210 }
0211 //!@!}
0212 
0213 //! \endcond
0214 //---------------------------------------------------------------------------//
0215 // FREE FUNCTIONS
0216 //---------------------------------------------------------------------------//
0217 /*!
0218  * Get a zero quantity (analogous to nullptr).
0219  */
0220 CELER_CONSTEXPR_FUNCTION auto zero_quantity() noexcept
0221 {
0222     return detail::UnitlessQuantity<detail::QConstant::zero>{};
0223 }
0224 
0225 //---------------------------------------------------------------------------//
0226 /*!
0227  * Get a quantitity greater than any other numeric quantity.
0228  */
0229 CELER_CONSTEXPR_FUNCTION auto max_quantity() noexcept
0230 {
0231     return detail::UnitlessQuantity<detail::QConstant::max>{};
0232 }
0233 
0234 //---------------------------------------------------------------------------//
0235 /*!
0236  * Get a quantitity less than any other numeric quantity.
0237  */
0238 CELER_CONSTEXPR_FUNCTION auto neg_max_quantity() noexcept
0239 {
0240     return detail::UnitlessQuantity<detail::QConstant::neg_max>{};
0241 }
0242 
0243 //---------------------------------------------------------------------------//
0244 /*!
0245  * Swap two Quantities.
0246  */
0247 template<class U, class V>
0248 CELER_CONSTEXPR_FUNCTION void
0249 swap(Quantity<U, V>& a, Quantity<U, V>& b) noexcept
0250 {
0251     Quantity<U, V> tmp{a};
0252     a = b;
0253     b = tmp;
0254 }
0255 
0256 //---------------------------------------------------------------------------//
0257 /*!
0258  * Convert the given quantity into the native Celeritas unit system.
0259  *
0260  * \code
0261    assert(native_value_from(Quantity<CLight>{1}) == 2.998e10 *
0262    centimeter/second);
0263  * \endcode
0264  */
0265 template<class UnitT, class ValueT>
0266 CELER_CONSTEXPR_FUNCTION auto
0267 native_value_from(Quantity<UnitT, ValueT> quant) noexcept -> decltype(auto)
0268 {
0269     return quant.value() * UnitT::value();
0270 }
0271 
0272 //---------------------------------------------------------------------------//
0273 /*!
0274  * Create a quantity from a value in the Celeritas unit system.
0275  *
0276  * This function can be used for defining a constant for use in another unit
0277  * system (typically a "natural" unit system for use in physics kernels).
0278  *
0279  * \code
0280    constexpr LightSpeed c = native_value_to<LightSpeed>(constants::c_light);
0281    assert(c.value() == 1);
0282  * \endcode
0283  */
0284 template<class Q>
0285 CELER_CONSTEXPR_FUNCTION Q native_value_to(typename Q::value_type value) noexcept
0286 {
0287     return Q{value / Q::unit_type::value()};
0288 }
0289 
0290 //---------------------------------------------------------------------------//
0291 /*!
0292  * Use the value of a Quantity.
0293  *
0294  * The redundant unit type in the function signature is to make coupling safer
0295  * across different parts of the code and to make the user code more readable.
0296  *
0297  * \code
0298  assert(value_as<LightSpeed>(LightSpeed{1}) == 1);
0299  * \endcode
0300  */
0301 template<class Q, class SrcUnitT, class ValueT>
0302 CELER_CONSTEXPR_FUNCTION auto
0303 value_as(Quantity<SrcUnitT, ValueT> quant) noexcept -> ValueT
0304 {
0305     static_assert(std::is_same<Q, Quantity<SrcUnitT, ValueT>>::value,
0306                   "quantity units do not match");
0307     return quant.value();
0308 }
0309 
0310 //---------------------------------------------------------------------------//
0311 /*!
0312  * Get the label for a unit returned from a class accessor.
0313  *
0314  * Example:
0315  * \code
0316    cout << accessor_unit_label<decltype(&ParticleView::mass)>() << endl;
0317    \endcode
0318  */
0319 template<class T>
0320 inline char const* accessor_unit_label()
0321 {
0322     return detail::AccessorResultType<T>::unit_type::label();
0323 }
0324 
0325 //---------------------------------------------------------------------------//
0326 }  // namespace celeritas