File indexing completed on 2025-10-30 08:37:32
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <cmath>
0010
0011 #include "corecel/math/Algorithms.hh"
0012 #include "celeritas/Quantities.hh"
0013 #include "celeritas/phys/AtomicNumber.hh"
0014
0015 namespace celeritas
0016 {
0017
0018
0019 struct NuclearFormFactorTraits
0020 {
0021
0022
0023 using AtomicMassNumber = AtomicNumber;
0024 using Momentum = units::MevMomentum;
0025 using MomentumSq = units::MevMomentumSq;
0026 using InvMomentum = RealQuantity<UnitInverse<Momentum::unit_type>>;
0027 using InvMomentumSq = RealQuantity<UnitInverse<MomentumSq::unit_type>>;
0028 using FFType = NuclearFormFactorType;
0029
0030
0031
0032 static CELER_CONSTEXPR_FUNCTION InvMomentum fm_par_hbar()
0033 {
0034 return native_value_to<InvMomentum>(units::femtometer
0035 / constants::hbar_planck);
0036 }
0037 };
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 class ExpNuclearFormFactor : public NuclearFormFactorTraits
0059 {
0060 public:
0061
0062 static CELER_CONSTEXPR_FUNCTION FFType ff_type()
0063 {
0064 return FFType::exponential;
0065 }
0066
0067
0068 explicit inline CELER_FUNCTION
0069 ExpNuclearFormFactor(AtomicMassNumber a_mass);
0070
0071
0072 explicit inline CELER_FUNCTION
0073 ExpNuclearFormFactor(InvMomentumSq prefactor);
0074
0075
0076 inline CELER_FUNCTION real_type operator()(MomentumSq target_momsq) const;
0077
0078
0079 inline CELER_FUNCTION real_type operator()(Momentum target_mom) const;
0080
0081
0082 CELER_FORCEINLINE_FUNCTION InvMomentumSq prefactor() const
0083 {
0084 return InvMomentumSq{prefactor_};
0085 }
0086
0087 private:
0088 real_type prefactor_;
0089 };
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 class GaussianNuclearFormFactor : public ExpNuclearFormFactor
0101 {
0102 public:
0103
0104 static CELER_CONSTEXPR_FUNCTION FFType ff_type()
0105 {
0106 return FFType::gaussian;
0107 }
0108
0109 using ExpNuclearFormFactor::ExpNuclearFormFactor;
0110
0111
0112 inline CELER_FUNCTION real_type operator()(MomentumSq target_momsq) const;
0113
0114
0115 inline CELER_FUNCTION real_type operator()(Momentum target_mom) const;
0116 };
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146 class UUNuclearFormFactor : public NuclearFormFactorTraits
0147 {
0148 public:
0149
0150 static CELER_CONSTEXPR_FUNCTION FFType ff_type() { return FFType::flat; }
0151
0152
0153 explicit inline CELER_FUNCTION UUNuclearFormFactor(AtomicMassNumber a_mass);
0154
0155
0156 inline CELER_FUNCTION real_type operator()(MomentumSq target_momsq) const;
0157
0158
0159 inline CELER_FUNCTION real_type operator()(Momentum target_mom) const;
0160
0161 private:
0162 real_type nucl_radius_fm_;
0163
0164
0165 static CELER_CONSTEXPR_FUNCTION real_type skin_radius_fm() { return 2; }
0166 };
0167
0168
0169
0170
0171
0172
0173
0174 CELER_FUNCTION
0175 ExpNuclearFormFactor::ExpNuclearFormFactor(AtomicMassNumber a_mass)
0176 {
0177 CELER_EXPECT(a_mass);
0178 real_type nucl_radius_fm = [a_mass] {
0179 if (CELER_UNLIKELY(a_mass == AtomicMassNumber{1}))
0180 {
0181
0182 return real_type{0.85};
0183 }
0184 return real_type{1.27}
0185 * fastpow(real_type(a_mass.get()), real_type{0.27});
0186 }();
0187 prefactor_ = ipow<2>(nucl_radius_fm * value_as<InvMomentum>(fm_par_hbar()))
0188 * (real_type{1} / 12);
0189 CELER_ENSURE(prefactor_ > 0);
0190 }
0191
0192
0193
0194
0195
0196 CELER_FUNCTION
0197 ExpNuclearFormFactor::ExpNuclearFormFactor(InvMomentumSq prefactor)
0198 : prefactor_{prefactor.value()}
0199 {
0200 CELER_EXPECT(prefactor_ > 0);
0201 }
0202
0203
0204
0205
0206
0207 CELER_FUNCTION real_type
0208 ExpNuclearFormFactor::operator()(MomentumSq target_momsq) const
0209 {
0210 CELER_EXPECT(target_momsq >= zero_quantity());
0211 return 1 / ipow<2>(1 + prefactor_ * target_momsq.value());
0212 }
0213
0214
0215
0216
0217
0218 CELER_FUNCTION real_type ExpNuclearFormFactor::operator()(Momentum target_mom) const
0219 {
0220 return (*this)(MomentumSq{ipow<2>(target_mom.value())});
0221 }
0222
0223
0224
0225
0226
0227 CELER_FUNCTION real_type
0228 GaussianNuclearFormFactor::operator()(MomentumSq target_momsq) const
0229 {
0230 CELER_EXPECT(target_momsq >= zero_quantity());
0231 return std::exp(-2 * value_as<InvMomentumSq>(this->prefactor())
0232 * target_momsq.value());
0233 }
0234
0235
0236
0237
0238
0239 CELER_FUNCTION real_type
0240 GaussianNuclearFormFactor::operator()(Momentum target_mom) const
0241 {
0242 return (*this)(MomentumSq{ipow<2>(target_mom.value())});
0243 }
0244
0245
0246
0247
0248
0249 CELER_FUNCTION UUNuclearFormFactor::UUNuclearFormFactor(AtomicMassNumber a_mass)
0250 {
0251 CELER_EXPECT(a_mass);
0252 nucl_radius_fm_ = real_type{1.2}
0253 * fastpow(real_type(a_mass.get()), real_type{1} / 3);
0254 }
0255
0256
0257
0258
0259
0260 CELER_FUNCTION real_type
0261 UUNuclearFormFactor::operator()(MomentumSq target_momsq) const
0262 {
0263 CELER_EXPECT(target_momsq >= zero_quantity());
0264 return (*this)(Momentum{std::sqrt(target_momsq.value())});
0265 }
0266
0267
0268
0269
0270
0271 CELER_FUNCTION real_type UUNuclearFormFactor::operator()(Momentum target_mom) const
0272 {
0273 auto sphere_ff = [&target_mom](real_type r) {
0274
0275
0276 real_type x = value_as<Momentum>(target_mom)
0277 * (r * value_as<InvMomentum>(fm_par_hbar()));
0278 return (3 / ipow<3>(x)) * std::fma(-x, std::cos(x), std::sin(x));
0279 };
0280
0281
0282 return min(sphere_ff(nucl_radius_fm_)
0283 * sphere_ff(UUNuclearFormFactor::skin_radius_fm()),
0284 real_type{1});
0285 }
0286
0287
0288 }