Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:09:40

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file corecel/math/ArraySoftUnit.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <cmath>
0010 
0011 #include "corecel/Types.hh"
0012 #include "corecel/cont/Array.hh"
0013 
0014 #include "detail/SoftEqualTraits.hh"
0015 
0016 namespace celeritas
0017 {
0018 //---------------------------------------------------------------------------//
0019 /*!
0020  * Test for being approximately a unit vector.
0021  *
0022  * Consider a unit vector \em v with a small perturbation along a unit vector
0023  * \em e : \f[
0024    \vec v + \epsilon \vec e
0025   \f]
0026  * The magnitude of this "nearly unit" is
0027  * \f[
0028   m^2 = (v + \epsilon e) \cdot (v + \epsilon e)
0029    = 1 + 2 (v \cdot e) \epsilon + \epsilon^2
0030  \f]
0031  *
0032  * Since by the triangle inequality \f[ |v \cdot e|  <= |v||e| = 1 \f] ,
0033  * then the magnitude squared of a perturbed unit vector is bounded
0034  * \f[
0035   m^2 = 1 \pm 2 \epsilon + \epsilon^2
0036   \f]
0037  *
0038  * Instead of calculating the square of the tolerance we use
0039  * \f$ \epsilon^2 < \epsilon \f$ to make the "soft unit vector" condition
0040  * \f[
0041    | \vec v \vd \vec v - 1 | < 3 \epsilon .
0042    \f]
0043  */
0044 template<class T = ::celeritas::real_type>
0045 class ArraySoftUnit
0046 {
0047   public:
0048     //!@{
0049     //! \name Type aliases
0050     using value_type = T;
0051     //!@}
0052 
0053   public:
0054     // Construct with explicit tolerance
0055     CELER_FUNCTION inline ArraySoftUnit(value_type tol);
0056 
0057     // Construct with default tolerance
0058     CELER_CONSTEXPR_FUNCTION ArraySoftUnit();
0059 
0060     // Calculate whether the array is nearly a unit vector
0061     template<::celeritas::size_type N>
0062     CELER_CONSTEXPR_FUNCTION bool operator()(Array<T, N> const& arr) const;
0063 
0064   private:
0065     value_type tol_;
0066 };
0067 
0068 //---------------------------------------------------------------------------//
0069 // TEMPLATE DEDUCTION GUIDES
0070 //---------------------------------------------------------------------------//
0071 template<class T>
0072 CELER_FUNCTION ArraySoftUnit(T) -> ArraySoftUnit<T>;
0073 
0074 //---------------------------------------------------------------------------//
0075 // FREE FUNCTIONS
0076 //---------------------------------------------------------------------------//
0077 // Test for being approximately a unit vector
0078 template<class T, size_type N>
0079 CELER_CONSTEXPR_FUNCTION bool is_soft_unit_vector(Array<T, N> const& v);
0080 
0081 //---------------------------------------------------------------------------//
0082 // INLINE DEFINITIONS
0083 //---------------------------------------------------------------------------//
0084 /*!
0085  * Construct with explicit tolereance.
0086  */
0087 template<class T>
0088 CELER_FUNCTION ArraySoftUnit<T>::ArraySoftUnit(T tol) : tol_{3 * tol}
0089 {
0090     CELER_EXPECT(tol_ > 0);
0091 }
0092 
0093 //---------------------------------------------------------------------------//
0094 /*!
0095  * Construct with default tolereance.
0096  */
0097 template<class T>
0098 CELER_CONSTEXPR_FUNCTION ArraySoftUnit<T>::ArraySoftUnit()
0099     : tol_{3 * detail::SoftEqualTraits<T>::rel_prec()}
0100 {
0101 }
0102 
0103 //---------------------------------------------------------------------------//
0104 /*!
0105  * Calculate whether the array is nearly a unit vector.
0106  *
0107  * The calculation below is equivalent to
0108  * \code
0109  * return SoftEqual{tol, tol}(1, dot_product(arr, arr));
0110  * \endcode.
0111  */
0112 template<class T>
0113 template<::celeritas::size_type N>
0114 CELER_CONSTEXPR_FUNCTION bool
0115 ArraySoftUnit<T>::operator()(Array<T, N> const& arr) const
0116 {
0117     T length_sq{};
0118     for (size_type i = 0; i != N; ++i)
0119     {
0120         length_sq = std::fma(arr[i], arr[i], length_sq);
0121     }
0122     return std::fabs(length_sq - 1) < tol_ * std::fmax(real_type(1), length_sq);
0123 }
0124 
0125 //---------------------------------------------------------------------------//
0126 //! Test with default tolerance for being a unit vector
0127 template<class T, size_type N>
0128 CELER_CONSTEXPR_FUNCTION bool is_soft_unit_vector(Array<T, N> const& v)
0129 {
0130     return ArraySoftUnit<T>{}(v);
0131 }
0132 
0133 //---------------------------------------------------------------------------//
0134 }  // namespace celeritas