Warning, file /include/celeritas/em/xs/WentzelHelper.hh was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include "corecel/Macros.hh"
0010 #include "corecel/Types.hh"
0011 #include "corecel/math/Algorithms.hh"
0012 #include "celeritas/em/data/CommonCoulombData.hh"
0013 #include "celeritas/em/data/WentzelOKVIData.hh"
0014 #include "celeritas/mat/MaterialView.hh"
0015 #include "celeritas/phys/AtomicNumber.hh"
0016 #include "celeritas/phys/ParticleTrackView.hh"
0017
0018 namespace celeritas
0019 {
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 class WentzelHelper
0039 {
0040 public:
0041
0042
0043 using Charge = units::ElementaryCharge;
0044 using Energy = units::MevEnergy;
0045 using Mass = units::MevMass;
0046 using MomentumSq = units::MevMomentumSq;
0047
0048
0049 public:
0050
0051 inline CELER_FUNCTION
0052 WentzelHelper(ParticleTrackView const& particle,
0053 MaterialView const& material,
0054 AtomicNumber target_z,
0055 NativeCRef<WentzelOKVIData> const& wentzel,
0056 CoulombIds const& ids,
0057 Energy cutoff);
0058
0059
0060 CELER_FUNCTION AtomicNumber atomic_number() const { return target_z_; }
0061
0062
0063 CELER_FUNCTION real_type screening_coefficient() const
0064 {
0065 return screening_coefficient_;
0066 }
0067
0068
0069 CELER_FUNCTION real_type mott_factor() const { return mott_factor_; }
0070
0071
0072 CELER_FUNCTION real_type kin_factor() const { return kin_factor_; }
0073
0074
0075 CELER_FUNCTION real_type cos_thetamax_electron() const
0076 {
0077 return cos_thetamax_elec_;
0078 }
0079
0080
0081 CELER_FUNCTION real_type cos_thetamax_nuclear() const
0082 {
0083 return cos_thetamax_nuc_;
0084 }
0085
0086
0087 inline CELER_FUNCTION real_type
0088 calc_xs_electron(real_type cos_thetamin, real_type cos_thetamax) const;
0089
0090
0091 inline CELER_FUNCTION real_type
0092 calc_xs_nuclear(real_type cos_thetamin, real_type cos_thetamax) const;
0093
0094 private:
0095
0096
0097 AtomicNumber const target_z_;
0098 real_type screening_coefficient_;
0099 real_type kin_factor_;
0100 real_type mott_factor_;
0101 real_type cos_thetamax_elec_;
0102 real_type cos_thetamax_nuc_;
0103
0104
0105
0106
0107 static CELER_CONSTEXPR_FUNCTION MomentumSq screen_r_sq_elec();
0108
0109
0110 static inline CELER_FUNCTION real_type calc_cos_thetamax_electron(
0111 ParticleTrackView const&, CoulombIds const&, Energy, Mass);
0112
0113
0114 inline CELER_FUNCTION real_type calc_screening_coefficient(
0115 ParticleTrackView const&, CoulombIds const&) const;
0116
0117
0118 inline CELER_FUNCTION real_type calc_kin_factor(ParticleTrackView const&,
0119 Mass) const;
0120
0121
0122 inline CELER_FUNCTION real_type calc_cos_thetamax_nuclear(
0123 ParticleTrackView const&,
0124 MaterialView const& material,
0125 NativeCRef<WentzelOKVIData> const& wentzel) const;
0126
0127
0128 inline CELER_FUNCTION real_type calc_xs_factor(real_type cos_thetamin,
0129 real_type cos_thetamax) const;
0130 };
0131
0132
0133
0134
0135
0136
0137
0138 CELER_FUNCTION
0139 WentzelHelper::WentzelHelper(ParticleTrackView const& particle,
0140 MaterialView const& material,
0141 AtomicNumber target_z,
0142 NativeCRef<WentzelOKVIData> const& wentzel,
0143 CoulombIds const& ids,
0144 Energy cutoff)
0145 : target_z_(target_z)
0146 , screening_coefficient_(this->calc_screening_coefficient(particle, ids)
0147 * wentzel.params.screening_factor)
0148 , kin_factor_(this->calc_kin_factor(particle, wentzel.electron_mass))
0149 , mott_factor_(particle.particle_id() == ids.electron
0150 ? 1 + real_type(2e-4) * ipow<2>(target_z_.get())
0151 : 1)
0152 , cos_thetamax_elec_(this->calc_cos_thetamax_electron(
0153 particle, ids, cutoff, wentzel.electron_mass))
0154 , cos_thetamax_nuc_(
0155 this->calc_cos_thetamax_nuclear(particle, material, wentzel))
0156 {
0157 CELER_EXPECT(screening_coefficient_ > 0);
0158 CELER_EXPECT(cos_thetamax_elec_ >= -1 && cos_thetamax_elec_ <= 1);
0159 CELER_EXPECT(cos_thetamax_nuc_ >= -1 && cos_thetamax_nuc_ <= 1);
0160 }
0161
0162
0163
0164
0165
0166 CELER_FUNCTION real_type WentzelHelper::calc_xs_electron(
0167 real_type cos_thetamin, real_type cos_thetamax) const
0168 {
0169 cos_thetamin = max(cos_thetamin, cos_thetamax_elec_);
0170 cos_thetamax = max(cos_thetamax, cos_thetamax_elec_);
0171 if (cos_thetamin <= cos_thetamax)
0172 {
0173 return 0;
0174 }
0175 return this->calc_xs_factor(cos_thetamin, cos_thetamax);
0176 }
0177
0178
0179
0180
0181
0182 CELER_FUNCTION real_type WentzelHelper::calc_xs_nuclear(
0183 real_type cos_thetamin, real_type cos_thetamax) const
0184 {
0185 return target_z_.get() * this->calc_xs_factor(cos_thetamin, cos_thetamax);
0186 }
0187
0188
0189
0190
0191
0192 CELER_FUNCTION real_type WentzelHelper::calc_xs_factor(
0193 real_type cos_thetamin, real_type cos_thetamax) const
0194 {
0195 return kin_factor_ * mott_factor_ * (cos_thetamin - cos_thetamax)
0196 / ((1 - cos_thetamin + 2 * screening_coefficient_)
0197 * (1 - cos_thetamax + 2 * screening_coefficient_));
0198 }
0199
0200
0201
0202
0203
0204
0205
0206
0207 CELER_FUNCTION real_type WentzelHelper::calc_screening_coefficient(
0208 ParticleTrackView const& particle, CoulombIds const& ids) const
0209 {
0210
0211 real_type correction = 1;
0212 real_type sq_cbrt_z = fastpow(real_type(target_z_.get()), real_type{2} / 3);
0213 if (target_z_.get() > 1)
0214 {
0215
0216
0217
0218 real_type factor;
0219 real_type z_factor = 1;
0220 if (particle.particle_id() == ids.electron
0221 || particle.particle_id() == ids.positron)
0222 {
0223
0224 real_type tau = value_as<Energy>(particle.energy())
0225 / value_as<Mass>(particle.mass());
0226 factor = std::sqrt(tau / (tau + sq_cbrt_z));
0227 }
0228 else
0229 {
0230
0231 factor = ipow<2>(value_as<Charge>(particle.charge()));
0232 z_factor += std::exp(-ipow<2>(target_z_.get()) * real_type(0.001));
0233 }
0234 correction = min(target_z_.get() * real_type{1.13},
0235 real_type{1.13}
0236 + real_type{3.76}
0237 * ipow<2>(target_z_.get()
0238 * constants::alpha_fine_structure)
0239 * factor / particle.beta_sq())
0240 * z_factor;
0241 }
0242
0243 return correction * sq_cbrt_z
0244 * value_as<MomentumSq>(this->screen_r_sq_elec())
0245 / value_as<MomentumSq>(particle.momentum_sq());
0246 }
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263 CELER_CONSTEXPR_FUNCTION auto WentzelHelper::screen_r_sq_elec() -> MomentumSq
0264 {
0265
0266 constexpr Constant ctf{0.8853413770001135};
0267
0268 return native_value_to<MomentumSq>(
0269 ipow<2>(constants::hbar_planck / (2 * ctf * constants::a0_bohr)));
0270 }
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284 CELER_FUNCTION real_type WentzelHelper::calc_kin_factor(
0285 ParticleTrackView const& particle, Mass electron_mass) const
0286 {
0287 constexpr Constant twopirsq = 2 * constants::pi
0288 * ipow<2>(constants::r_electron);
0289 return twopirsq * target_z_.get()
0290 * ipow<2>(value_as<Mass>(electron_mass)
0291 * value_as<Charge>(particle.charge()))
0292 / (particle.beta_sq()
0293 * value_as<MomentumSq>(particle.momentum_sq()));
0294 }
0295
0296
0297
0298
0299
0300
0301
0302
0303 CELER_FUNCTION real_type
0304 WentzelHelper::calc_cos_thetamax_electron(ParticleTrackView const& particle,
0305 CoulombIds const& ids,
0306 Energy cutoff,
0307 Mass electron_mass)
0308 {
0309 real_type result = 0;
0310 real_type inc_energy = value_as<Energy>(particle.energy());
0311 real_type mass = value_as<Mass>(particle.mass());
0312
0313 if (particle.particle_id() == ids.electron
0314 || particle.particle_id() == ids.positron)
0315 {
0316
0317 real_type max_energy = particle.particle_id() == ids.electron
0318 ? real_type{0.5} * inc_energy
0319 : inc_energy;
0320 real_type final_energy = inc_energy
0321 - min(value_as<Energy>(cutoff), max_energy);
0322 if (final_energy > 0)
0323 {
0324 real_type inc_ratio = 1 + 2 * mass / inc_energy;
0325 real_type final_ratio = 1 + 2 * mass / final_energy;
0326 result = clamp<real_type>(std::sqrt(inc_ratio / final_ratio), 0, 1);
0327 }
0328 }
0329 else
0330 {
0331
0332 real_type mass_ratio = value_as<Mass>(electron_mass) / mass;
0333 real_type tau = inc_energy / mass;
0334 real_type max_energy
0335 = 2 * value_as<Mass>(electron_mass) * tau * (tau + 2)
0336 / (1 + 2 * mass_ratio * (tau + 1) + ipow<2>(mass_ratio));
0337 result = -min(value_as<Energy>(cutoff), max_energy)
0338 * value_as<Mass>(electron_mass)
0339 / value_as<MomentumSq>(particle.momentum_sq());
0340 }
0341 CELER_ENSURE(result >= 0 && result <= 1);
0342 return result;
0343 }
0344
0345
0346
0347
0348
0349 CELER_FUNCTION real_type WentzelHelper::calc_cos_thetamax_nuclear(
0350 ParticleTrackView const& particle,
0351 MaterialView const& material,
0352 NativeCRef<WentzelOKVIData> const& wentzel) const
0353 {
0354 if (wentzel.params.is_combined)
0355 {
0356 CELER_ASSERT(material.material_id() < wentzel.inv_mass_cbrt_sq.size());
0357 return max(wentzel.params.costheta_limit,
0358 1
0359 - wentzel.params.a_sq_factor
0360 * wentzel.inv_mass_cbrt_sq[material.material_id()]
0361 / value_as<MomentumSq>(particle.momentum_sq()));
0362 }
0363 return wentzel.params.costheta_limit;
0364 }
0365
0366
0367 }