![]() |
|
|||
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 NUCLEUS_H 0007 #define NUCLEUS_H 0008 0009 #include <memory> 0010 #include <random> 0011 #include <string> 0012 #include <vector> 0013 0014 #include "fwd_decl.h" 0015 #include "nucleon.h" 0016 0017 #ifdef TRENTO_HDF5 0018 // forward declaration for std::unique_ptr<H5::DataSet> member of ManualNucleus 0019 namespace H5 { 0020 class DataSet; 0021 } 0022 #endif 0023 0024 namespace trento { 0025 0026 // Alias for a smart pointer to a Nucleus. 0027 using NucleusPtr = std::unique_ptr<Nucleus>; 0028 0029 /// \rst 0030 /// Interface class to all nucleus types. Stores an ensemble of nucleons and 0031 /// randomly samples their positions. Implements a standard iterator interface 0032 /// through ``begin()`` and ``end()`` functions. Iterating over a ``Nucleus`` 0033 /// means iterating over its ``Nucleon`` members. 0034 /// \endrst 0035 class Nucleus { 0036 public: 0037 /// \rst 0038 /// The canonical way to create a ``Nucleus``. Constructs the appropriate 0039 /// subclass for the given species. Sets the Woods-Saxon parameters for Au, 0040 /// Pb, U, etc; parameters copied from the PHOBOS Glauber model: 0041 /// 0042 /// - http://inspirehep.net/record/786828 0043 /// - http://inspirehep.net/record/1310629 0044 /// 0045 /// Example:: 0046 /// 0047 /// std::unique_ptr<Nucleus> lead_nucleus = Nucleus::create("Pb"); 0048 /// double radius = lead_nucleus->radius(); 0049 /// lead_nucleus->sample_nucleons(0); 0050 /// for (const auto& nucleon : *lead_nucleus) 0051 /// do_something(nucleon) 0052 /// 0053 /// \endrst 0054 /// 0055 /// \param species standard symbol, e.g. "p" for proton or "Pb" for lead-208 0056 /// \param nucleon_dmin minimum nucleon-nucleon distance for Woods-Saxon 0057 /// nuclei (optional, default zero) 0058 /// 0059 /// \return a smart pointer \c std::unique_ptr<Nucleus> 0060 /// 0061 /// \throw std::invalid_argument for unknown species 0062 static NucleusPtr create(const std::string& species, double nucleon_width, double nucleon_dmin = 0); 0063 0064 /// Default virtual destructor for abstract base class. 0065 virtual ~Nucleus() = default; 0066 0067 /// The "radius", i.e. the maximum distance at which a nucleon could be 0068 /// placed. 0069 virtual double radius() const = 0; 0070 0071 /// Sample a new ensemble of nucleon positions with the given offset in the 0072 /// x-direction. 0073 void sample_nucleons(double offset); 0074 0075 using size_type = std::vector<Nucleon>::size_type; 0076 using iterator = std::vector<Nucleon>::iterator; 0077 using const_iterator = std::vector<Nucleon>::const_iterator; 0078 0079 // size = number of nucleons 0080 size_type size() const noexcept 0081 { return nucleons_.size(); } 0082 0083 // non-const overload 0084 iterator begin() noexcept 0085 { return nucleons_.begin(); } 0086 iterator end() noexcept 0087 { return nucleons_.end(); } 0088 0089 // const overload 0090 const_iterator begin() const noexcept 0091 { return nucleons_.begin(); } 0092 const_iterator end() const noexcept 0093 { return nucleons_.end(); } 0094 0095 // forced const 0096 const_iterator cbegin() const noexcept 0097 { return nucleons_.cbegin(); } 0098 const_iterator cend() const noexcept 0099 { return nucleons_.cend(); } 0100 0101 protected: 0102 /// Constructor only accessible by derived classes. 0103 /// \param A number of nucleons 0104 explicit Nucleus(std::size_t A); 0105 0106 /// \rst 0107 /// Set a ``Nucleon`` position. This function provides a consistent interface 0108 /// to derived classes and ensures the position is correctly offset. 0109 /// ``Nucleus`` is a friend of ``Nucleon`` and therefore able to set nucleon 0110 /// positions; the derived classes must use this function to set positions. 0111 /// \endrst 0112 void set_nucleon_position(iterator nucleon, double x, double y, double z); 0113 0114 private: 0115 /// Internal interface to the actual implementation of the nucleon sampling 0116 /// algorithm, used in public function sample_nucleons(). This function must 0117 /// sample nucleon positions relative to the origin and set them using the 0118 /// protected function set_nucleon_position(), which enforces the offset. 0119 virtual void sample_nucleons_impl() = 0; 0120 0121 /// Internal storage of Nucleon objects. 0122 std::vector<Nucleon> nucleons_; 0123 0124 /// Offset of nucleon x-positions. 0125 /// This variable is reset upon each call of sample_nucleons() and is read by 0126 /// set_nucleon_position(). 0127 double offset_; 0128 }; 0129 0130 // Now declare Nucleus subclasses. 0131 // Each subclass must do the following: 0132 // - Define a public constructor which (at minimum) initializes a Nucleus 0133 // with the required number of nucleons. 0134 // - Override and implement the pure virtual functions 0135 // radius() and sample_nucleons_impl(). 0136 0137 /// Trivial nucleus with a single nucleon. 0138 class Proton : public Nucleus { 0139 public: 0140 /// Default constructor. 0141 Proton(); 0142 0143 /// The radius of a proton is trivially zero. 0144 virtual double radius() const override; 0145 0146 private: 0147 /// The proton trivially places its nucleon at the origin. 0148 virtual void sample_nucleons_impl() override; 0149 }; 0150 0151 /// \rst 0152 /// Samples pairs of nucleons from the Hulthén wavefunction 0153 /// 0154 /// .. math:: 0155 /// 0156 /// f(r) \propto \biggl( \frac{\exp(-ar) - \exp(-br)}{r} \biggr)^2. 0157 /// 0158 /// http://inspirehep.net/record/1261055 0159 /// 0160 /// \endrst 0161 class Deuteron : public Nucleus { 0162 public: 0163 /// Insantiate with values for the (a, b) parameters. 0164 /// The defaults are from the PHOBOS Glauber model. 0165 Deuteron(double a = 0.457, double b = 2.35); 0166 0167 /// The radius is computed from the parameters (a, b). 0168 virtual double radius() const override; 0169 0170 private: 0171 /// Sample positions from the Hulthén wavefunction. 0172 virtual void sample_nucleons_impl() override; 0173 0174 /// Internal storage of wavefunction parameters. 0175 const double a_, b_; 0176 }; 0177 0178 /// A nucleus that can check if its nucleons are within a specified minimum 0179 /// distance. 0180 class MinDistNucleus : public Nucleus { 0181 protected: 0182 /// \param A number of nucleons 0183 /// \param dmin minimum nucleon-nucleon distance (optional, default zero) 0184 MinDistNucleus(std::size_t A, double dmin = 0); 0185 0186 /// \rst 0187 /// Check if a ``Nucleon`` is too close (within the minimum distance) of any 0188 /// previously placed nucleons. Specifically, check nucleons from ``begin()`` 0189 /// up to the given iterator. 0190 /// \endrst 0191 bool is_too_close(const_iterator nucleon) const; 0192 0193 private: 0194 /// Internal storage of squared minimum distance. 0195 const double dminsq_; 0196 }; 0197 0198 /// \rst 0199 /// Samples nucleons from a spherically symmetric Woods-Saxon distribution 0200 /// 0201 /// .. math:: 0202 /// 0203 /// f(r) \propto \frac{1}{1 + \exp(\frac{r-R}{a})}. 0204 /// 0205 /// For non-deformed heavy nuclei such as lead. 0206 /// 0207 /// \endrst 0208 class WoodsSaxonNucleus : public MinDistNucleus { 0209 public: 0210 /// ``Nucleus::create()`` sets these parameters for a given species. 0211 /// \param A number of nucleons 0212 /// \param R Woods-Saxon radius 0213 /// \param a Woods-Saxon surface thickness 0214 /// \param dmin minimum nucleon-nucleon distance (optional, default zero) 0215 WoodsSaxonNucleus(std::size_t A, double R, double a, double dmin = 0); 0216 0217 /// The radius of a Woods-Saxon Nucleus is computed from the parameters (R, a). 0218 virtual double radius() const override; 0219 0220 private: 0221 /// Sample Woods-Saxon nucleon positions. 0222 virtual void sample_nucleons_impl() override; 0223 0224 /// Woods-Saxon parameters. 0225 const double R_, a_; 0226 0227 /// Woods-Saxon distribution object. Since the dist does not have an analytic 0228 /// inverse CDF, approximate it as a piecewise linear dist. For a large 0229 /// number of steps this is very accurate. 0230 mutable std::piecewise_linear_distribution<double> woods_saxon_dist_; 0231 }; 0232 0233 /// \rst 0234 /// Samples nucleons from a deformed spheroidal Woods-Saxon distribution 0235 /// 0236 /// .. math:: 0237 /// 0238 /// f(r, \theta) \propto 0239 /// \frac{1}{1 + \exp(\frac{r-R(1+\beta_2Y_{20}+\beta_4Y_{40})}{a})}. 0240 /// 0241 /// For deformed heavy nuclei such as uranium. 0242 /// 0243 /// \endrst 0244 class DeformedWoodsSaxonNucleus : public MinDistNucleus { 0245 public: 0246 /// ``Nucleus::create()`` sets these parameters for a given species. 0247 /// \param A number of nucleons 0248 /// \param R Woods-Saxon radius 0249 /// \param a Woods-Saxon surface thickness 0250 /// \param beta2 Woods-Saxon deformation parameter 0251 /// \param beta4 Woods-Saxon deformation parameter 0252 /// \param dmin minimum nucleon-nucleon distance (optional, default zero) 0253 DeformedWoodsSaxonNucleus(std::size_t A, double R, double a, 0254 double beta2, double beta4, double dmin = 0); 0255 0256 /// The radius of a deformed Woods-Saxon Nucleus is computed from the 0257 /// parameters (R, a, beta2, beta4). 0258 virtual double radius() const override; 0259 0260 private: 0261 /// Sample deformed Woods-Saxon nucleon positions. 0262 virtual void sample_nucleons_impl() override; 0263 0264 /// Evaluate the deformed Woods-Saxon distribution. 0265 double deformed_woods_saxon_dist(double r, double cos_theta) const; 0266 0267 /// Woods-Saxon parameters. 0268 const double R_, a_, beta2_, beta4_; 0269 0270 /// Maximum radius. 0271 const double rmax_; 0272 }; 0273 0274 #ifdef TRENTO_HDF5 0275 0276 /// Reads manual nuclear configurations from an HDF5 file. 0277 class ManualNucleus : public Nucleus { 0278 public: 0279 /// Create a ManualNucleus that reads from the given file. 0280 /// Throw std::invalid_argument if there are any problems. 0281 /// 0282 /// Since this is a derived class, the base Nucleus class is initialized 0283 /// before any the data members. This creates a bit of a catch-22, since the 0284 /// number of nucleons must be known to initialize the base class, but that 0285 /// must be deduced from the file. As a workaround, this factory function 0286 /// opens the file, determines the number of nucleons, and then calls the 0287 /// constructor. 0288 static std::unique_ptr<ManualNucleus> create(const std::string& path); 0289 0290 /// Must define destructor because of member pointer to incomplete type. 0291 /// See explanation for Collider destructor. 0292 virtual ~ManualNucleus() override; 0293 0294 /// The radius is determined by reading many positions from the file and 0295 /// saving the maximum. 0296 virtual double radius() const override; 0297 0298 private: 0299 /// Private constructor -- use create(). 0300 /// \param dataset smart pointer to HDF5 dataset 0301 /// \param nconfigs number of nucleus configs in the dataset 0302 /// \param A number of nucleons 0303 /// \param rmax max radius 0304 ManualNucleus(std::unique_ptr<H5::DataSet> dataset, 0305 std::size_t nconfigs, std::size_t A, double rmax); 0306 0307 /// Read a configuration from the file, rotate it, and set nucleon positions. 0308 virtual void sample_nucleons_impl() override; 0309 0310 /// Internal pointer to HDF5 dataset object (PIMPL-like). 0311 const std::unique_ptr<H5::DataSet> dataset_; 0312 0313 /// Internal storage of the maximum radius. 0314 const double rmax_; 0315 0316 /// Distribution for choosing random configs. 0317 std::uniform_int_distribution<std::size_t> index_dist_; 0318 }; 0319 0320 #endif // TRENTO_HDF5 0321 0322 } // namespace trento 0323 0324 #endif // NUCLEUS_H
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |