Version: SMASH-3.4
nucleus.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2022,2024-2025
3  * SMASH Team
4  *
5  * GNU General Public License (GPLv3 or later)
6  */
7 #ifndef SRC_INCLUDE_SMASH_NUCLEUS_H_
8 #define SRC_INCLUDE_SMASH_NUCLEUS_H_
9 
10 #include <map>
11 #include <stdexcept>
12 #include <vector>
13 
14 #include "configuration.h"
15 #include "constants.h"
16 #include "forwarddeclarations.h"
17 #include "fourvector.h"
18 #include "particledata.h"
19 #include "threevector.h"
20 
21 namespace smash {
22 
23 /**
24  * A nucleus is a collection of particles that are initialized,
25  * before the beginning of the simulation and all have the same velocity.
26  */
27 class Nucleus {
28  public:
29  /// default constructor
30  Nucleus() = default;
31 
32  /**
33  * Constructor for Nucleus, that needs the configuration parameters from
34  * the inputfile and the number of testparticles
35  *
36  * \param[in] config contains the parameters from the inputfile on the
37  * numbers of particles with a certain PDG code
38  * \param[in] nTest number of testparticles
39  */
40  Nucleus(Configuration &config, int nTest);
41 
42  /**
43  * Constructor which directly initializes the Nucleus with particles
44  * and respective counts.
45  * Only used for testing.
46  *
47  * \param[in] particle_list std::map, which maps PdgCode and count
48  * of this particle.
49  * \param[in] nTest Number of test particles.
50  * \param[in] spin_interaction_type whether to use spin interactions.
51  */
52  Nucleus(const std::map<PdgCode, int> &particle_list, int nTest,
53  SpinInteractionType spin_interaction_type = SpinInteractionType::Off);
54 
55  virtual ~Nucleus() = default;
56 
57  /**
58  * \return Mass of the nucleus [GeV].
59  * It needs to be double to allow for calculations at LHC energies.
60  */
61  double mass() const;
62 
63  /**
64  * The distribution of return values from this function is according to a
65  * spherically symmetric Woods-Saxon distribution suitable for this nucleus.
66  * \f$\frac{dN}{dr} = \frac{r^2}{\exp\left(\frac{r-r_0}{d}\right) +
67  * 1}\f$ where \f$d\f$ is the diffusiveness_ parameter and \f$r_0\f$ is
68  * nuclear_radius_.
69  *
70  * \return Woods-Saxon distributed position.
71  */
73 
74  /**
75  * Woods-Saxon distribution
76  * \param[in] x the position at which to evaluate the function
77  * \return un-normalized Woods-saxon probability
78  */
79  double woods_saxon(double x);
80 
81  /// Sets the positions of the nucleons inside a nucleus.
82  virtual void arrange_nucleons();
83 
84  /**
85  * Sets the deformation parameters of the Woods-Saxon distribution
86  * according to the current mass number.
87  * The values are taken from \iref{DeVries:1987atn} and
88  * \iref{Loizides:2014vua}. They are in agreement with MC-Glauber models such
89  * as GLISSANDO (see \iref{Rybczynski:2013yba}) and TGlauber MC (see
90  * \iref{Loizides:2017ack}).
91  */
92  virtual void set_parameters_automatic();
93 
94  /**
95  * Generates momenta according to Fermi motion for the nucleons.
96  * For neutrons and protons Fermi momenta are calculated as
97  * \f$ p_{F} = (3 \pi^2 \rho)^{1/3}\f$, where \f$ rho \f$ is
98  * neutron density for neutrons and proton density for protons.
99  * The actual momenta \f$p_x\f$, \f$p_y\f$, \f$p_z\f$ are
100  * uniformly distributed in the sphere with radius \f$p_F\f$.
101  */
102  virtual void generate_fermi_momenta();
103 
104  /**
105  * Boosts the nuclei into the computational frame, such that
106  * the nucleons have the appropriate momentum and the
107  * nuclei are lorentz-contracted. Note that the usual boost cannot be
108  * applied for nuclei, since the particles would end up with different
109  * times and the binding energy needs to be taken into account.
110  *
111  * \param[in] beta_scalar velocity in z-direction used for boost.
112  */
113  void boost(double beta_scalar);
114 
115  /**
116  * Adds particles from a map PDG code =>
117  * Number_of_particles_with_that_PDG_code to the nucleus. E.g., the map [2212:
118  * 6, 2112: 7] initializes C-13 (6 protons and 7 neutrons). The particles are
119  * only created, no position or momenta are yet assigned. It is also possible
120  * to use any other PDG code, in addition to nucleons.
121  *
122  * \param[out] particle_list The particle slots that are created.
123  * \param[in] testparticles Number of test particles to use.
124  */
125  void fill_from_list(const std::map<PdgCode, int> &particle_list,
126  int testparticles);
127 
128  /**
129  * Shifts the nucleus to correct impact parameter and z displacement.
130  *
131  * \param[in] z_offset is the shift in z-direction
132  * \param[in] x_offset is the shift in x-direction
133  * \param[in] simulation_time set the time and formation_time of each
134  * particle to this value.
135  */
136  void shift(double z_offset, double x_offset, double simulation_time);
137 
138  /**
139  * Rotates the nucleus using the three euler angles phi, theta and psi.
140  */
141  virtual void rotate();
142 
143  /**
144  * Copies the particles from this nucleus into the particle list.
145  *
146  * \param[out] particles Particle list with all constituents of a nucleus
147  */
148  void copy_particles(Particles *particles);
149 
150  /// Number of numerical (=test-)particles in the nucleus:
151  inline size_t size() const { return particles_.size(); }
152 
153  /**
154  * Number of physical particles in the nucleus:
155  *
156  * \throw TestparticleConfusion if the number of the nucleons is not a
157  * multiple of testparticles_.
158  */
159  inline size_t number_of_particles() const {
160  size_t nop = particles_.size() / testparticles_;
161  /* If size() is not a multiple of testparticles_, this will throw an
162  * error. */
163  if (nop * testparticles_ != particles_.size()) {
164  throw TestparticleConfusion(
165  "Number of test particles and test particles"
166  "per particle are incompatible.");
167  }
168  return nop;
169  }
170 
171  /**
172  * Number of physical protons in the nucleus:
173  *
174  * \return number of protons
175  * \throw Testparticleconfusion if the number of the protons is not a
176  * multiple of testparticles_.
177  */
178  inline size_t number_of_protons() const {
179  size_t proton_counter = 0;
180  /* If n_protons is not a multiple of testparticles_, this will throw an
181  * error. */
182  for (auto &particle : particles_) {
183  if (particle.type().pdgcode() == pdg::p) {
184  proton_counter++;
185  }
186  }
187 
188  size_t n_protons = proton_counter / testparticles_;
189 
190  if (n_protons * testparticles_ != proton_counter) {
191  throw TestparticleConfusion(
192  "Number of test protons and test particles"
193  "per proton are incompatible.");
194  }
195 
196  return n_protons;
197  }
198 
199  /**
200  * Calculate geometrical center of the nucleus
201  * \return \f$\mathbf{r}_s = \frac{1}{N} \sum_{i=1}^N \mathbf{r}_i\f$ (for a
202  * nucleus with N particles that are at the positions \f$\mathbf{r}_i\f$).
203  */
204  FourVector center() const;
205 
206  /// Sets target / projectile labels on nucleons
207  void set_label(BelongsTo label) {
208  for (ParticleData &data : particles_) {
209  data.set_belongs_to(label);
210  }
211  }
212 
213  /**
214  * Shifts the nucleus so that its center is at (0,0,0)
215  * \see center()
216  */
217  void align_center() {
218  FourVector centerpoint = center();
219  for (auto p = particles_.begin(); p != particles_.end(); ++p) {
220  p->set_4position(p->position() - centerpoint);
221  }
222  }
223 
224  /**
225  * Return the Woods-Saxon probability density for the given position. This
226  * corresponds to the nuclear density at the very same position.
227  *
228  * \param[in] r The radius at which to sample
229  * \return The Woods-Saxon density
230  */
231  // This function as well as nucleon_density_unnormalized could in principle
232  // be defined without the second argument
233  virtual double nucleon_density(double r, double, double) const;
234  /**
235  * Return the unnormalized Woods-Saxon distribution for the given position
236  * without deformation.
237  *
238  * \param[in] r The radius
239  * \return The unnormalized Woods-Saxon distribution
240  */
241  virtual double nucleon_density_unnormalized(double r, double, double) const;
242  /**
243  * \return the normalized ground state density for the corresponding
244  * Woods-Saxon parameter. This is done by integrating the Woods-Saxon
245  * distribution and setting the normalization such that the integral of the
246  * Woods-Saxon distribution yields the number of particles in the nucleus
247  * \f$\int\rho(r)d^3r = N_{particles}\f$.
248  *
249  */
250  virtual double calculate_saturation_density() const;
251  /**
252  * Sets the saturation density of the nucleus
253  * \see saturation_density_
254  */
255  virtual void set_saturation_density(double density) {
256  saturation_density_ = density;
257  }
258 
259  /// \ingroup exception
260  struct TestparticleConfusion : public std::length_error {
261  using std::length_error::length_error;
262  };
263 
264  private:
265  /**
266  * Diffusiveness of Woods-Saxon distribution of this nucleus in fm
267  * (for diffusiveness_ == 0, we obtain a hard sphere).
268  */
270  /// Nuclear radius of this nucleus
272  /**
273  * Single proton radius in fm
274  * \see default_nuclear_radius
275  */
276  double proton_radius_ = 1.2;
277  /// Number of testparticles per physical particle
278  size_t testparticles_ = 1;
279 
280  /// Set unpolarized spin vectors for all particles in the nucleus
282  for (auto &particle : particles_) {
283  particle.set_unpolarized_spin_vector();
284  }
285  }
286 
287  protected:
288  /// Particles associated with this nucleus.
289  std::vector<ParticleData> particles_;
290 
291  /// Saturation density of this nucleus.
292  // Needed as public member for inheritance to deformed nuclei
294 
295  /**
296  * Randomly generate Euler angles. Necessary for rotation of deformed and
297  * custom nuclei, whenever a new nucleus of this kind is initialized.
298  */
299  void random_euler_angles();
300 
301  /**
302  * The Euler angle phi of the three Euler angles used to apply rotations to
303  * the nucleus. We do not use the \c Angles class here to keep a clear
304  * distinction between spherical coordinates and angles for rotations.
305  */
306  double euler_phi_ = 0.0;
307  /// Euler angle theta
308  double euler_theta_ = 0.0;
309  /// Euler angle psi
310  double euler_psi_ = 0.0;
311  /// Whether the nucleus should be rotated randomly.
312  bool random_rotation_ = false;
313 
314  public:
315  /// For iterators over the particle list:
316  inline std::vector<ParticleData>::iterator begin() {
317  return particles_.begin();
318  }
319  /// For iterators over the particle list:
320  inline std::vector<ParticleData>::iterator end() { return particles_.end(); }
321  /// For const iterators over the particle list:
322  inline std::vector<ParticleData>::const_iterator cbegin() const {
323  return particles_.cbegin();
324  }
325  /// For const iterators over the particle list:
326  inline std::vector<ParticleData>::const_iterator cend() const {
327  return particles_.cend();
328  }
329  /**
330  * Sets the diffusiveness of the nucleus
331  * \see diffusiveness_
332  */
333  inline void set_diffusiveness(double diffuse) { diffusiveness_ = diffuse; }
334  /**
335  * \return the diffusiveness of the nucleus
336  * \see diffusiveness_
337  */
338  inline double get_diffusiveness() const { return diffusiveness_; }
339  /**
340  * \return the saturation density of the nucleus
341  * \see saturation_density_
342  */
343  inline double get_saturation_density() const { return saturation_density_; }
344  /**
345  * Default nuclear radius calculated as:
346  * \li \f$ r = r_\mathrm{proton} \ A^{1/3} \qquad \qquad \qquad \ \f$ for A <=
347  * 16 \li \f$ r = 1.12 \ A^{1/3} - 0.86 \ A^{-1/3} \qquad \f$ for A > 16
348  *
349  * \return default radius for the nucleus in fm\n
350  */
351  inline double default_nuclear_radius() {
352  int A = number_of_particles();
353 
354  if (A <= 16) {
355  // radius: rough guess for all nuclei not listed explicitly with A <= 16
356  return (proton_radius_ * std::cbrt(A));
357  } else {
358  // radius taken from \iref{Rybczynski:2013yba}
359  return (1.12 * std::pow(A, 1.0 / 3.0) - 0.86 * std::pow(A, -1.0 / 3.0));
360  }
361  }
362  /**
363  * Sets the nuclear radius
364  * \see nuclear_radius
365  */
366  inline void set_nuclear_radius(double rad) { nuclear_radius_ = rad; }
367  /**
368  * \return the nuclear radius
369  * \see nuclear_radius
370  */
371  inline double get_nuclear_radius() const { return nuclear_radius_; }
372  /**
373  * Set angles for rotation of the nucleus from config file.
374  * \param[in] orientation_config The configuration for the rotation of this
375  * nucleus (projectile or target).
376  */
377  void set_orientation_from_config(Configuration &orientation_config);
378  /**
379  * \ingroup logging
380  * Writes the state of the Nucleus object to the output stream.
381  */
382  friend std::ostream &operator<<(std::ostream &, const Nucleus &);
383 };
384 
385 /**
386  * Find out whether a configuration has a projectile or a target sub-section.
387  *
388  * \param config The configuration to be checked.
389  */
390 bool has_projectile_or_target(const Configuration &config);
391 
392 /**
393  * Find out whether a configuration is about projectile or target.
394  *
395  * \param config The configuration to be checked.
396  *
397  * \throw An \c std::logic_error if there is neither a projectile nor a target
398  * subsection or if both are present.
399  */
400 bool is_about_projectile(const Configuration &config);
401 
402 } // namespace smash
403 
404 #endif // SRC_INCLUDE_SMASH_NUCLEUS_H_
Interface to the SMASH configuration files.
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
A nucleus is a collection of particles that are initialized, before the beginning of the simulation a...
Definition: nucleus.h:27
double proton_radius_
Single proton radius in fm.
Definition: nucleus.h:276
Nucleus()=default
default constructor
double get_diffusiveness() const
Definition: nucleus.h:338
double euler_theta_
Euler angle theta.
Definition: nucleus.h:308
std::vector< ParticleData >::const_iterator cbegin() const
For const iterators over the particle list:
Definition: nucleus.h:322
virtual double nucleon_density_unnormalized(double r, double, double) const
Return the unnormalized Woods-Saxon distribution for the given position without deformation.
Definition: nucleus.cc:559
void shift(double z_offset, double x_offset, double simulation_time)
Shifts the nucleus to correct impact parameter and z displacement.
Definition: nucleus.cc:520
double get_saturation_density() const
Definition: nucleus.h:343
double woods_saxon(double x)
Woods-Saxon distribution.
Definition: nucleus.cc:285
void random_euler_angles()
Randomly generate Euler angles.
Definition: nucleus.cc:547
virtual ~Nucleus()=default
virtual void arrange_nucleons()
Sets the positions of the nucleons inside a nucleus.
Definition: nucleus.cc:289
virtual double calculate_saturation_density() const
Definition: nucleus.cc:563
double default_nuclear_radius()
Default nuclear radius calculated as:
Definition: nucleus.h:351
double diffusiveness_
Diffusiveness of Woods-Saxon distribution of this nucleus in fm (for diffusiveness_ == 0,...
Definition: nucleus.h:269
double saturation_density_
Saturation density of this nucleus.
Definition: nucleus.h:293
FourVector center() const
Calculate geometrical center of the nucleus.
Definition: nucleus.cc:538
virtual void generate_fermi_momenta()
Generates momenta according to Fermi motion for the nucleons.
Definition: nucleus.cc:415
virtual void set_parameters_automatic()
Sets the deformation parameters of the Woods-Saxon distribution according to the current mass number.
Definition: nucleus.cc:306
std::vector< ParticleData >::const_iterator cend() const
For const iterators over the particle list:
Definition: nucleus.h:326
size_t size() const
Number of numerical (=test-)particles in the nucleus:
Definition: nucleus.h:151
size_t testparticles_
Number of testparticles per physical particle.
Definition: nucleus.h:278
double get_nuclear_radius() const
Definition: nucleus.h:371
virtual double nucleon_density(double r, double, double) const
Return the Woods-Saxon probability density for the given position.
Definition: nucleus.cc:554
double euler_phi_
The Euler angle phi of the three Euler angles used to apply rotations to the nucleus.
Definition: nucleus.h:306
double nuclear_radius_
Nuclear radius of this nucleus.
Definition: nucleus.h:271
void fill_from_list(const std::map< PdgCode, int > &particle_list, int testparticles)
Adds particles from a map PDG code => Number_of_particles_with_that_PDG_code to the nucleus.
Definition: nucleus.cc:506
std::vector< ParticleData > particles_
Particles associated with this nucleus.
Definition: nucleus.h:289
double euler_psi_
Euler angle psi.
Definition: nucleus.h:310
double mass() const
Definition: nucleus.cc:84
void make_nucleus_unpolarized()
Set unpolarized spin vectors for all particles in the nucleus.
Definition: nucleus.h:281
void align_center()
Shifts the nucleus so that its center is at (0,0,0)
Definition: nucleus.h:217
void copy_particles(Particles *particles)
Copies the particles from this nucleus into the particle list.
Definition: nucleus.cc:532
virtual void set_saturation_density(double density)
Sets the saturation density of the nucleus.
Definition: nucleus.h:255
void set_nuclear_radius(double rad)
Sets the nuclear radius.
Definition: nucleus.h:366
void set_label(BelongsTo label)
Sets target / projectile labels on nucleons.
Definition: nucleus.h:207
bool random_rotation_
Whether the nucleus should be rotated randomly.
Definition: nucleus.h:312
void set_diffusiveness(double diffuse)
Sets the diffusiveness of the nucleus.
Definition: nucleus.h:333
virtual void rotate()
Rotates the nucleus using the three euler angles phi, theta and psi.
Definition: nucleus.cc:395
std::vector< ParticleData >::iterator begin()
For iterators over the particle list:
Definition: nucleus.h:316
size_t number_of_protons() const
Number of physical protons in the nucleus:
Definition: nucleus.h:178
void boost(double beta_scalar)
Boosts the nuclei into the computational frame, such that the nucleons have the appropriate momentum ...
Definition: nucleus.cc:476
virtual ThreeVector distribute_nucleon()
The distribution of return values from this function is according to a spherically symmetric Woods-Sa...
Definition: nucleus.cc:239
size_t number_of_particles() const
Number of physical particles in the nucleus:
Definition: nucleus.h:159
void set_orientation_from_config(Configuration &orientation_config)
Set angles for rotation of the nucleus from config file.
Definition: nucleus.cc:364
std::vector< ParticleData >::iterator end()
For iterators over the particle list:
Definition: nucleus.h:320
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:59
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
Collection of useful constants that are known at compile time.
SpinInteractionType
Possible spin interaction types.
@ Off
No spin interactions.
friend std::ostream & operator<<(std::ostream &, const Nucleus &)
Writes the state of the Nucleus object to the output stream.
Definition: nucleus.cc:579
constexpr int p
Proton.
Definition: action.h:24
constexpr double nuclear_density
Ground state density of symmetric nuclear matter [fm^-3].
Definition: constants.h:52
bool has_projectile_or_target(const Configuration &config)
Find out whether a configuration has a projectile or a target sub-section.
Definition: nucleus.cc:588
bool is_about_projectile(const Configuration &config)
Find out whether a configuration is about projectile or target.
Definition: nucleus.cc:594