Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:31:20

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 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 celeritas/em/xs/NuclearFormFactors.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <cmath>
0011 
0012 #include "corecel/math/Algorithms.hh"
0013 #include "celeritas/Quantities.hh"
0014 #include "celeritas/phys/AtomicNumber.hh"
0015 
0016 namespace celeritas
0017 {
0018 //---------------------------------------------------------------------------//
0019 //! Helper traits used in nuclear form factors
0020 struct NuclearFormFactorTraits
0021 {
0022     //!@{
0023     //! \name Type aliases
0024     using AtomicMassNumber = AtomicNumber;
0025     using Momentum = units::MevMomentum;
0026     using MomentumSq = units::MevMomentumSq;
0027     using InvMomentum = Quantity<UnitInverse<Momentum::unit_type>>;
0028     using InvMomentumSq = Quantity<UnitInverse<MomentumSq::unit_type>>;
0029     using FFType = NuclearFormFactorType;
0030     //!@}
0031 
0032     //! Momentum transfer prefactor: 1 fm / hbar
0033     static CELER_CONSTEXPR_FUNCTION InvMomentum fm_par_hbar()
0034     {
0035         return native_value_to<InvMomentum>(units::femtometer
0036                                             / constants::hbar_planck);
0037     }
0038 };
0039 
0040 //---------------------------------------------------------------------------//
0041 /*!
0042  * Exponential nuclear form factor.
0043  *
0044  * This nuclear form factor corresponds \c NuclearFormFactorType::exponential
0045  * and assumes the nuclear charge decays exponentially from its center. This
0046  * assumes a parameterization of the atomic nucleus valid for light and medium
0047  * atomic nuclei (Eq. 7 of [BKM2002]): \f[
0048  * R_N = 1.27A^{0.27} \,\mathrm{fm}
0049  * \f]
0050  * with a special case for the proton radius, \f$ R_p = 0.85 \f$ fm.
0051  *
0052  * [BKM2002] A.V. Butkevich, R.P. Kokoulin, G.V. Matushko, S.P. Mikheyev,
0053  *      Comments on multiple scattering of high-energy muons in thick layers,
0054  *      Nuclear Instruments and Methods in Physics Research Section A:
0055  *      Accelerators, Spectrometers, Detectors and Associated Equipment 488
0056  *      (2002) 282–294. https://doi.org/10.1016/S0168-9002(02)00478-3.
0057  *
0058  * \todo Instead of using this coarse parameterization, we should add nuclear
0059  * radius to the isotope properties for a more accurate treatment, and
0060  * construct these classes directly from the atomic radius.
0061  */
0062 class ExpNuclearFormFactor : public NuclearFormFactorTraits
0063 {
0064   public:
0065     //! Form factor type corresponding to this distribution
0066     static CELER_CONSTEXPR_FUNCTION FFType ff_type()
0067     {
0068         return FFType::exponential;
0069     }
0070 
0071     // Construct with atomic mass number
0072     explicit inline CELER_FUNCTION
0073     ExpNuclearFormFactor(AtomicMassNumber a_mass);
0074 
0075     // Construct with precalculated form factor
0076     explicit inline CELER_FUNCTION
0077     ExpNuclearFormFactor(InvMomentumSq prefactor);
0078 
0079     // Calculate from square of target momentum
0080     inline CELER_FUNCTION real_type operator()(MomentumSq target_momsq) const;
0081 
0082     // Calculate from target momentum
0083     inline CELER_FUNCTION real_type operator()(Momentum target_mom) const;
0084 
0085     //! Nuclear form prefactor for the selected isotope
0086     CELER_FORCEINLINE_FUNCTION InvMomentumSq prefactor() const
0087     {
0088         return InvMomentumSq{prefactor_};
0089     }
0090 
0091   private:
0092     real_type prefactor_;  // Function of nuclear radius [(MeV/c)^{-2}]
0093 };
0094 
0095 //---------------------------------------------------------------------------//
0096 /*!
0097  * Gaussian nuclear form factor.
0098  *
0099  * This nuclear form factor corresponds \c NuclearFormFactorType::gaussian and
0100  * assumes a Gaussian distribution of nuclear charge. Its
0101  * prefactor has the same value as the exponential.
0102  */
0103 class GaussianNuclearFormFactor : public ExpNuclearFormFactor
0104 {
0105   public:
0106     //! Form factor type corresponding to this distribution
0107     static CELER_CONSTEXPR_FUNCTION FFType ff_type()
0108     {
0109         return FFType::gaussian;
0110     }
0111 
0112     using ExpNuclearFormFactor::ExpNuclearFormFactor;
0113 
0114     // Calculate from square of target momentum
0115     inline CELER_FUNCTION real_type operator()(MomentumSq target_momsq) const;
0116 
0117     // Calculate from target momentum
0118     inline CELER_FUNCTION real_type operator()(Momentum target_mom) const;
0119 };
0120 
0121 //---------------------------------------------------------------------------//
0122 /*!
0123  * Uniform-uniform folded nuclear form factor.
0124  *
0125  * This nuclear form factor corresponds \c NuclearFormFactorType::flat and
0126  * assumes a uniform nuclear charge at the center with a smoothly decreasing
0127  * charge at the surface. This leads to a form factor: \f[
0128  * F(q) = F'(x(R_0, q)) F'(x(R_1, q))
0129  * \f]
0130  * where \f$ x \equiv q R / \hbar \f$ uses the effective nuclear radius \f$
0131  * R_0 = 1.2 A^{1/3} \,\mathrm{fm} \f$ and nuclear surface skin \f$ R_1 = 2.0
0132  * \,\mathrm{fm} \f$,
0133  * and
0134  * \f[
0135  * F'(x) = \frac{3}{x^3} ( \sin x - x \cos x)
0136  * \f]
0137  * is the form factor for a uniformly charged sphere.
0138  *
0139  * \warning This form factor suffers from catastrophic numerical cancellation
0140  * for small radii and momenta so should only be used for large nuclei or large
0141  * momentum transfers.
0142  *
0143  * [LR16] C. Leroy and P.G. Rancoita. Principles of Radiation Interaction in
0144  *        Matter and Detection. World Scientific (Singapore), 4th edition,
0145  *        2016.
0146  *
0147  * [H56] R.H. Helm, Inelastic and Elastic Scattering of 187-Mev Electrons from
0148  *       Selected Even-Even Nuclei, Phys. Rev. 104 (1956) 1466–1475.
0149  *       https://doi.org/10.1103/PhysRev.104.1466.
0150  *
0151  * [FMS93] J.M. Fernández-Varea, R. Mayol, F. Salvat, Cross sections for
0152  *       elastic scattering of fast electrons and positrons by atoms, Nuclear
0153  *       Instruments and Methods in Physics Research Section B: Beam
0154  * Interactions with Materials and Atoms 82 (1993) 39–45.
0155  *       https://doi.org/10.1016/0168-583X(93)95079-K.
0156  */
0157 class UUNuclearFormFactor : public NuclearFormFactorTraits
0158 {
0159   public:
0160     //! Form factor type corresponding to this distribution
0161     static CELER_CONSTEXPR_FUNCTION FFType ff_type() { return FFType::flat; }
0162 
0163     // Construct with atomic mass number
0164     explicit inline CELER_FUNCTION UUNuclearFormFactor(AtomicMassNumber a_mass);
0165 
0166     // Calculate from square of target momentum
0167     inline CELER_FUNCTION real_type operator()(MomentumSq target_momsq) const;
0168 
0169     // Calculate from target momentum
0170     inline CELER_FUNCTION real_type operator()(Momentum target_mom) const;
0171 
0172   private:
0173     real_type nucl_radius_fm_;
0174 
0175     // Effective nuclear skin radius: 2 fm
0176     static CELER_CONSTEXPR_FUNCTION real_type skin_radius_fm() { return 2; }
0177 };
0178 
0179 //---------------------------------------------------------------------------//
0180 // INLINE DEFINITIONS
0181 //---------------------------------------------------------------------------//
0182 /*!
0183  * Construct from atomic mass number.
0184  */
0185 CELER_FUNCTION
0186 ExpNuclearFormFactor::ExpNuclearFormFactor(AtomicMassNumber a_mass)
0187 {
0188     CELER_EXPECT(a_mass);
0189     real_type nucl_radius_fm = [a_mass] {
0190         if (CELER_UNLIKELY(a_mass == AtomicMassNumber{1}))
0191         {
0192             // Special case for proton radius
0193             return real_type{0.85};
0194         }
0195         return real_type{1.27}
0196                * fastpow(real_type(a_mass.get()), real_type{0.27});
0197     }();
0198     prefactor_ = ipow<2>(nucl_radius_fm * value_as<InvMomentum>(fm_par_hbar()))
0199                  * (real_type{1} / 12);
0200     CELER_ENSURE(prefactor_ > 0);
0201 }
0202 
0203 //---------------------------------------------------------------------------//
0204 /*!
0205  * Construct with precalculated form factor.
0206  */
0207 CELER_FUNCTION
0208 ExpNuclearFormFactor::ExpNuclearFormFactor(InvMomentumSq prefactor)
0209     : prefactor_{prefactor.value()}
0210 {
0211     CELER_EXPECT(prefactor_ > 0);
0212 }
0213 
0214 //---------------------------------------------------------------------------//
0215 /*!
0216  * Calculate the exponential folded form factor from the square momentum.
0217  */
0218 CELER_FUNCTION real_type
0219 ExpNuclearFormFactor::operator()(MomentumSq target_momsq) const
0220 {
0221     CELER_EXPECT(target_momsq >= zero_quantity());
0222     return 1 / ipow<2>(1 + prefactor_ * target_momsq.value());
0223 }
0224 
0225 //---------------------------------------------------------------------------//
0226 /*!
0227  * Calculate the exponential folded form factor.
0228  */
0229 CELER_FUNCTION real_type ExpNuclearFormFactor::operator()(Momentum target_mom) const
0230 {
0231     return (*this)(MomentumSq{ipow<2>(target_mom.value())});
0232 }
0233 
0234 //---------------------------------------------------------------------------//
0235 /*!
0236  * Calculate the gaussian folded form factor.
0237  */
0238 CELER_FUNCTION real_type
0239 GaussianNuclearFormFactor::operator()(MomentumSq target_momsq) const
0240 {
0241     CELER_EXPECT(target_momsq >= zero_quantity());
0242     return std::exp(-2 * value_as<InvMomentumSq>(this->prefactor())
0243                     * target_momsq.value());
0244 }
0245 
0246 //---------------------------------------------------------------------------//
0247 /*!
0248  * Calculate the gaussian folded form factor by squaring the momentum.
0249  */
0250 CELER_FUNCTION real_type
0251 GaussianNuclearFormFactor::operator()(Momentum target_mom) const
0252 {
0253     return (*this)(MomentumSq{ipow<2>(target_mom.value())});
0254 }
0255 
0256 //---------------------------------------------------------------------------//
0257 /*!
0258  * Construct from atomic mass number.
0259  */
0260 CELER_FUNCTION UUNuclearFormFactor::UUNuclearFormFactor(AtomicMassNumber a_mass)
0261 {
0262     CELER_EXPECT(a_mass);
0263     nucl_radius_fm_ = real_type{1.2}
0264                       * fastpow(real_type(a_mass.get()), real_type{1} / 3);
0265 }
0266 
0267 //---------------------------------------------------------------------------//
0268 /*!
0269  * Calculate the uniform-uniform folded form factor by calculating momentum.
0270  */
0271 CELER_FUNCTION real_type
0272 UUNuclearFormFactor::operator()(MomentumSq target_momsq) const
0273 {
0274     CELER_EXPECT(target_momsq >= zero_quantity());
0275     return (*this)(Momentum{std::sqrt(target_momsq.value())});
0276 }
0277 
0278 //---------------------------------------------------------------------------//
0279 /*!
0280  * Calculate the uniform-uniform folded form factor.
0281  */
0282 CELER_FUNCTION real_type UUNuclearFormFactor::operator()(Momentum target_mom) const
0283 {
0284     auto sphere_ff = [&target_mom](real_type r) {
0285         // x = q R / hbar
0286         // r units: fm
0287         real_type x = value_as<Momentum>(target_mom)
0288                       * (r * value_as<InvMomentum>(fm_par_hbar()));
0289         return (3 / ipow<3>(x)) * std::fma(-x, std::cos(x), std::sin(x));
0290     };
0291 
0292     // Due to catastrophic error for small x, clamp the result to 1
0293     return min(sphere_ff(nucl_radius_fm_)
0294                    * sphere_ff(UUNuclearFormFactor::skin_radius_fm()),
0295                real_type{1});
0296 }
0297 
0298 //---------------------------------------------------------------------------//
0299 }  // namespace celeritas