Loading [MathJax]/extensions/tex2jax.js
 Version: SMASH-3.2
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
smash::Nucleus Class Reference

#include <nucleus.h>

A nucleus is a collection of particles that are initialized, before the beginning of the simulation and all have the same velocity.

Definition at line 27 of file nucleus.h.

Inheritance diagram for smash::Nucleus:
smash::AlphaClusteredNucleus smash::CustomNucleus smash::DeformedNucleus

Classes

struct  TestparticleConfusion
 

Public Member Functions

 Nucleus ()=default
 default constructor More...
 
 Nucleus (Configuration &config, int nTest)
 Constructor for Nucleus, that needs the configuration parameters from the inputfile and the number of testparticles. More...
 
 Nucleus (const std::map< PdgCode, int > &particle_list, int nTest)
 Constructor which directly initializes the Nucleus with particles and respective counts. More...
 
virtual ~Nucleus ()=default
 
double mass () const
 
virtual ThreeVector distribute_nucleon ()
 The distribution of return values from this function is according to a spherically symmetric Woods-Saxon distribution suitable for this nucleus. More...
 
double woods_saxon (double x)
 Woods-Saxon distribution. More...
 
virtual void arrange_nucleons ()
 Sets the positions of the nucleons inside a nucleus. More...
 
virtual void set_parameters_automatic ()
 Sets the deformation parameters of the Woods-Saxon distribution according to the current mass number. More...
 
virtual void generate_fermi_momenta ()
 Generates momenta according to Fermi motion for the nucleons. More...
 
void boost (double beta_scalar)
 Boosts the nuclei into the computational frame, such that the nucleons have the appropriate momentum and the nuclei are lorentz-contracted. More...
 
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. More...
 
void shift (double z_offset, double x_offset, double simulation_time)
 Shifts the nucleus to correct impact parameter and z displacement. More...
 
virtual void rotate ()
 Rotates the nucleus using the three euler angles phi, theta and psi. More...
 
void copy_particles (Particles *particles)
 Copies the particles from this nucleus into the particle list. More...
 
size_t size () const
 Number of numerical (=test-)particles in the nucleus: More...
 
size_t number_of_particles () const
 Number of physical particles in the nucleus: More...
 
size_t number_of_protons () const
 Number of physical protons in the nucleus: More...
 
FourVector center () const
 Calculate geometrical center of the nucleus. More...
 
void set_label (BelongsTo label)
 Sets target / projectile labels on nucleons. More...
 
void align_center ()
 Shifts the nucleus so that its center is at (0,0,0) More...
 
virtual double nucleon_density (double r, double, double) const
 Return the Woods-Saxon probability density for the given position. More...
 
virtual double nucleon_density_unnormalized (double r, double, double) const
 Return the unnormalized Woods-Saxon distribution for the given position without deformation. More...
 
virtual double calculate_saturation_density () const
 
virtual void set_saturation_density (double density)
 Sets the saturation density of the nucleus. More...
 
std::vector< ParticleData >::iterator begin ()
 For iterators over the particle list: More...
 
std::vector< ParticleData >::iterator end ()
 For iterators over the particle list: More...
 
std::vector< ParticleData >::const_iterator cbegin () const
 For const iterators over the particle list: More...
 
std::vector< ParticleData >::const_iterator cend () const
 For const iterators over the particle list: More...
 
void set_diffusiveness (double diffuse)
 Sets the diffusiveness of the nucleus. More...
 
double get_diffusiveness () const
 
double get_saturation_density () const
 
double default_nuclear_radius ()
 Default nuclear radius calculated as: More...
 
void set_nuclear_radius (double rad)
 Sets the nuclear radius. More...
 
double get_nuclear_radius () const
 
void set_orientation_from_config (Configuration &orientation_config)
 Set angles for rotation of the nucleus from config file. More...
 

Protected Member Functions

void random_euler_angles ()
 Randomly generate Euler angles. More...
 

Protected Attributes

std::vector< ParticleDataparticles_
 Particles associated with this nucleus. More...
 
double saturation_density_ = nuclear_density
 Saturation density of this nucleus. More...
 
double euler_phi_ = 0.0
 The Euler angle phi of the three Euler angles used to apply rotations to the nucleus. More...
 
double euler_theta_ = 0.0
 Euler angle theta. More...
 
double euler_psi_ = 0.0
 Euler angle psi. More...
 
bool random_rotation_ = false
 Whether the nucleus should be rotated randomly. More...
 

Private Attributes

double diffusiveness_
 Diffusiveness of Woods-Saxon distribution of this nucleus in fm (for diffusiveness_ == 0, we obtain a hard sphere). More...
 
double nuclear_radius_
 Nuclear radius of this nucleus. More...
 
double proton_radius_ = 1.2
 Single proton radius in fm. More...
 
size_t testparticles_ = 1
 Number of testparticles per physical particle. More...
 

Friends

std::ostream & operator<< (std::ostream &, const Nucleus &)
 Writes the state of the Nucleus object to the output stream. More...
 

Constructor & Destructor Documentation

◆ Nucleus() [1/3]

smash::Nucleus::Nucleus ( )
default

default constructor

◆ Nucleus() [2/3]

smash::Nucleus::Nucleus ( Configuration config,
int  nTest 
)

Constructor for Nucleus, that needs the configuration parameters from the inputfile and the number of testparticles.

Parameters
[in]configcontains the parameters from the inputfile on the numbers of particles with a certain PDG code
[in]nTestnumber of testparticles

Definition at line 34 of file nucleus.cc.

