Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:19:07

0001 // TRENTO: Reduced Thickness Event-by-event Nuclear Topology
0002 // Copyright 2015 Jonah E. Bernhard, J. Scott Moreland
0003 // TRENTO3D: Three-dimensional extension of TRENTO by Weiyao Ke
0004 // MIT License
0005 
0006 #ifndef NUCLEON_H
0007 #define NUCLEON_H
0008 
0009 #include <boost/math/constants/constants.hpp>
0010 
0011 #include "fast_exp.h"
0012 #include "fwd_decl.h"
0013 #include "random.h"
0014 
0015 namespace trento {
0016 
0017 class Nucleon;
0018 
0019 /// \rst
0020 /// Encapsulates properties shared by all nucleons: transverse thickness
0021 /// profile, cross section, fluctuations.  Responsible for sampling
0022 /// nucleon-nucleon participation with given `\sigma_{NN}`.
0023 /// \endrst
0024 class NucleonProfile {
0025  public:
0026   /// Instantiate from the configuration.
0027   explicit NucleonProfile(const VarMap& var_map);
0028 
0029   /// The radius at which the nucleon profile is truncated.
0030   double radius() const;
0031 
0032   /// The maximum impact parameter for participation.
0033   double max_impact() const;
0034 
0035   /// Randomly fluctuate the profile.  Should be called prior to evaluating the
0036   /// thickness function for a new nucleon.
0037   void fluctuate();
0038 
0039   /// Compute the thickness function at a (squared) distance from the profile
0040   /// center.
0041   double thickness(double distance_sqr) const;
0042 
0043   /// WK: same as above, but without the Gamma fluctuation, 
0044   /// used in the calculation of binary collision density 
0045   double deterministic_thickness(double distance_sqr) const;
0046 
0047   /// WK: return Tpp given bpp^2
0048   double norm_Tpp(double bpp_sqr) const;
0049 
0050   /// Randomly determine if a pair of nucleons participates.
0051   bool participate(Nucleon& A, Nucleon& B) const;
0052 
0053  private:
0054   /// Width of Gaussian thickness function.
0055   const double width_sqr_;
0056 
0057   /// Truncate the Gaussian at this radius.
0058   const double trunc_radius_sqr_;
0059 
0060   /// Maximum impact parameter for participants.
0061   const double max_impact_sqr_;
0062 
0063   /// Cache (-1/2w^2) for use in the thickness function exponential.
0064   /// Yes, this actually makes a speed difference...
0065   const double neg_one_div_two_width_sqr_;
0066 
0067   /// WK 1/4w^2
0068   const double neg_one_div_four_width_sqr_;
0069 
0070   /// WK 1/4pi
0071   const double one_div_four_pi_;
0072 
0073   /// Dimensionless parameter set to reproduce the inelastic nucleon-nucleon
0074   /// cross section \sigma_{NN}.  Calculated in constructor.
0075   const double cross_sec_param_;
0076 
0077   /// Fast exponential for calculating the thickness profile.
0078   const FastExp<double> fast_exp_;
0079 
0080   /// Fluctuation distribution.
0081   std::gamma_distribution<double> fluct_dist_;
0082 
0083   /// Thickness function prefactor = fluct/(2*pi*w^2)
0084   double prefactor_;
0085  
0086   /// bool variable to calcualte Ncoll
0087   bool with_ncoll_;
0088 };
0089 
0090 /// \rst
0091 /// Represents a single nucleon.  Stores its position and whether or not it's a
0092 /// participant.  These properties are globally readable, but can only be set
0093 /// through ``Nucleus`` and ``NucleonProfile``.
0094 /// \endrst
0095 class Nucleon {
0096  public:
0097   /// Only a default constructor is necessary\---the class is designed to be
0098   /// constructed once and repeatedly updated.
0099   Nucleon() = default;
0100 
0101   /// The transverse \em x position.
0102   double x() const;
0103 
0104   /// The transverse \em y position.
0105   double y() const;
0106 
0107   /// The longitudinal \em z position.
0108   double z() const;
0109 
0110   /// Whether or not this nucleon is a participant.
0111   bool is_participant() const;
0112 
0113  private:
0114   /// A Nucleus must be able to set its Nucleon positions.
0115   friend class Nucleus;
0116 
0117   /// The NucleonProfile samples participants so must be able to set
0118   /// participation status.
0119   friend bool NucleonProfile::participate(Nucleon&, Nucleon&) const;
0120 
0121   /// Set the position and reset participant status to false.
0122   void set_position(double x, double y, double z);
0123 
0124   /// Mark as a participant.
0125   void set_participant();
0126 
0127   /// Internal storage of the position.
0128   double x_, y_, z_;
0129 
0130   /// Internal storage of participant status.
0131   bool participant_;
0132 };
0133 
0134 // These functions are short, called very often, and account for a large
0135 // fraction of the total computation time, so request inlining.
0136 
0137 // Nucleon inline member functions
0138 
0139 inline double Nucleon::x() const {
0140   return x_;
0141 }
0142 
0143 inline double Nucleon::y() const {
0144   return y_;
0145 }
0146 
0147 inline double Nucleon::z() const {
0148   return z_;
0149 }
0150 
0151 inline bool Nucleon::is_participant() const {
0152   return participant_;
0153 }
0154 
0155 inline void Nucleon::set_position(double x, double y, double z) {
0156   x_ = x;
0157   y_ = y;
0158   z_ = z;
0159   participant_ = false;
0160 }
0161 
0162 inline void Nucleon::set_participant() {
0163   participant_ = true;
0164 }
0165 
0166 // NucleonProfile inline member functions
0167 
0168 inline double NucleonProfile::radius() const {
0169   return std::sqrt(trunc_radius_sqr_);
0170 }
0171 
0172 inline double NucleonProfile::max_impact() const {
0173   return std::sqrt(max_impact_sqr_);
0174 }
0175 
0176 inline void NucleonProfile::fluctuate() {
0177   prefactor_ = fluct_dist_(random::engine) *
0178      math::double_constants::one_div_two_pi / width_sqr_;
0179 }
0180 
0181 inline double NucleonProfile::thickness(double distance_sqr) const {
0182   if (distance_sqr > trunc_radius_sqr_)
0183     return 0.;
0184   return prefactor_ * fast_exp_(neg_one_div_two_width_sqr_*distance_sqr);
0185 }
0186 
0187 // WK
0188 inline double NucleonProfile::deterministic_thickness(double distance_sqr) const {
0189   if (distance_sqr > trunc_radius_sqr_)
0190     return 0.;
0191   return math::double_constants::one_div_two_pi / width_sqr_ 
0192         * fast_exp_(neg_one_div_two_width_sqr_*distance_sqr);
0193 }
0194 
0195 // WK
0196 inline double NucleonProfile::norm_Tpp(double bpp_sqr) const  {
0197   return one_div_four_pi_ / width_sqr_ 
0198         * fast_exp_(neg_one_div_four_width_sqr_*bpp_sqr);
0199 }
0200 
0201 inline bool NucleonProfile::participate(Nucleon& A, Nucleon& B) const {
0202   // If both nucleons are already participants, there's nothing to do, unless
0203   // in Ncoll mode
0204   if (A.is_participant() && B.is_participant() && (! with_ncoll_))
0205     return true;
0206 
0207   double dx = A.x() - B.x();
0208   double dy = A.y() - B.y();
0209   double distance_sqr = dx*dx + dy*dy;
0210 
0211   // Check if nucleons are out of range.
0212   if (distance_sqr > max_impact_sqr_)
0213     return false;
0214 
0215   // The probability is
0216   //   P = 1 - exp(...)
0217   // which we could sample as
0218   //   P > U
0219   // where U is a standard uniform (0, 1) random number.  We can also compute
0220   //   1 - P = exp(...)
0221   // and then sample
0222   //   (1 - P) > (1 - U)
0223   // or equivalently
0224   //   (1 - P) < U
0225   auto one_minus_prob = std::exp(
0226       -std::exp(cross_sec_param_ - .25*distance_sqr/width_sqr_));
0227 
0228   // Sample one random number and decide if this pair participates.
0229   if (one_minus_prob < random::canonical<double>()) {
0230     A.set_participant();
0231     B.set_participant();
0232     return true;
0233   }
0234 
0235   return false;
0236 }
0237 
0238 }  // namespace trento
0239 
0240 #endif  // NUCLEON_H