Version: SMASH-3.1
deformednucleus.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2022
3  * SMASH Team
4  *
5  * GNU General Public License (GPLv3 or later)
6  */
8 
9 #include <cmath>
10 #include <map>
11 #include <stdexcept>
12 
13 #include "smash/configuration.h"
14 #include "smash/constants.h"
15 #include "smash/fourvector.h"
16 #include "smash/random.h"
17 #include "smash/threevector.h"
18 
19 namespace smash {
20 
21 DeformedNucleus::DeformedNucleus(const std::map<PdgCode, int> &particle_list,
22  int nTest)
23  : Nucleus(particle_list, nTest) {}
24 
26  bool auto_deformation)
27  : Nucleus(config, nTest) {
28  if (auto_deformation) {
31  } else {
33  }
34  if (config.has_value({"Deformed", "Orientation"})) {
35  Configuration sub_conf =
36  config.extract_sub_configuration({"Deformed", "Orientation"});
38  }
39 }
40 
42  double a_radius;
43  Angles a_direction;
44  // Set a sensible maximum bound for radial sampling.
45  double radius_max =
48 
49  // Sample the distribution.
50  do {
51  a_direction.distribute_isotropically();
52  // sample r**2 dr
53  a_radius = radius_max * std::cbrt(random::canonical());
54  } while (random::canonical() > nucleon_density(a_radius,
55  a_direction.costheta(),
56  a_direction.phi()) /
58 
59  // Update (x, y, z) positions.
60  return a_direction.threevec() * a_radius;
61 }
62 
64  // Set the deformation parameters
65  // reference for U, Pb, Au, Cu: \iref{Moller:1993ed}
66  // reference for Zr and Ru: \iref{Schenke:2019ruo}
67  // reference for Xe: \iref{Moller:2015fba}
68  bool listed = 0;
69  const std::map<int, std::string> A_map = {{238, "Uranium"},
70  {208, "Lead"},
71  {197, "Gold"},
72  {63, "Copper"},
73  {129, "Xenon"}};
74  const std::map<std::string, std::string> Z_map = {{"Uranium", "92"},
75  {"Lead", "82"},
76  {"Gold", "79"},
77  {"Copper", "29"},
78  {"Xenon", "54"}};
81  switch (A) {
82  case 238: // Uranium
83  if (Z == 92) {
84  set_beta_2(0.28);
85  set_beta_4(0.093);
86  } else {
87  listed = true;
88  }
89  break;
90  case 208: // Lead
91  if (Z == 82) {
92  set_beta_2(0.0);
93  set_beta_4(0.0);
94  } else {
95  listed = true;
96  }
97  break;
98  case 197: // Gold
99  if (Z == 79) {
100  set_beta_2(-0.131);
101  set_beta_4(-0.031);
102  } else {
103  listed = true;
104  }
105  break;
106  case 129: // Xenon
107  if (Z == 54) {
108  set_beta_2(0.162);
109  set_beta_4(-0.003);
110  } else {
111  listed = true;
112  }
113  break;
114  case 63: // Copper
115  if (Z == 29) {
116  set_beta_2(0.162);
117  set_beta_4(-0.006);
118  } else {
119  listed = true;
120  }
121  break;
122  case 96:
123  if (Z == 40) { // Zirconium
124  set_beta_2(0.0);
125  set_beta_4(0.0);
126  } else if (Z == 44) { // Ruthenium
127  set_beta_2(0.158);
128  set_beta_4(0.0);
129  } else {
130  throw std::domain_error(
131  "Number of protons for nuclei with mass number A = 96 does not "
132  "match that of Zirconium or Ruthenium. The deformation parameters "
133  "for additional isobars are currently not implemented."
134  " Please specify at least \"Beta_2\" and \"Beta_4\" "
135  "manually and set \"Automatic: False.\" ");
136  }
137  break;
138  default:
139  throw std::domain_error(
140  "Mass number not listed for automatically setting deformation "
141  "parameters. Please specify at least \"Beta_2\" and \"Beta_4\" "
142  "manually and set \"Automatic: False.\" ");
143  }
144  if (listed) {
145  throw std::domain_error("Mass number is listed under " + A_map.at(A) +
146  " but the proton "
147  "number of " +
148  std::to_string(Z) +
149  " does not match "
150  "its " +
151  Z_map.at(A_map.at(A)) +
152  " protons."
153  "Please specify at least \"Beta_2\" and \"Beta_4\" "
154  "manually and set \"Automatic: False.\" ");
155  }
156 }
157 
159  Configuration &config) {
160  // Deformation parameters.
161  if (config.has_value({"Deformed", "Beta_2"})) {
162  set_beta_2(static_cast<double>(config.take({"Deformed", "Beta_2"})));
163  }
164  if (config.has_value({"Deformed", "Gamma"})) {
165  set_gamma(static_cast<double>(config.take({"Deformed", "Gamma"})));
166  }
167  if (config.has_value({"Deformed", "Beta_3"})) {
168  set_beta_3(static_cast<double>(config.take({"Deformed", "Beta_3"})));
169  }
170  if (config.has_value({"Deformed", "Beta_4"})) {
171  set_beta_4(static_cast<double>(config.take({"Deformed", "Beta_4"})));
172  }
173 }
174 
176  Configuration &orientation_config) {
177  // Read in orientation if provided, otherwise, the defaults are
178  // theta = pi/2, phi = 0, as declared in the angles class
179 
180  if (orientation_config.has_value({"Theta"})) {
181  if (orientation_config.has_value({"Random_Rotation"}) &&
182  orientation_config.take({"Random_Rotation"})) {
183  throw std::domain_error(
184  "Random rotation of nuclei is activated although"
185  " theta is provided. Please specify only either of them. ");
186  } else {
187  set_polar_angle(static_cast<double>(orientation_config.take({"Theta"})));
188  }
189  }
190 
191  if (orientation_config.has_value({"Phi"})) {
192  if (orientation_config.has_value({"Random_Rotation"}) &&
193  orientation_config.take({"Random_Rotation"})) {
194  throw std::domain_error(
195  "Random rotation of nuclei is activated although"
196  " phi is provided. Please specify only either of them. ");
197  } else {
199  static_cast<double>(orientation_config.take({"Phi"})));
200  }
201  }
202 
203  if (orientation_config.has_value({"Psi"})) {
204  if (orientation_config.has_value({"Random_Rotation"}) &&
205  orientation_config.take({"Random_Rotation"})) {
206  throw std::domain_error(
207  "Random rotation of nuclei is activated although"
208  " psi is provided. Please specify only either of them. ");
209  } else {
210  set_angle_psi(static_cast<double>(orientation_config.take({"Psi"})));
211  }
212  }
213 
214  if (orientation_config.take({"Random_Rotation"}, false)) {
215  random_rotation_ = true;
216  }
217 }
218 
220  if (random_rotation_) {
221  // Randomly generate euler angles for theta and phi. Psi needs not be
222  // assigned, as the nucleus objects are symmetric with respect to psi.
227  }
228  for (auto &particle : *this) {
229  /* Rotate every vector by the nuclear azimuth phi, polar angle
230  * theta and psi (the Euler angles). This means applying the matrix for a
231  * rotation of phi about z, followed by the matrix for a rotation
232  * theta about the rotated x axis. If the triaxiality coefficient is not
233  * zero, one has to include the third rotation around psi as the nucleus is
234  * not symmetric under rotation of any axis.*/
235  ThreeVector three_pos = particle.position().threevec();
238  particle.set_3position(three_pos);
239  }
240 }
241 
242 double y_l_m(int l, int m, double cosx, double phi) {
243  if (l == 2 && m == 0) {
244  return (1. / 4) * std::sqrt(5 / M_PI) * (3. * (cosx * cosx) - 1);
245  } else if (l == 2 && m == 2) {
246  double sinx2 = 1. - cosx * cosx;
247  return (1. / 4) * std::sqrt(15 / (2. * M_PI)) * sinx2 * std::cos(2. * phi);
248  } else if (l == 3 && m == 0) {
249  return (1. / 4) * std::sqrt(7 / M_PI) *
250  (5. * cosx * (cosx * cosx) - 3. * cosx);
251  } else if (l == 4 && m == 0) {
252  return (3. / 16) * std::sqrt(1 / M_PI) *
253  (35. * (cosx * cosx) * (cosx * cosx) - 30. * (cosx * cosx) + 3);
254  } else {
255  throw std::domain_error(
256  "Not a valid angular momentum quantum number in y_l_m.");
257  }
258 }
259 
260 double DeformedNucleus::nucleon_density(double r, double cosx,
261  double phi) const {
263  (1 + std::exp((r - Nucleus::get_nuclear_radius() *
264  (1 +
265  beta2_ * (std::cos(gamma_) *
266  y_l_m(2, 0, cosx, phi) +
267  std::sqrt(2) * std::sin(gamma_) *
268  y_l_m(2, 2, cosx, phi)) +
269  beta3_ * y_l_m(3, 0, cosx, phi) +
270  beta4_ * y_l_m(4, 0, cosx, phi))) /
272 }
273 
275  double phi) const {
276  return 1.0 /
277  (1 + std::exp((r - Nucleus::get_nuclear_radius() *
278  (1 +
279  beta2_ * (std::cos(gamma_) *
280  y_l_m(2, 0, cosx, phi) +
281  std::sqrt(2) * std::sin(gamma_) *
282  y_l_m(2, 2, cosx, phi)) +
283  beta3_ * y_l_m(3, 0, cosx, phi) +
284  beta4_ * y_l_m(4, 0, cosx, phi))) /
286 }
287 
289  double cosx) const {
291  // Perform the phi integration. This is needed if the triaxiality coefficient
292  // gamma is included, which includes a dependency around the phi axis.
293  // Unfortunately the Integrator class does not support 3d integration which is
294  // why this intermediate integral is needed. It has been checked that the
295  // integral factorizes.
296  const auto result = integrate(0.0, 2.0 * M_PI, [&](double phi) {
297  return nucleon_density_unnormalized(r, cosx, phi);
298  });
299  return result.value();
300 }
301 
304  // Transform integral from (0, oo) to (0, 1) via r = (1 - t) / t.
305  // To prevent overflow, the integration is only performed to t = 0.01 which
306  // corresponds to r = 99fm. Additionally the precision settings in the
307  // Integrator2d scheme are equally important. However both these point affect
308  // the result only after the seventh digit which should not be relevant here.
309  if (gamma_ == 0.0) {
310  const auto result = integrate(0.01, 1, -1, 1, [&](double t, double cosx) {
311  const double r = (1 - t) / t;
312  return twopi * std::pow(r, 2.0) *
313  nucleon_density_unnormalized(r, cosx, 0.0) / std::pow(t, 2.0);
314  });
315  const auto rho0 = number_of_particles() / result.value();
316  return rho0;
317  } else {
318  const auto result = integrate(0.01, 1, -1, 1, [&](double t, double cosx) {
319  const double r = (1 - t) / t;
320  return std::pow(r, 2.0) * integrant_nucleon_density_phi(r, cosx) /
321  std::pow(t, 2.0);
322  });
323  const auto rho0 = number_of_particles() / result.value();
324  return rho0;
325  }
326 }
327 
328 } // namespace smash
Angles provides a common interface for generating directions: i.e., two angles that should be interpr...
Definition: angles.h:59
ThreeVector threevec() const
Definition: angles.h:288
void distribute_isotropically()
Populate the object with a new direction.
Definition: angles.h:199
double theta() const
Definition: angles.h:292
double phi() const
Definition: angles.h:279
double psi() const
Definition: angles.h:280
double costheta() const
Definition: angles.h:278
Interface to the SMASH configuration files.
bool has_value(std::initializer_list< const char * > keys) const
Return whether there is a non-empty value behind the requested keys.
Configuration extract_sub_configuration(std::initializer_list< const char * > keys, Configuration::GetEmpty empty_if_not_existing=Configuration::GetEmpty::No)
Create a new configuration from a then-removed section of the present object.
Value take(std::initializer_list< const char * > keys)
The default interface for SMASH to read configuration values.
void set_orientation_from_config(Configuration &orientation_config)
Set angles for orientation of nucleus from config file.
void set_gamma(double ga)
Set the triaxiality coefficient gamma for Y_2_0 and Y_2_2.
bool random_rotation_
Whether the nuclei should be rotated randomly.
void set_beta_3(double b3)
Set deformation coefficient for Y_3_0.
ThreeVector distribute_nucleon() override
Deformed Woods-Saxon sampling routine.
double nucleon_density_unnormalized(double r, double cosx, double phi) const override
Return the unnormalized deformed Woods-Saxon distribution for the given position.
void set_angle_psi(double psi)
Set the angle psi.
double integrant_nucleon_density_phi(double r, double cosx) const
Return the integral over the azimuthal angle phi.
void set_polar_angle(double theta)
Set the nucleus polar angle.
void rotate() override
Rotates the nucleus according to members nucleus_polar_angle_ and nucleus_azimuthal_angle_ and update...
double beta4_
Deformation parameter for angular momentum l=4.
double gamma_
Triaxiality parameter for angular momentum l=2.
void set_deformation_parameters_from_config(Configuration &config)
Set parameters for spherical deformation of the nucleus from the values specified in the configuratio...
void set_beta_2(double b2)
Set deformation coefficient for Y_2_0.
Angles nuclear_orientation_
Nucleus orientation (initial profile in xz plane) in terms of a pair of angles (theta,...
double beta3_
Deformation parameter for angular momentum l=3.
double nucleon_density(double r, double cosx, double phi) const override
Return the deformed Woods-Saxon probability density for the given position.
DeformedNucleus(const std::map< PdgCode, int > &particle_list, int nTest)
Constructor for DeformedNucles which takes a particle list and the number of testparticles.
void set_beta_4(double b4)
Set deformation coefficient for Y_4_0.
void set_azimuthal_angle(double phi)
Set the nucleus azimuthal angle.
double beta2_
Deformation parameter for angular momentum l=2.
double calculate_saturation_density() const override
void set_deformation_parameters_automatic()
Sets the deformation parameters of the radius according to the current mass number.
A C++ interface for numerical integration in two dimensions with the Cuba Cuhre integration function.
Definition: integrate.h:219
A C++ interface for numerical integration in one dimension with the GSL CQUAD integration functions.
Definition: integrate.h:106
A nucleus is a collection of particles that are initialized, before the beginning of the simulation a...
Definition: nucleus.h:27
double get_diffusiveness() const
Definition: nucleus.h:331
double euler_theta_
Euler angel theta.
Definition: nucleus.h:303
double get_saturation_density() const
Definition: nucleus.h:336
void random_euler_angles()
Randomly generate Euler angles.
Definition: nucleus.cc:480
double get_nuclear_radius() const
Definition: nucleus.h:364
double euler_phi_
Euler angel phi.
Definition: nucleus.h:301
double euler_psi_
Euler angel psi.
Definition: nucleus.h:305
virtual void set_saturation_density(double density)
Sets the saturation density of the nucleus.
Definition: nucleus.h:261
size_t number_of_protons() const
Number of physical protons in the nucleus:
Definition: nucleus.h:184
size_t number_of_particles() const
Number of physical particles in the nucleus:
Definition: nucleus.h:165
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
void rotate(double phi, double theta, double psi)
Rotate vector by the given Euler angles phi, theta, psi.
Definition: threevector.h:283
Collection of useful constants that are known at compile time.
T canonical()
Definition: random.h:113
Definition: action.h:24
static Integrator integrate
Definition: decaytype.cc:143
double y_l_m(int l, int m, double cosx, double phi)
Spherical harmonics Y_2_0, Y_2_2, Y_3_0 and Y_4_0.
constexpr double twopi
.
Definition: constants.h:45