34  {
35  assert(has_projectile_or_target(config));
36  const bool is_projectile = is_about_projectile(config);
37  const auto &[particles_key, diffusiveness_key, radius_key,
38  saturation_key] = [&is_projectile]() {
39  return is_projectile
40  ? std::make_tuple(
45  : std::make_tuple(
46  InputKeys::modi_collider_target_particles,
47  InputKeys::modi_collider_target_diffusiveness,
48  InputKeys::modi_collider_target_radius,
49  InputKeys::modi_collider_target_saturationDensity);
50  }();
51  // Fill nuclei with particles.
52  std::map<PdgCode, int> part = config.take(particles_key);
53  fill_from_list(part, nTest);
54  // Look for user-defined values or take the default parameters.
55  const bool is_diffusiveness_given = config.has_value(diffusiveness_key),
56  is_radius_given = config.has_value(radius_key),
57  is_saturation_given = config.has_value(saturation_key);
58  if (is_diffusiveness_given && is_radius_given && is_saturation_given) {
59  diffusiveness_ = config.take(diffusiveness_key);
60  nuclear_radius_ = config.take(radius_key);
61  saturation_density_ = config.take(saturation_key);
62  } else if (!is_diffusiveness_given && !is_radius_given &&
63  !is_saturation_given) {
66  } else {
67  throw std::invalid_argument(
68  "Diffusiveness, Radius and Saturation_Density required to manually "
69  "configure the Woods-Saxon distribution. Only one or two were provided."
70  "\nProviding none of the above mentioned parameters automatically "
71  "configures the distribution based on the atomic number.");
72  }
73 }
virtual double calculate_saturation_density() const
Definition: nucleus.cc:559
double diffusiveness_
Diffusiveness of Woods-Saxon distribution of this nucleus in fm (for diffusiveness_ == 0,...
Definition: nucleus.h:266
double saturation_density_
Saturation density of this nucleus.
Definition: nucleus.h:283
virtual void set_parameters_automatic()
Sets the deformation parameters of the Woods-Saxon distribution according to the current mass number.
Definition: nucleus.cc:302
double nuclear_radius_
Nuclear radius of this nucleus.
Definition: nucleus.h:268
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:502
virtual void set_saturation_density(double density)
Sets the saturation density of the nucleus.
Definition: nucleus.h:252
bool has_projectile_or_target(const Configuration &config)
Find out whether a configuration has a projectile or a target sub-section.
Definition: nucleus.cc:584
bool is_about_projectile(const Configuration &config)
Find out whether a configuration is about projectile or target.
Definition: nucleus.cc:590
static const Key< double > modi_collider_projectile_saturationDensity
See user guide description for more information.
Definition: input_keys.h:3293
static const Key< double > modi_collider_projectile_radius
See user guide description for more information.
Definition: input_keys.h:3270
static const Key< double > modi_collider_projectile_diffusiveness
See user guide description for more information.
Definition: input_keys.h:3216
static const Key< std::map< PdgCode, int > > modi_collider_projectile_particles
See user guide description for more information.
Definition: input_keys.h:3244

◆ Nucleus() [3/3]

smash::Nucleus::Nucleus ( const std::map< PdgCode, int > &  particle_list,
int  nTest 
)

Constructor which directly initializes the Nucleus with particles and respective counts.

Only used for testing.

Parameters
[in]particle_liststd::map, which maps PdgCode and count of this particle.
[in]nTestNumber of test particles.

Definition at line 28 of file nucleus.cc.

28  {
29  fill_from_list(particle_list, nTest);
32 }

◆ ~Nucleus()

virtual smash::Nucleus::~Nucleus ( )
virtualdefault

Member Function Documentation

◆ mass()

double smash::Nucleus::mass ( ) const
Returns
Mass of the nucleus [GeV]. It needs to be double to allow for calculations at LHC energies.

Definition at line 75 of file nucleus.cc.

75  {
76  double total_mass = 0.;
77  for (auto i = cbegin(); i != cend(); i++) {
78  total_mass += i->momentum().abs();
79  }
80  return total_mass / (testparticles_ + 0.0);
81 }
std::vector< ParticleData >::const_iterator cbegin() const
For const iterators over the particle list:
Definition: nucleus.h:312
std::vector< ParticleData >::const_iterator cend() const
For const iterators over the particle list:
Definition: nucleus.h:316
size_t testparticles_
Number of testparticles per physical particle.
Definition: nucleus.h:275

◆ distribute_nucleon()

ThreeVector smash::Nucleus::distribute_nucleon ( )
virtual

The distribution of return values from this function is according to a spherically symmetric Woods-Saxon distribution suitable for this nucleus.

\(\frac{dN}{dr} = \frac{r^2}{\exp\left(\frac{r-r_0}{d}\right) + 1}\) where \(d\) is the diffusiveness_ parameter and \(r_0\) is nuclear_radius_.

Returns
Woods-Saxon distributed position.

Woods-Saxon-distribution

The distribution

Nucleons in nuclei are distributed according to a Woods-Saxon-distribution (see Woods:1954zz [65])

\[\frac{dN}{d^3r} = \frac{\rho_0}{\exp\left(\frac{r-r_0}{d}\right) +1},\]

where \(d\) is the diffusiveness of the nucleus. For \(d=0\), the nucleus is a hard sphere. \(\rho_0\) and \(r_0\) are, in this limit, the nuclear ground state density and nuclear radius, respectively. For small \(d\), this is still approximately true.

This distribution is obviously spherically symmetric, hence we can rewrite \(d^3r = 4\pi r^2 dr\) and obtain

\[\frac{dN}{4\pi\rho_0dr} = \frac{r^2}{\exp\left(\frac{r-r_0}{d}\right) + 1}.\]

Let us rewrite that in units of \(d\) (that's the diffusiveness) and drop any constraints on normalization (since in the end we only care about relative probabilities: we create as many nucleons as we need). Now, \(p(B)\) is the un-normalized probability to obtain a point at \(r = Bd\) (with \(R = r_0/d\)):

\[p(B) = \frac{B^2}{\exp(B-R) + 1}.\]

Splitting it up in two regimes

We shift the distribution so that \(B-R\) is 0 at \(t = 0\): \(t = B-R\):

\[p^{(1)}(t)= \frac{(t+R)^2}{\exp(t)+1}\]

and observe

\[\frac{1}{\exp(x)+1} = \frac{e^{-x}}{e^{-x}e^{x}+e^{-x}} = \frac{e^{-x}}{e^{-x}+1}.\]

The distribution function can now be split into two cases. For negative t (first case), \(-|t| = t\), and for positive t (second case), \(-|t| = -t\):

\[p^{(1)}(t) = \frac{1}{e^{-|t|}+1} \cdot (t+R)^2 \cdot \begin{cases} 1 & -R \le t < 0 \\ e^{-t} & t \ge 0 \end{cases}.\]

Apart from the first term, all that remains here can easily and exactly be generated from unrejected uniform random numbers (see below). The first term itself - \((1+e^{-|t|})^{-1}\) - is a number between 1/2 and 1.

If we now have a variable \(t\) distributed according to the remainder, \(p^{(2)}(t)\), and reject \(t\) with a probability \(p^{(rej)}(t) = 1 - p^{(survive)}(t) = 1 - (1+e^{-|t|})^{-1}\), the resulting distribution is \(p^{(combined)}(t) = p^{(2)}(t) \cdot p^{(survive)}(t)\). Hence, we need to generate \(p^{(2)}(t)\), which we can normalize to

\[\tilde{p}^{(2)}(t) = \frac{1}{1+3/R+6/R^2+6/R^3} \cdot \begin{cases} \frac{3}{R^3} (t+R)^2 & -R \le t < 0 \\ e^{-t} \left( \frac{3}{R}+\frac{6}{R^2}t+\frac{6}{R^3}\frac{1}{2}t^2 \right) & t \ge 0 \end{cases}.\]

(the tilde \(\tilde{p}\) means that this is normalized).

Four parts inside the rejection

Let \(c_1 = 1+3/R+6/R^2+6/R^3\). The above means:

\[\mbox{Choose: } \begin{cases} \tilde p^{({\rm I})} = \frac{3}{R^3}(t+R)^2 \Theta(-t) \Theta(t+R) \\ \tilde p^{({\rm II})}= e^{-t}\Theta(t) \\ \tilde p^{({\rm III})}=e^{-t}\Theta(t) t \\ \tilde p^{({\rm IV})} =e^{-t}\Theta(t) \frac{1}{2} t^2 \end{cases} \mbox{ with a probability of }\begin{cases} \frac{1}{c_1} \cdot 1 \\ \frac{1}{c_1} \cdot \frac{3}{R} \\ \frac{1}{c_1} \cdot \frac{6}{R^2} \\ \frac{1}{c_1} \cdot \frac{6}{R^3} \end{cases}.\]

Let us see how those are generated. \(\chi_i\) are uniformly distributed numbers between 0 and 1.

\[p(\chi_i) = \Theta(\chi_i)\Theta(1-\chi_i)\]

For simple distributions (only one \(\chi\) involved), we invert \(t(\chi)\), derive it w.r.t. \(t\) and normalize.

Case I: \f$p^{({\rm I})}\f$

Simply from one random number:

\[t = R\left( \sqrt[ 3 ]{\chi} - 1 \right)\]

\[\tilde p^{({\rm I})} = \frac{3}{R^3}(t+R)^2 \mbox{ for } -R \le t \le 0\]

Case II: \f$p^{({\rm II})}\f$

Again, from one only:

\[t = -\log(\chi)\]

\[p(t) = \frac{d\chi}{dt}\]

\[p^{({\rm II})} = e^{-t} \mbox{ for } t > 0\]

Case III: \f$p^{({\rm III})}\f$

Here, we need two variables:

\[t = -\log{\chi_1} -\log{\chi_2}\]

\(p^{({\rm III})}\) is now the folding of \(p^{({\rm II})}\) with itself[1]:

\[p^{({\rm III})} = \int_{-\infty}^{\infty} d\tau e^{-\tau} e^{-(t-\tau)} \Theta(\tau) \Theta(t-\tau) = t e^{-t} \mbox{ for } t > 0\]

Case IV: \f$p^{({\rm IV})}\f$

Three variables needed:

\[t = -\log{\chi_1} -\log{\chi_2} -\log{\chi_3}\]

\(p^{({\rm IV})}\) is now the folding of \(p^{({\rm II})}\) with \(p^{({\rm III})}\):

\[p^{({\rm IV})} = \int_{ - \infty}^{\infty} d\tau e^{- \tau} \left( t - \tau \right) e^{ - (t - \tau)} \Theta(\tau) \Theta(t - \tau) = \frac{1}{2} t^2 e^{ -t} \mbox{ for } t > 0\]

[1]: This is [the probability to find a \(\tau\)] times [the probability to find the value \(\tau_2 = t-\tau\) that added to \(\tau\) yields \(t\)], integrated over all possible combinations that have that property.

From the beginning

So, the algorithm needs to do all this from the end:

  • Decide which branch \(\tilde p^{({\rm I - IV})}\) to go into
  • Generate \(t\) from the distribution in the respective branches
  • Reject that number with a probability \(1-(1+\exp(-|t|))^{-1}\) (the efficiency of this should be \(\gg \frac{1}{2}\))
  • Shift and rescale \(t\) to \(r = d\cdot t + r_0\)

Reimplemented in smash::DeformedNucleus, smash::CustomNucleus, and smash::AlphaClusteredNucleus.

Definition at line 235 of file nucleus.cc.

235  {
236  // Get the solid angle of the nucleon.
237  Angles dir;
238  dir.distribute_isotropically();
239  // diffusiveness_ zero or negative? Use hard sphere.
240  if (almost_equal(diffusiveness_, 0.)) {
241  return dir.threevec() * nuclear_radius_ * std::cbrt(random::canonical());
242  }
243  if (almost_equal(nuclear_radius_, 0.)) {
244  return smash::ThreeVector();
245  }
246  double radius_scaled = nuclear_radius_ / diffusiveness_;
247  double prob_range1 = 1.0;
248  double prob_range2 = 3. / radius_scaled;
249  double prob_range3 = 2. * prob_range2 / radius_scaled;
250  double prob_range4 = 1. * prob_range3 / radius_scaled;
251  double ranges234 = prob_range2 + prob_range3 + prob_range4;
252  double t;
254  do {
255  double which_range = random::uniform(-prob_range1, ranges234);
256  if (which_range < 0.0) {
257  t = radius_scaled * (std::cbrt(random::canonical()) - 1.);
258  } else {
259  t = -std::log(random::canonical());
260  if (which_range >= prob_range2) {
261  t -= std::log(random::canonical());
262  if (which_range >= prob_range2 + prob_range3) {
263  t -= std::log(random::canonical());
264  }
265  }
266  }
274  } while (random::canonical() > 1. / (1. + std::exp(-std::abs(t))));
276  double position_scaled = t + radius_scaled;
277  double position = position_scaled * diffusiveness_;
278  return dir.threevec() * position;
279 }
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
T uniform(T min, T max)
Definition: random.h:88
T canonical()
Definition: random.h:113
bool almost_equal(const N x, const N y)
Checks two numbers for relative approximate equality.
Definition: numerics.h:44

◆ woods_saxon()

double smash::Nucleus::woods_saxon ( double  x)

Woods-Saxon distribution.

Parameters
[in]xthe position at which to evaluate the function
Returns
un-normalized Woods-saxon probability

Definition at line 281 of file nucleus.cc.

281  {
282  return r * r / (std::exp((r - nuclear_radius_) / diffusiveness_) + 1);
283 }

◆ arrange_nucleons()

void smash::Nucleus::arrange_nucleons ( )
virtual

Sets the positions of the nucleons inside a nucleus.

Reimplemented in smash::CustomNucleus.

Definition at line 285 of file nucleus.cc.

285  {
286  for (auto i = begin(); i != end(); i++) {
287  // Initialize momentum
288  i->set_4momentum(i->pole_mass(), 0.0, 0.0, 0.0);
289  /* Sampling the Woods-Saxon, get the radial
290  * position and solid angle for the nucleon. */
291  ThreeVector pos = distribute_nucleon();
292 
293  // Set the position of the nucleon.
294  i->set_4position(FourVector(0.0, pos));
295  }
296 
297  // Recenter and rotate
298  align_center();
299  rotate();
300 }
void align_center()
Shifts the nucleus so that its center is at (0,0,0)
Definition: nucleus.h:214
virtual void rotate()
Rotates the nucleus using the three euler angles phi, theta and psi.
Definition: nucleus.cc:391
std::vector< ParticleData >::iterator begin()
For iterators over the particle list:
Definition: nucleus.h:306
virtual ThreeVector distribute_nucleon()
The distribution of return values from this function is according to a spherically symmetric Woods-Sa...
Definition: nucleus.cc:235
std::vector< ParticleData >::iterator end()
For iterators over the particle list:
Definition: nucleus.h:310

◆ set_parameters_automatic()

void smash::Nucleus::set_parameters_automatic ( )
virtual

Sets the deformation parameters of the Woods-Saxon distribution according to the current mass number.

The values are taken from DeVries:1987atn [20] and Loizides:2014vua [38]. They are in agreement with MC-Glauber models such as GLISSANDO (see Rybczynski:2013yba [49]) and TGlauber MC (see Loizides:2017ack [39]).

Definition at line 302 of file nucleus.cc.

302  {
304  int Z = Nucleus::number_of_protons();
305  if (A == 1) { // single particle
306  /* In case of testparticles, an infinite reaction loop will be
307  * avoided by a small finite spread according to a single particles
308  * 'nucleus'. The proper solution will be to introduce parallel
309  * ensembles. */
311  testparticles_ == 1 ? 0. : 1. - std::exp(-(testparticles_ - 1.) * 0.1));
312  set_diffusiveness(testparticles_ == 1 ? -1. : 0.02);
313  } else if ((A == 238) && (Z == 92)) { // Uranium
314  // Default values.
315  set_diffusiveness(0.556);
316  set_nuclear_radius(6.86);
317  } else if ((A == 208) && (Z == 82)) { // Lead
318  // Default values.
319  set_diffusiveness(0.54);
320  set_nuclear_radius(6.67);
321  } else if ((A == 197) && (Z == 79)) { // Gold
322  // Default values from \iref{Schopper:2004qco}
323  set_diffusiveness(0.523);
324  set_nuclear_radius(6.55);
325  } else if ((A == 129) && (Z == 54)) { // Xenon
326  // Default values.
327  set_diffusiveness(0.59);
328  set_nuclear_radius(5.36);
329  } else if ((A == 63) && (Z == 29)) { // Copper
330  // Default values.
331  set_diffusiveness(0.5977);
332  set_nuclear_radius(4.20641);
333  } else if (A == 96) {
334  if (Z == 40) { // Zirconium
335  // Default values.
336  set_diffusiveness(0.46);
337  set_nuclear_radius(5.02);
338  } else if (Z == 44) { // Ruthenium
339  // Default values.
340  set_diffusiveness(0.46);
341  set_nuclear_radius(5.085);
342  } else {
343  // radius and diffusiveness taken from \iref{Rybczynski:2013yba}
344  set_diffusiveness(0.54);
345  set_nuclear_radius(1.12 * std::pow(A, 1.0 / 3.0) -
346  0.86 * std::pow(A, -1.0 / 3.0));
347  }
348  } else {
349  // saturation density already has reasonable default
351  if (A <= 16) {
352  set_diffusiveness(0.545);
353  } else {
354  // diffusiveness taken from \iref{Rybczynski:2013yba}
355  set_diffusiveness(0.54);
356  }
357  }
358 }
double default_nuclear_radius()
Default nuclear radius calculated as:
Definition: nucleus.h:341
void set_nuclear_radius(double rad)
Sets the nuclear radius.
Definition: nucleus.h:356
void set_diffusiveness(double diffuse)
Sets the diffusiveness of the nucleus.
Definition: nucleus.h:323
size_t number_of_protons() const
Number of physical protons in the nucleus:
Definition: nucleus.h:175
size_t number_of_particles() const
Number of physical particles in the nucleus:
Definition: nucleus.h:156

◆ generate_fermi_momenta()

void smash::Nucleus::generate_fermi_momenta ( )
virtual

Generates momenta according to Fermi motion for the nucleons.

For neutrons and protons Fermi momenta are calculated as \( p_{F} = (3 \pi^2 \rho)^{1/3}\), where \( rho \) is neutron density for neutrons and proton density for protons. The actual momenta \(p_x\), \(p_y\), \(p_z\) are uniformly distributed in the sphere with radius \(p_F\).

Reimplemented in smash::CustomNucleus.

Definition at line 411 of file nucleus.cc.

411  {
412  const int N_n = std::count_if(begin(), end(), [](const ParticleData i) {
413  return i.pdgcode() == pdg::n;
414  });
415  const int N_p = std::count_if(begin(), end(), [](const ParticleData i) {
416  return i.pdgcode() == pdg::p;
417  });
418  const FourVector nucleus_center = center();
419  const int A = N_n + N_p;
420  constexpr double pi2_3 = 3.0 * M_PI * M_PI;
421  logg[LNucleus].debug() << N_n << " neutrons, " << N_p << " protons.";
422 
423  ThreeVector ptot = ThreeVector(0.0, 0.0, 0.0);
424  for (auto i = begin(); i != end(); i++) {
425  // Only protons and neutrons get Fermi momenta
426  if (i->pdgcode() != pdg::p && i->pdgcode() != pdg::n) {
427  if (i->is_baryon()) {
428  logg[LNucleus].warn() << "No rule to calculate Fermi momentum "
429  << "for particle " << i->pdgcode();
430  }
431  continue;
432  }
433  const double r = (i->position() - nucleus_center).abs3();
434  const double theta = (i->position().threevec().get_theta());
435  const double phi = (i->position().threevec().get_phi());
436  double rho = nucleon_density(r, std::cos(theta), phi);
437 
438  if (i->pdgcode() == pdg::p) {
439  rho = rho * N_p / A;
440  }
441  if (i->pdgcode() == pdg::n) {
442  rho = rho * N_n / A;
443  }
444  const double p =
445  hbarc * std::pow(pi2_3 * rho * random::uniform(0.0, 1.0), 1.0 / 3.0);
446  Angles phitheta;
447  phitheta.distribute_isotropically();
448  const ThreeVector ith_3momentum = phitheta.threevec() * p;
449  ptot += ith_3momentum;
450  i->set_3momentum(ith_3momentum);
451  logg[LNucleus].debug() << "Particle: " << *i << ", pF[GeV]: "
452  << hbarc * std::pow(pi2_3 * rho, 1.0 / 3.0)
453  << " r[fm]: " << r
454  << " Nuclear radius[fm]: " << nuclear_radius_;
455  }
456  if (A == 0) {
457  // No Fermi momenta should be assigned
458  assert(ptot.x1() == 0.0 && ptot.x2() == 0.0 && ptot.x3() == 0.0);
459  } else {
460  /* Ensure zero total momentum of nucleus - redistribute ptot equally
461  * among protons and neutrons */
462  const ThreeVector centralizer = ptot / A;
463  for (auto i = begin(); i != end(); i++) {
464  if (i->pdgcode() == pdg::p || i->pdgcode() == pdg::n) {
465  i->set_4momentum(i->pole_mass(),
466  i->momentum().threevec() - centralizer);
467  }
468  }
469  }
470 }
FourVector center() const
Calculate geometrical center of the nucleus.
Definition: nucleus.cc:534
virtual double nucleon_density(double r, double, double) const
Return the Woods-Saxon probability density for the given position.
Definition: nucleus.cc:550
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:40
constexpr int p
Proton.
constexpr int n
Neutron.
constexpr double hbarc
GeV <-> fm conversion factor.
Definition: constants.h:25
static constexpr int LNucleus
Definition: nucleus.cc:26

◆ boost()

void smash::Nucleus::boost ( double  beta_scalar)

Boosts the nuclei into the computational frame, such that the nucleons have the appropriate momentum and the nuclei are lorentz-contracted.

Note that the usual boost cannot be applied for nuclei, since the particles would end up with different times and the binding energy needs to be taken into account.

Parameters
[in]beta_scalarvelocity in z-direction used for boost.

Definition at line 472 of file nucleus.cc.

472  {
473  double beta_squared = beta_scalar * beta_scalar;
474  double one_over_gamma = std::sqrt(1.0 - beta_squared);
475  double gamma = 1.0 / one_over_gamma;
476  /* We are talking about a /passive/ lorentz transformation here, as
477  * far as I can see, so we need to boost in the direction opposite to
478  * where we want to go
479  * ( The vector we transform - p - stays unchanged, but we go into
480  * a system that moves with -beta. Now in this frame, it seems
481  * like p has been accelerated with +beta.
482  * ) */
483  for (auto i = begin(); i != end(); i++) {
484  /* a real Lorentz Transformation would leave the particles at
485  * different times here, which we would then have to propagate back
486  * to equal times. Since we know the result, we can simply multiply
487  * the z-value with 1/gamma. */
488  FourVector this_position = i->position();
489  this_position.set_x3(this_position.x3() * one_over_gamma);
490  i->set_4position(this_position);
491  /* The simple Lorentz transformation of momenta does not take into account
492  * that nucleus has binding energy. Here we apply the method used
493  * in the JAM code \iref{Nara:1999dz}: p' = p_beam + gamma*p_F.
494  * This formula is derived under assumption that all nucleons have
495  * the same binding energy. */
496  FourVector mom_i = i->momentum();
497  i->set_4momentum(i->pole_mass(), mom_i.x1(), mom_i.x2(),
498  gamma * (beta_scalar * mom_i.x0() + mom_i.x3()));
499  }
500 }

◆ fill_from_list()

void smash::Nucleus::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.

E.g., the map [2212: 6, 2112: 7] initializes C-13 (6 protons and 7 neutrons). The particles are only created, no position or momenta are yet assigned. It is also possible to use any other PDG code, in addition to nucleons.

Parameters
[out]particle_listThe particle slots that are created.
[in]testparticlesNumber of test particles to use.

Definition at line 502 of file nucleus.cc.

503  {
504  testparticles_ = testparticles;
505  for (auto n = particle_list.cbegin(); n != particle_list.cend(); ++n) {
506  const ParticleType &current_type = ParticleType::find(n->first);
507  double current_mass = current_type.mass();
508  for (unsigned int i = 0; i < n->second * testparticles_; i++) {
509  // append particle to list and set its PDG code.
510  particles_.emplace_back(current_type);
511  particles_.back().set_4momentum(current_mass, 0.0, 0.0, 0.0);
512  }
513  }
514 }
std::vector< ParticleData > particles_
Particles associated with this nucleus.
Definition: nucleus.h:279
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
Definition: particletype.cc:99

◆ shift()

void smash::Nucleus::shift ( double  z_offset,
double  x_offset,
double  simulation_time 
)

Shifts the nucleus to correct impact parameter and z displacement.

Parameters
[in]z_offsetis the shift in z-direction
[in]x_offsetis the shift in x-direction
[in]simulation_timeset the time and formation_time of each particle to this value.

Definition at line 516 of file nucleus.cc.

516  {
517  // Move the nucleus in z and x directions, and set the time.
518  for (auto i = begin(); i != end(); i++) {
519  FourVector this_position = i->position();
520  this_position.set_x3(this_position.x3() + z_offset);
521  this_position.set_x1(this_position.x1() + x_offset);
522  this_position.set_x0(simulation_time);
523  i->set_4position(this_position);
524  i->set_formation_time(simulation_time);
525  }
526 }

◆ rotate()

void smash::Nucleus::rotate ( )
virtual

Rotates the nucleus using the three euler angles phi, theta and psi.

Definition at line 391 of file nucleus.cc.

391  {
392  if (random_rotation_) {
393  // Randomly generate euler angles for theta and phi. Psi needs not be
394  // assigned, as the nucleus objects are symmetric with respect to psi.
396  }
397  if (euler_phi_ != 0.0 || euler_theta_ != 0.0 || euler_psi_ != 0.0) {
398  for (auto &particle : *this) {
399  /* Rotate every vector by the euler angles phi, theta and psi.
400  * This means applying the matrix for a rotation of phi around the z-axis,
401  * followed by the matrix for a rotation of theta around the rotated
402  * x-axis and the matrix for a rotation of psi around the rotated z-axis.
403  */
404  ThreeVector three_pos = particle.position().threevec();
405  three_pos.rotate(euler_phi_, euler_theta_, euler_psi_);
406  particle.set_3position(three_pos);
407  }
408  }
409 }
double euler_theta_
Euler angle theta.
Definition: nucleus.h:298
void random_euler_angles()
Randomly generate Euler angles.
Definition: nucleus.cc:543
double euler_phi_
The Euler angle phi of the three Euler angles used to apply rotations to the nucleus.
Definition: nucleus.h:296
double euler_psi_
Euler angle psi.
Definition: nucleus.h:300
bool random_rotation_
Whether the nucleus should be rotated randomly.
Definition: nucleus.h:302

◆ copy_particles()

void smash::Nucleus::copy_particles ( Particles particles)

Copies the particles from this nucleus into the particle list.

Parameters
[out]particlesParticle list with all constituents of a nucleus

Definition at line 528 of file nucleus.cc.

528  {
529  for (auto p = begin(); p != end(); p++) {
530  external_particles->insert(*p);
531  }
532 }

◆ size()

size_t smash::Nucleus::size ( ) const
inline

Number of numerical (=test-)particles in the nucleus:

Definition at line 148 of file nucleus.h.

148 { return particles_.size(); }

◆ number_of_particles()

size_t smash::Nucleus::number_of_particles ( ) const
inline

Number of physical particles in the nucleus:

Exceptions
TestparticleConfusionif the number of the nucleons is not a multiple of testparticles_.

Definition at line 156 of file nucleus.h.

156  {
157  size_t nop = particles_.size() / testparticles_;
158  /* If size() is not a multiple of testparticles_, this will throw an
159  * error. */
160  if (nop * testparticles_ != particles_.size()) {
161  throw TestparticleConfusion(
162  "Number of test particles and test particles"
163  "per particle are incompatible.");
164  }
165  return nop;
166  }

◆ number_of_protons()

size_t smash::Nucleus::number_of_protons ( ) const
inline

Number of physical protons in the nucleus:

Returns
number of protons
Exceptions
Testparticleconfusionif the number of the protons is not a multiple of testparticles_.

Definition at line 175 of file nucleus.h.

175  {
176  size_t proton_counter = 0;
177  /* If n_protons is not a multiple of testparticles_, this will throw an
178  * error. */
179  for (auto &particle : particles_) {
180  if (particle.type().pdgcode() == pdg::p) {
181  proton_counter++;
182  }
183  }
184 
185  size_t n_protons = proton_counter / testparticles_;
186 
187  if (n_protons * testparticles_ != proton_counter) {
188  throw TestparticleConfusion(
189  "Number of test protons and test particles"
190  "per proton are incompatible.");
191  }
192 
193  return n_protons;
194  }

◆ center()

FourVector smash::Nucleus::center ( ) const

Calculate geometrical center of the nucleus.

Returns
\(\mathbf{r}_s = \frac{1}{N} \sum_{i=1}^N \mathbf{r}_i\) (for a nucleus with N particles that are at the positions \(\mathbf{r}_i\)).

Definition at line 534 of file nucleus.cc.

534  {
535  FourVector centerpoint(0.0, 0.0, 0.0, 0.0);
536  for (auto p = cbegin(); p != cend(); p++) {
537  centerpoint += p->position();
538  }
539  centerpoint /= size();
540  return centerpoint;
541 }
size_t size() const
Number of numerical (=test-)particles in the nucleus:
Definition: nucleus.h:148

◆ set_label()

void smash::Nucleus::set_label ( BelongsTo  label)
inline

Sets target / projectile labels on nucleons.

Definition at line 204 of file nucleus.h.

204  {
205  for (ParticleData &data : particles_) {
206  data.set_belongs_to(label);
207  }
208  }

◆ align_center()

void smash::Nucleus::align_center ( )
inline

Shifts the nucleus so that its center is at (0,0,0)

See also
center()

Definition at line 214 of file nucleus.h.

214  {
215  FourVector centerpoint = center();
216  for (auto p = particles_.begin(); p != particles_.end(); ++p) {
217  p->set_4position(p->position() - centerpoint);
218  }
219  }

◆ nucleon_density()

double smash::Nucleus::nucleon_density ( double  r,
double  ,
double   
) const
virtual

Return the Woods-Saxon probability density for the given position.

This corresponds to the nuclear density at the very same position.

Parameters
[in]rThe radius at which to sample
Returns
The Woods-Saxon density

Reimplemented in smash::DeformedNucleus.

Definition at line 550 of file nucleus.cc.

550  {
551  return get_saturation_density() /
552  (std::exp((r - nuclear_radius_) / diffusiveness_) + 1.);
553 }
double get_saturation_density() const
Definition: nucleus.h:333

◆ nucleon_density_unnormalized()

double smash::Nucleus::nucleon_density_unnormalized ( double  r,
double  ,
double   
) const
virtual

Return the unnormalized Woods-Saxon distribution for the given position without deformation.

Parameters
[in]rThe radius
Returns
The unnormalized Woods-Saxon distribution

Reimplemented in smash::DeformedNucleus.

Definition at line 555 of file nucleus.cc.

555  {
556  return 1.0 / (std::exp((r - nuclear_radius_) / diffusiveness_) + 1.);
557 }

◆ calculate_saturation_density()

double smash::Nucleus::calculate_saturation_density ( ) const
virtual
Returns
the normalized ground state density for the corresponding Woods-Saxon parameter. This is done by integrating the Woods-Saxon distribution and setting the normalization such that the integral of the Woods-Saxon distribution yields the number of particles in the nucleus \(\int\rho(r)d^3r = N_{particles}\).

Reimplemented in smash::DeformedNucleus.

Definition at line 559 of file nucleus.cc.

559  {
560  Integrator2d integrate;
561  // Transform integral from (0, oo) to (0, 1) via r = (1 - t) / t.
562  // To prevent overflow, the integration is only performed to t = 0.01 which
563  // corresponds to r = 99fm. Additionally the precision settings in the
564  // Integrator2d scheme are equally important. However both these point affect
565  // the result only after the seventh digit which should not be relevant here.
566  const auto result = integrate(0.01, 1, -1, 1, [&](double t, double cosx) {
567  const double r = (1 - t) / t;
568  return twopi * std::pow(r, 2.0) *
569  nucleon_density_unnormalized(r, cosx, 0.0) / std::pow(t, 2.0);
570  });
571  const auto rho0 = number_of_particles() / result.value();
572  return rho0;
573 }
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:555
static Integrator integrate
Definition: decaytype.cc:143
constexpr double twopi
.
Definition: constants.h:45

◆ set_saturation_density()

virtual void smash::Nucleus::set_saturation_density ( double  density)
inlinevirtual

Sets the saturation density of the nucleus.

See also
saturation_density_

Definition at line 252 of file nucleus.h.

252  {
253  saturation_density_ = density;
254  }

◆ random_euler_angles()

void smash::Nucleus::random_euler_angles ( )
protected

Randomly generate Euler angles.

Necessary for rotation of deformed and custom nuclei, whenever a new nucleus of this kind is initialized.

Definition at line 543 of file nucleus.cc.

543  {
544  // Sample euler_theta_ such that cos(theta) is uniform
545  euler_phi_ = twopi * random::uniform(0., 1.);
546  euler_theta_ = std::acos(2 * random::uniform(0., 1.) - 1);
547  euler_psi_ = twopi * random::uniform(0., 1.);
548 }

◆ begin()

std::vector<ParticleData>::iterator smash::Nucleus::begin ( )
inline

For iterators over the particle list:

Definition at line 306 of file nucleus.h.

306  {
307  return particles_.begin();
308  }

◆ end()

std::vector<ParticleData>::iterator smash::Nucleus::end ( )
inline

For iterators over the particle list:

Definition at line 310 of file nucleus.h.

310 { return particles_.end(); }

◆ cbegin()

std::vector<ParticleData>::const_iterator smash::Nucleus::cbegin ( ) const
inline

For const iterators over the particle list:

Definition at line 312 of file nucleus.h.

312  {
313  return particles_.cbegin();
314  }

◆ cend()

std::vector<ParticleData>::const_iterator smash::Nucleus::cend ( ) const
inline

For const iterators over the particle list:

Definition at line 316 of file nucleus.h.

316  {
317  return particles_.cend();
318  }

◆ set_diffusiveness()

void smash::Nucleus::set_diffusiveness ( double  diffuse)
inline

Sets the diffusiveness of the nucleus.

See also
diffusiveness_

Definition at line 323 of file nucleus.h.

323 { diffusiveness_ = diffuse; }

◆ get_diffusiveness()

double smash::Nucleus::get_diffusiveness ( ) const
inline
Returns
the diffusiveness of the nucleus
See also
diffusiveness_

Definition at line 328 of file nucleus.h.

328 { return diffusiveness_; }

◆ get_saturation_density()

double smash::Nucleus::get_saturation_density ( ) const
inline
Returns
the saturation density of the nucleus
See also
saturation_density_

Definition at line 333 of file nucleus.h.

333 { return saturation_density_; }

◆ default_nuclear_radius()

double smash::Nucleus::default_nuclear_radius ( )
inline

Default nuclear radius calculated as:

  • \( r = r_\mathrm{proton} \ A^{1/3} \qquad \qquad \qquad \ \) for A <= 16
  • \( r = 1.12 \ A^{1/3} - 0.86 \ A^{-1/3} \qquad \) for A > 16
Returns
default radius for the nucleus in fm

Definition at line 341 of file nucleus.h.

341  {
342  int A = number_of_particles();
343 
344  if (A <= 16) {
345  // radius: rough guess for all nuclei not listed explicitly with A <= 16
346  return (proton_radius_ * std::cbrt(A));
347  } else {
348  // radius taken from \iref{Rybczynski:2013yba}
349  return (1.12 * std::pow(A, 1.0 / 3.0) - 0.86 * std::pow(A, -1.0 / 3.0));
350  }
351  }
double proton_radius_
Single proton radius in fm.
Definition: nucleus.h:273

◆ set_nuclear_radius()

void smash::Nucleus::set_nuclear_radius ( double  rad)
inline

Sets the nuclear radius.

See also
nuclear_radius

Definition at line 356 of file nucleus.h.

356 { nuclear_radius_ = rad; }

◆ get_nuclear_radius()

double smash::Nucleus::get_nuclear_radius ( ) const
inline
Returns
the nuclear radius
See also
nuclear_radius

Definition at line 361 of file nucleus.h.

361 { return nuclear_radius_; }

◆ set_orientation_from_config()

void smash::Nucleus::set_orientation_from_config ( Configuration orientation_config)

Set angles for rotation of the nucleus from config file.

Parameters
[in]orientation_configThe configuration for the rotation of this nucleus (projectile or target).

Definition at line 360 of file nucleus.cc.

360  {
361  const bool is_projectile =
362  has_projectile_or_target(config) ? is_about_projectile(config) : true;
363  const auto &[rotation_key, theta_key, phi_key, psi_key] = [&is_projectile]() {
364  return is_projectile
365  ? std::make_tuple(
370  : std::make_tuple(
371  InputKeys::modi_collider_target_orientation_randRot,
372  InputKeys::modi_collider_target_orientation_theta,
373  InputKeys::modi_collider_target_orientation_phi,
374  InputKeys::modi_collider_target_orientation_psi);
375  }();
376  const bool was_any_angle_provided = config.has_value(theta_key) ||
377  config.has_value(phi_key) ||
378  config.has_value(psi_key);
379  random_rotation_ = config.take(rotation_key);
380  if (random_rotation_ && was_any_angle_provided) {
381  throw std::domain_error(
382  "The random rotation of nuclei has been requested, but some specific "
383  "rotation angle is provided, too. Please specify only either of them.");
384  } else {
385  euler_theta_ = config.take(theta_key);
386  euler_phi_ = config.take(phi_key);
387  euler_psi_ = config.take(psi_key);
388  }
389 }
static const Key< double > modi_collider_projectile_orientation_theta
See user guide description for more information.
Definition: input_keys.h:3639
static const Key< double > modi_collider_projectile_orientation_psi
See user guide description for more information.
Definition: input_keys.h:3657
static const Key< double > modi_collider_projectile_orientation_phi
See user guide description for more information.
Definition: input_keys.h:3621
static const Key< bool > modi_collider_projectile_orientation_randRot
See user guide description for more information.
Definition: input_keys.h:3676

Member Data Documentation

◆ diffusiveness_

double smash::Nucleus::diffusiveness_
private

Diffusiveness of Woods-Saxon distribution of this nucleus in fm (for diffusiveness_ == 0, we obtain a hard sphere).

Definition at line 266 of file nucleus.h.

◆ nuclear_radius_

double smash::Nucleus::nuclear_radius_
private

Nuclear radius of this nucleus.

Definition at line 268 of file nucleus.h.

◆ proton_radius_

double smash::Nucleus::proton_radius_ = 1.2
private

Single proton radius in fm.

See also
default_nuclear_radius

Definition at line 273 of file nucleus.h.

◆ testparticles_

size_t smash::Nucleus::testparticles_ = 1
private

Number of testparticles per physical particle.

Definition at line 275 of file nucleus.h.

◆ particles_

std::vector<ParticleData> smash::Nucleus::particles_
protected

Particles associated with this nucleus.

Definition at line 279 of file nucleus.h.

◆ saturation_density_

double smash::Nucleus::saturation_density_ = nuclear_density
protected

Saturation density of this nucleus.

Definition at line 283 of file nucleus.h.

◆ euler_phi_

double smash::Nucleus::euler_phi_ = 0.0
protected

The Euler angle phi of the three Euler angles used to apply rotations to the nucleus.

We do not use the Angles class here to keep a clear distinction between spherical coordinates and angles for rotations.

Definition at line 296 of file nucleus.h.

◆ euler_theta_

double smash::Nucleus::euler_theta_ = 0.0
protected

Euler angle theta.

Definition at line 298 of file nucleus.h.

◆ euler_psi_

double smash::Nucleus::euler_psi_ = 0.0
protected

Euler angle psi.

Definition at line 300 of file nucleus.h.

◆ random_rotation_

bool smash::Nucleus::random_rotation_ = false
protected

Whether the nucleus should be rotated randomly.

Definition at line 302 of file nucleus.h.


The documentation for this class was generated from the following files: