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 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