Version: SMASH-2.0
distributions.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2013-2020
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 #include "smash/distributions.h"
10 
11 #include <gsl/gsl_sf_bessel.h>
12 #include <cmath>
13 #include <cstdio>
14 #include <cstdlib>
15 
16 #include "smash/constants.h"
17 #include "smash/logging.h"
18 #include "smash/random.h"
19 
20 namespace smash {
21 static constexpr int LDistributions = LogArea::Distributions::id;
22 
23 // Relativistic Breit-Wigner distribution
24 double breit_wigner(const double m, const double pole, const double width) {
25  const double msqr = m * m;
26  const double dmsqr = msqr - pole * pole;
27  return 2. * msqr * width / (M_PI * (dmsqr * dmsqr + msqr * width * width));
28 }
29 
30 // Non-relativistic Breit-Wigner distribution
31 double breit_wigner_nonrel(double m, double pole, double width) {
32  return cauchy(m, pole, width / 2.);
33 }
34 
35 // Cauchy distribution used in non-relativistic Breit-Wigner above
36 double cauchy(double x, double pole, double width) {
37  const double dm = x - pole;
38  return width / (M_PI * (dm * dm + width * width));
39 }
40 
41 // density_integrand - Maxwell-Boltzmann distribution
42 double density_integrand(const double energy, const double momentum_sqr,
43  const double temperature) {
44  return 4.0 * M_PI * momentum_sqr * std::exp(-energy / temperature);
45 }
46 
47 double density_integrand_mass(const double energy, const double momentum_sqr,
48  const double temperature) {
49  return momentum_sqr * std::sqrt(momentum_sqr) *
50  std::exp(-energy / temperature);
51 }
52 
53 double density_integrand_1M_IC(const double energy, const double momentum_sqr,
54  const double temperature) {
55  return ((3.0 / 20.0) * (momentum_sqr / (temperature * temperature)) -
56  (6.0 / 5.0) * (energy / temperature) + (14.0 / 5.0)) *
57  std::exp(-energy / temperature) * momentum_sqr;
58 }
59 
60 double density_integrand_2M_IC(const double energy, const double momentum_sqr,
61  const double temperature) {
62  return (0.75 + 0.125 * (momentum_sqr / (temperature * temperature)) -
63  (1.0 / 30.0) * (momentum_sqr * energy /
64  (temperature * temperature * temperature)) +
65  (1.0 / 480.0) *
66  (momentum_sqr * momentum_sqr /
67  (temperature * temperature * temperature * temperature))) *
68  std::exp(-energy / temperature) * momentum_sqr;
69 }
70 
79 double juttner_distribution_func(double momentum_radial, double mass,
80  double temperature,
81  double effective_chemical_potential,
82  double statistics) {
83  const double Boltzmann_factor =
84  std::exp(-(std::sqrt(momentum_radial * momentum_radial + mass * mass) -
85  effective_chemical_potential) /
86  temperature);
87  // exp(-x) / [1 + exp(-x)] is numerically more stable than 1 / [exp(x) + 1]
88  return Boltzmann_factor / (1 + statistics * Boltzmann_factor);
89 }
90 
91 double sample_momenta_non_eq_mass(const double temperature, const double mass) {
92  logg[LDistributions].debug("Sample momenta with mass ", mass, " and T ",
93  temperature);
94 
95  /* Calculate range on momentum values to use
96  * ideally 0.0 and as large as possible but we want to be efficient! */
97  const double mom_min = 0.0;
98  const double mom_max =
99  std::sqrt(50. * 50. * temperature * temperature - mass * mass);
100  /* Calculate momentum and energy values that will give
101  * maxima of density_integrand_mass, verified by differentiation */
102  const double p_non_eq_sq =
103  0.5 * (9 * temperature * temperature +
104  temperature *
105  std::sqrt(81 * temperature * temperature + 36 * mass * mass));
106  const double e_non_eq = std::sqrt(p_non_eq_sq + mass * mass);
107  const double probability_max =
108  2. * density_integrand_mass(e_non_eq, p_non_eq_sq, temperature);
109 
110  /* sample by rejection method: (see numerical recipes for more efficient)
111  * random momenta and random probability need to be below the distribution */
112  double energy, momentum_radial, probability;
113  do {
114  // sample uniformly in momentum, DONT sample uniformly in energy!
115  momentum_radial = random::uniform(mom_min, mom_max);
116  // Energy by on-shell condition
117  energy = std::sqrt(momentum_radial * momentum_radial + mass * mass);
118  probability = density_integrand_mass(
119  energy, momentum_radial * momentum_radial, temperature);
120  } while (random::uniform(0., probability_max) > probability);
121 
122  return momentum_radial;
123 }
124 
125 double sample_momenta_1M_IC(const double temperature, const double mass) {
126  logg[LDistributions].debug("Sample momenta with mass ", mass, " and T ",
127  temperature);
128  // Maxwell-Boltzmann average E <E>=3T + m * K_1(m/T) / K_2(m/T)
129  double energy_average;
130  if (mass > 0.) {
131  // massive particles
132  const double m_over_T = mass / temperature;
133  energy_average = 3 * temperature + mass * gsl_sf_bessel_K1(m_over_T) /
134  gsl_sf_bessel_Kn(2, m_over_T);
135  } else {
136  // massless particles
137  energy_average = 3 * temperature;
138  }
139  const double momentum_average_sqr =
140  (energy_average - mass) * (energy_average + mass);
141  const double energy_min = mass;
142  const double energy_max = 50. * temperature;
143  /* 16 * the massless peak value to be well above maximum of the
144  * distribution */
145  const double probability_max =
146  16. * density_integrand_1M_IC(energy_average, momentum_average_sqr,
147  temperature);
148 
149  /* sample by rejection method: (see numerical recipes for more efficient)
150  * random momenta and random probability need to be below the distribution */
151  double momentum_radial_sqr, probability;
152  do {
153  double energy = random::uniform(energy_min, energy_max);
154  momentum_radial_sqr = (energy - mass) * (energy + mass);
155  probability =
156  density_integrand_1M_IC(energy, momentum_radial_sqr, temperature);
157  } while (random::uniform(0., probability_max) > probability);
158 
159  return std::sqrt(momentum_radial_sqr);
160 }
161 
162 double sample_momenta_2M_IC(const double temperature, const double mass) {
163  logg[LDistributions].debug("Sample momenta with mass ", mass, " and T ",
164  temperature);
165  /* Maxwell-Boltzmann average E <E>=3T + m * K_1(m/T) / K_2(m/T) */
166  double energy_average;
167  if (mass > 0.) {
168  // massive particles
169  const double m_over_T = mass / temperature;
170  energy_average = 3 * temperature + mass * gsl_sf_bessel_K1(m_over_T) /
171  gsl_sf_bessel_Kn(2, m_over_T);
172  } else {
173  // massless particles
174  energy_average = 3 * temperature;
175  }
176  const double momentum_average_sqr =
177  (energy_average - mass) * (energy_average + mass);
178  const double energy_min = mass;
179  const double energy_max = 50. * temperature;
180  /* 16 * the massless peak value to be well above maximum of the
181  * distribution */
182  const double probability_max =
183  16. * density_integrand_2M_IC(energy_average, momentum_average_sqr,
184  temperature);
185 
186  /* sample by rejection method: (see numerical recipes for more efficient)
187  * random momenta and random probability need to be below the distribution */
188  double momentum_radial_sqr, probability;
189  do {
190  double energy = random::uniform(energy_min, energy_max);
191  momentum_radial_sqr = (energy - mass) * (energy + mass);
192  probability =
193  density_integrand_2M_IC(energy, momentum_radial_sqr, temperature);
194  } while (random::uniform(0., probability_max) > probability);
195 
196  return std::sqrt(momentum_radial_sqr);
197 }
198 
199 double sample_momenta_from_thermal(const double temperature,
200  const double mass) {
201  logg[LDistributions].debug("Sample momenta with mass ", mass, " and T ",
202  temperature);
203  double momentum_radial, energy;
204  // when temperature/mass
205  if (temperature > 0.6 * mass) {
206  while (true) {
207  const double a = -std::log(random::canonical_nonzero());
208  const double b = -std::log(random::canonical_nonzero());
209  const double c = -std::log(random::canonical_nonzero());
210  momentum_radial = temperature * (a + b + c);
211  energy = std::sqrt(momentum_radial * momentum_radial + mass * mass);
212  if (random::canonical() <
213  std::exp((momentum_radial - energy) / temperature)) {
214  break;
215  }
216  }
217  } else {
218  while (true) {
219  const double r0 = random::canonical();
220  const double I1 = mass * mass;
221  const double I2 = 2.0 * mass * temperature;
222  const double I3 = 2.0 * temperature * temperature;
223  const double Itot = I1 + I2 + I3;
224  double K;
225  if (r0 < I1 / Itot) {
226  const double r1 = random::canonical_nonzero();
227  K = -temperature * std::log(r1);
228  } else if (r0 < (I1 + I2) / Itot) {
229  const double r1 = random::canonical_nonzero();
230  const double r2 = random::canonical_nonzero();
231  K = -temperature * std::log(r1 * r2);
232  } else {
233  const double r1 = random::canonical_nonzero();
234  const double r2 = random::canonical_nonzero();
235  const double r3 = random::canonical_nonzero();
236  K = -temperature * std::log(r1 * r2 * r3);
237  }
238  energy = K + mass;
239  momentum_radial = std::sqrt((energy + mass) * (energy - mass));
240  if (random::canonical() < momentum_radial / energy) {
241  break;
242  }
243  }
244  }
245  return momentum_radial;
246 }
247 
248 double sample_momenta_IC_ES(const double temperature) {
249  double momentum_radial;
250  const double a = -std::log(random::canonical_nonzero());
251  const double b = -std::log(random::canonical_nonzero());
252  const double c = -std::log(random::canonical_nonzero());
253  const double d = -std::log(random::canonical_nonzero());
254  momentum_radial = (3.0 / 4.0) * temperature * (a + b + c + d);
255 
256  return momentum_radial;
257 }
258 
259 } // namespace smash
smash::breit_wigner
double breit_wigner(double m, double pole, double width)
Returns a relativistic Breit-Wigner distribution.
Definition: distributions.cc:24
smash
Definition: action.h:24
K
static const uint32_t K[64]
The K array.
Definition: sha256.cc:70
smash::sample_momenta_1M_IC
double sample_momenta_1M_IC(const double temperature, const double mass)
Samples a momentum from the non-equilibrium distribution 1M_IC from Bazow:2016oky .
Definition: distributions.cc:125
smash::density_integrand_2M_IC
double density_integrand_2M_IC(const double energy, const double momentum_sqr, const double temperature)
density integrand - 2M_IC massless particles for expanding metric initialization, see Bazow:2016oky
Definition: distributions.cc:60
smash::sample_momenta_non_eq_mass
double sample_momenta_non_eq_mass(const double temperature, const double mass)
Samples a momentum via rejection method from the non-equilibrium distribution.
Definition: distributions.cc:91
smash::density_integrand
double density_integrand(const double energy, const double momentum_sqr, const double temperature)
Returns the Maxwell-Boltzmann distribution.
Definition: distributions.cc:42
smash::density_integrand_1M_IC
double density_integrand_1M_IC(const double energy, const double momentum_sqr, const double temperature)
density integrand - 1M_IC massless particles for expanding metric initialization, see Bazow:2016oky
Definition: distributions.cc:53
smash::logg
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
smash::random::canonical_nonzero
T canonical_nonzero()
Definition: random.h:122
random.h
smash::juttner_distribution_func
double juttner_distribution_func(double momentum_radial, double mass, double temperature, double effective_chemical_potential, double statistics)
Relativistic Juttner distribution function is just a convenience wrapper for displaying Fermi,...
Definition: distributions.cc:79
smash::cauchy
double cauchy(double x, double pole, double width)
Returns a Cauchy distribution (sometimes also called Lorentz or non-relativistic Breit-Wigner distrib...
Definition: distributions.cc:36
smash::breit_wigner_nonrel
double breit_wigner_nonrel(double m, double pole, double width)
Returns a non-relativistic Breit-Wigner distribution, which is essentially a Cauchy distribution with...
Definition: distributions.cc:31
distributions.h
smash::sample_momenta_2M_IC
double sample_momenta_2M_IC(const double temperature, const double mass)
Samples a momentum from the non-equilibrium distribution 2M_IC from Bazow:2016oky .
Definition: distributions.cc:162
smash::sample_momenta_IC_ES
double sample_momenta_IC_ES(const double temperature)
Sample momenta according to the momentum distribution in Bazow:2016oky .
Definition: distributions.cc:248
constants.h
logging.h
smash::random::uniform
T uniform(T min, T max)
Definition: random.h:88
smash::density_integrand_mass
double density_integrand_mass(const double energy, const double momentum_sqr, const double temperature)
density_integrand_mass - off_equilibrium distribution for massive particles
Definition: distributions.cc:47
smash::sample_momenta_from_thermal
double sample_momenta_from_thermal(const double temperature, const double mass)
Samples a momentum from the Maxwell-Boltzmann (thermal) distribution in a faster way,...
Definition: distributions.cc:199
smash::LDistributions
static constexpr int LDistributions
Definition: distributions.cc:21
smash::random::canonical
T canonical()
Definition: random.h:113