File indexing completed on 2025-11-03 09:43:45
0001 
0002 
0003 
0004 
0005 
0006 
0007 #pragma once
0008 
0009 #include "corecel/Macros.hh"
0010 #include "corecel/Types.hh"
0011 #include "corecel/grid/NonuniformGrid.hh"
0012 #include "corecel/grid/TwodGridCalculator.hh"
0013 #include "corecel/grid/TwodGridData.hh"
0014 #include "corecel/math/Algorithms.hh"
0015 #include "corecel/math/ArrayOperators.hh"
0016 #include "corecel/math/ArrayUtils.hh"
0017 #include "corecel/random/distribution/GenerateCanonical.hh"
0018 #include "corecel/random/distribution/UniformRealDistribution.hh"
0019 #include "celeritas/Quantities.hh"
0020 #include "celeritas/Types.hh"
0021 #include "celeritas/grid/InverseCdfFinder.hh"
0022 #include "celeritas/phys/FourVector.hh"
0023 
0024 #include "CascadeParticle.hh"
0025 
0026 namespace celeritas
0027 {
0028 namespace detail
0029 {
0030 
0031 
0032 
0033 
0034 
0035 
0036 
0037 
0038 
0039 
0040 
0041 
0042 
0043 
0044 
0045 class CascadeCollider
0046 {
0047   public:
0048     
0049     
0050     using FinalState = Array<CascadeParticle, 2>;
0051     
0052 
0053   public:
0054     
0055     inline CELER_FUNCTION CascadeCollider(NeutronInelasticRef const& shared,
0056                                           CascadeParticle const& bullet,
0057                                           CascadeParticle const& target);
0058 
0059     
0060     template<class Engine>
0061     inline CELER_FUNCTION FinalState operator()(Engine& rng);
0062 
0063   private:
0064     
0065 
0066     using Mass = units::MevMass;
0067     using Momentum = units::MevMomentum;
0068     using Grid = NonuniformGrid<real_type>;
0069     using UniformRealDist = UniformRealDistribution<real_type>;
0070 
0071     
0072 
0073     
0074     NeutronInelasticRef const& shared_;
0075     
0076     CascadeParticle const& bullet_;
0077     CascadeParticle const& target_;
0078 
0079     
0080     ChannelId ch_id_;
0081     
0082     Real3 cm_velocity_;
0083     
0084     real_type cm_p_;
0085     
0086     real_type kin_energy_;
0087 
0088     
0089     UniformRealDist sample_phi_;
0090 
0091     
0092 
0093     
0094     static CELER_CONSTEXPR_FUNCTION real_type epsilon()
0095     {
0096         return real_type{1e-10};
0097     }
0098 
0099     
0100 
0101     
0102     inline CELER_FUNCTION real_type calc_cm_p(FourVector const& v) const;
0103 };
0104 
0105 
0106 
0107 
0108 
0109 
0110 
0111 CELER_FUNCTION
0112 CascadeCollider::CascadeCollider(NeutronInelasticRef const& shared,
0113                                  CascadeParticle const& bullet,
0114                                  CascadeParticle const& target)
0115     : shared_(shared)
0116     , bullet_(bullet)
0117     , target_(target)
0118     , ch_id_(ChannelId{
0119           static_cast<size_type>((bullet_.type == target_.type) ? 0 : 1)})
0120     , sample_phi_(0, static_cast<real_type>(2 * constants::pi))
0121 {
0122     
0123     FourVector sum_four_vec = bullet_.four_vec + target_.four_vec;
0124     cm_velocity_ = boost_vector(sum_four_vec);
0125     cm_p_ = this->calc_cm_p(sum_four_vec);
0126 
0127     
0128     FourVector bullet_p = bullet_.four_vec;
0129     boost(-boost_vector(target_.four_vec), &bullet_p);
0130     kin_energy_ = bullet_p.energy - norm(bullet_p);
0131 }
0132 
0133 
0134 
0135 
0136 
0137 template<class Engine>
0138 CELER_FUNCTION auto CascadeCollider::operator()(Engine& rng) -> FinalState
0139 {
0140     
0141     real_type cdf = generate_canonical(rng);
0142     TwodGridData const& cdf_grid = shared_.angular_cdf[ch_id_];
0143     Grid energy_grid(cdf_grid.x, shared_.reals);
0144     real_type cos_theta{0};
0145 
0146     if (kin_energy_ < energy_grid.back())
0147     {
0148         
0149         cos_theta = InverseCdfFinder(
0150             Grid(cdf_grid.y, shared_.reals),
0151             TwodGridCalculator(cdf_grid, shared_.reals)(kin_energy_))(cdf);
0152     }
0153     else
0154     {
0155         
0156         real_type slope = 2 * energy_grid.back() * ipow<2>(cm_p_);
0157         cos_theta = std::log(1 + cdf * std::expm1(2 * slope)) / slope - 1;
0158     }
0159 
0160     
0161     
0162     auto fv = FourVector::from_mass_momentum(
0163         bullet_.mass,
0164         Momentum{cm_p_},
0165         from_spherical(cos_theta, sample_phi_(rng)));
0166 
0167     
0168     FinalState result = {bullet_, target_};
0169 
0170     FourVector cm_momentum = target_.four_vec;
0171     boost(-cm_velocity_, &cm_momentum);
0172 
0173     Real3 cm_dir = make_unit_vector(-cm_momentum.mom);
0174     real_type vel_parallel = dot_product(cm_velocity_, cm_dir);
0175 
0176     Real3 vscm = cm_velocity_;
0177     axpy(-vel_parallel, cm_dir, &vscm);
0178 
0179     if (norm(vscm) > this->epsilon())
0180     {
0181         vscm = make_unit_vector(vscm);
0182         Real3 vxcm = make_unit_vector(cross_product(cm_dir, cm_velocity_));
0183         if (norm(vxcm) > this->epsilon())
0184         {
0185             for (int i = 0; i < 3; ++i)
0186             {
0187                 result[0].four_vec.mom[i] = fv.mom[0] * vscm[i]
0188                                             + fv.mom[1] * vxcm[i]
0189                                             + fv.mom[2] * cm_dir[i];
0190             }
0191             result[0].four_vec.energy = fv.energy;
0192         }
0193     }
0194     else
0195     {
0196         
0197         result[0].four_vec = fv;
0198     }
0199 
0200     result[1].four_vec = {{-result[0].four_vec.mom},
0201                           hypot(cm_p_, value_as<Mass>(target_.mass))};
0202 
0203     
0204     for (auto i : range(2))
0205     {
0206         boost(cm_velocity_, &result[i].four_vec);
0207     }
0208 
0209     return result;
0210 }
0211 
0212 
0213 
0214 
0215 
0216 
0217 CELER_FUNCTION real_type CascadeCollider::calc_cm_p(FourVector const& v) const
0218 {
0219     
0220     real_type m0 = norm(v);
0221 
0222     real_type m1 = value_as<Mass>(bullet_.mass);
0223     real_type m2 = value_as<Mass>(target_.mass);
0224 
0225     real_type pc_sq = diffsq(m0, m1 - m2) * diffsq(m0, m1 + m2);
0226 
0227     return std::sqrt(clamp_to_nonneg(pc_sq)) / (2 * m0);
0228 }
0229 
0230 
0231 }  
0232 }