Version: SMASH-1.5
distributions.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2013-2018
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 
22 // Relativistic Breit-Wigner distribution
23 double breit_wigner(const double m, const double pole, const double width) {
24  const double msqr = m * m;
25  const double dmsqr = msqr - pole * pole;
26  return 2. * msqr * width / (M_PI * (dmsqr * dmsqr + msqr * width * width));
27 }
28 
29 // Non-relativistic Breit-Wigner distribution
30 double breit_wigner_nonrel(double m, double pole, double width) {
31  return cauchy(m, pole, width / 2.);
32 }
33 
34 // Cauchy distribution used in non-relativistic Breit-Wigner above
35 double cauchy(double x, double pole, double width) {
36  const double dm = x - pole;
37  return width / (M_PI * (dm * dm + width * width));
38 }
39 
40 // density_integrand - Maxwell-Boltzmann distribution
41 double density_integrand(const double energy, const double momentum_sqr,
42  const double temperature) {
43  return 4.0 * M_PI * momentum_sqr * exp(-energy / temperature);
44 }
45 
46 double density_integrand_mass(const double energy, const double momentum_sqr,
47  const double temperature) {
48  return momentum_sqr * std::sqrt(momentum_sqr) * exp(-energy / temperature);
49 }
50 
51 double density_integrand_1M_IC(const double energy, const double momentum_sqr,
52  const double temperature) {
53  return ((3.0 / 20.0) * (momentum_sqr / (temperature * temperature)) -
54  (6.0 / 5.0) * (energy / temperature) + (14.0 / 5.0)) *
55  exp(-energy / temperature) * momentum_sqr;
56 }
57 
58 double density_integrand_2M_IC(const double energy, const double momentum_sqr,
59  const double temperature) {
60  return (0.75 + 0.125 * (momentum_sqr / (temperature * temperature)) -
61  (1.0 / 30.0) * (momentum_sqr * energy /
62  (temperature * temperature * temperature)) +
63  (1.0 / 480.0) *
64  (momentum_sqr * momentum_sqr /
65  (temperature * temperature * temperature * temperature))) *
66  exp(-energy / temperature) * momentum_sqr;
67 }
68 
69 double juttner_distribution_func(const double momentum_radial,
70  const double mass, const double temperature,
71  const double baryon_chemical_potential,
72  const double lam) {
73  return 1.0 /
74  (std::exp((sqrt(momentum_radial * momentum_radial + mass * mass) -
75  baryon_chemical_potential) /
76  temperature) +
77  lam);
78 }
79 
80 double sample_momenta_non_eq_mass(const double temperature, const double mass) {
81  const auto &log = logger<LogArea::Distributions>();
82  log.debug("Sample momenta with mass ", mass, " and T ", temperature);
83 
84  /* Calculate range on momentum values to use
85  * ideally 0.0 and as large as possible but we want to be efficient! */
86  const double mom_min = 0.0;
87  const double mom_max =
88  std::sqrt(50. * 50. * temperature * temperature - mass * mass);
89  /* Calculate momentum and energy values that will give
90  * maxima of density_integrand_mass, verified by differentiation */
91  const double p_non_eq_sq =
92  0.5 * (9 * temperature * temperature +
93  temperature *
94  std::sqrt(81 * temperature * temperature + 36 * mass * mass));
95  const double e_non_eq = std::sqrt(p_non_eq_sq + mass * mass);
96  const double probability_max =
97  2. * density_integrand_mass(e_non_eq, p_non_eq_sq, temperature);
98 
99  /* sample by rejection method: (see numerical recipes for more efficient)
100  * random momenta and random probability need to be below the distribution */
101  double energy, momentum_radial, probability;
102  do {
103  // sample uniformly in momentum, DONT sample uniformly in energy!
104  momentum_radial = random::uniform(mom_min, mom_max);
105  // Energy by on-shell condition
106  energy = std::sqrt(momentum_radial * momentum_radial + mass * mass);
107  probability = density_integrand_mass(
108  energy, momentum_radial * momentum_radial, temperature);
109  } while (random::uniform(0., probability_max) > probability);
110 
111  return momentum_radial;
112 }
113 
114 double sample_momenta_1M_IC(const double temperature, const double mass) {
115  const auto &log = logger<LogArea::Distributions>();
116  log.debug("Sample momenta with mass ", mass, " and T ", temperature);
117  // Maxwell-Boltzmann average E <E>=3T + m * K_1(m/T) / K_2(m/T)
118  double energy_average;
119  if (mass > 0.) {
120  // massive particles
121  const double m_over_T = mass / temperature;
122  energy_average = 3 * temperature + mass * gsl_sf_bessel_K1(m_over_T) /
123  gsl_sf_bessel_Kn(2, m_over_T);
124  } else {
125  // massless particles
126  energy_average = 3 * temperature;
127  }
128  const double momentum_average_sqr =
129  (energy_average - mass) * (energy_average + mass);
130  const double energy_min = mass;
131  const double energy_max = 50. * temperature;
132  /* 16 * the massless peak value to be well above maximum of the
133  * distribution */
134  const double probability_max =
135  16. * density_integrand_1M_IC(energy_average, momentum_average_sqr,
136  temperature);
137 
138  /* sample by rejection method: (see numerical recipes for more efficient)
139  * random momenta and random probability need to be below the distribution */
140  double momentum_radial_sqr, probability;
141  do {
142  double energy = random::uniform(energy_min, energy_max);
143  momentum_radial_sqr = (energy - mass) * (energy + mass);
144  probability =
145  density_integrand_1M_IC(energy, momentum_radial_sqr, temperature);
146  } while (random::uniform(0., probability_max) > probability);
147 
148  return std::sqrt(momentum_radial_sqr);
149 }
150 
151 double sample_momenta_2M_IC(const double temperature, const double mass) {
152  const auto &log = logger<LogArea::Distributions>();
153  log.debug("Sample momenta with mass ", mass, " and T ", temperature);
154  /* Maxwell-Boltzmann average E <E>=3T + m * K_1(m/T) / K_2(m/T) */
155  double energy_average;
156  if (mass > 0.) {
157  // massive particles
158  const double m_over_T = mass / temperature;
159  energy_average = 3 * temperature + mass * gsl_sf_bessel_K1(m_over_T) /
160  gsl_sf_bessel_Kn(2, m_over_T);
161  } else {
162  // massless particles
163  energy_average = 3 * temperature;
164  }
165  const double momentum_average_sqr =
166  (energy_average - mass) * (energy_average + mass);
167  const double energy_min = mass;
168  const double energy_max = 50. * temperature;
169  /* 16 * the massless peak value to be well above maximum of the
170  * distribution */
171  const double probability_max =
172  16. * density_integrand_2M_IC(energy_average, momentum_average_sqr,
173  temperature);
174 
175  /* sample by rejection method: (see numerical recipes for more efficient)
176  * random momenta and random probability need to be below the distribution */
177  double momentum_radial_sqr, probability;
178  do {
179  double energy = random::uniform(energy_min, energy_max);
180  momentum_radial_sqr = (energy - mass) * (energy + mass);
181  probability =
182  density_integrand_2M_IC(energy, momentum_radial_sqr, temperature);
183  } while (random::uniform(0., probability_max) > probability);
184 
185  return std::sqrt(momentum_radial_sqr);
186 }
187 
188 /* A much faster sampler for thermal distribution from Scott
189  * (see \iref{Pratt:2014vja}) APPENDIX: ALGORITHM FOR GENERATING PARTICLES
190  * math trick: for \f$ x^{n-1}e^{-x} \f$ distribution, sample x by:
191  * \f$ x = -ln(r_1 r_2 r_3 ... r_n) \f$
192  * where \f$ r_i \f$ are uniform random numbers between [0,1)
193  * for \f$ T/m > 0.6 \f$: \f$ p^2 e^{-E/T} = p^2 e^{-p/T} * e^{(p-E)/T} \f$,
194  * where \f$ e^{(p-E)/T}\f$ is used as rejection weight.
195  * Since \f$T/m > 0.6 \f$, \f$ e^{(p-E)/T}\f$ is close to 1.
196  * for \f$ T/m < 0.6 \f$, there are many rejections
197  * another manipulation is used:
198  * \f$ p^2 e^{-E/T} dp = dE \frac{E}{p} p^2 e^{-E/T} \f$
199  * \f$ = dK \frac{p}{E} (K+m)^2 e^{-K/T} e^{-m/T} \f$
200  * \f$ = dK (K^2 + 2mK + m^2) e^{-K/T} \frac{p}{E}\f$
201  * where \frac{p}{E} is used as rejection weight.
202  * return: themal momenta */
203 double sample_momenta_from_thermal(const double temperature,
204  const double mass) {
205  const auto &log = logger<LogArea::Distributions>();
206  log.debug("Sample momenta with mass ", mass, " and T ", temperature);
207  double momentum_radial, energy;
208  // when temperature/mass
209  if (temperature > 0.6 * mass) {
210  while (true) {
211  const double a = -std::log(random::canonical_nonzero());
212  const double b = -std::log(random::canonical_nonzero());
213  const double c = -std::log(random::canonical_nonzero());
214  momentum_radial = temperature * (a + b + c);
215  energy = sqrt(momentum_radial * momentum_radial + mass * mass);
216  if (random::canonical() < exp((momentum_radial - energy) / temperature)) {
217  break;
218  }
219  }
220  } else {
221  while (true) {
222  const double r0 = random::canonical();
223  const double I1 = mass * mass;
224  const double I2 = 2.0 * mass * temperature;
225  const double I3 = 2.0 * temperature * temperature;
226  const double Itot = I1 + I2 + I3;
227  double K;
228  if (r0 < I1 / Itot) {
229  const double r1 = random::canonical_nonzero();
230  K = -temperature * std::log(r1);
231  } else if (r0 < (I1 + I2) / Itot) {
232  const double r1 = random::canonical_nonzero();
233  const double r2 = random::canonical_nonzero();
234  K = -temperature * std::log(r1 * r2);
235  } else {
236  const double r1 = random::canonical_nonzero();
237  const double r2 = random::canonical_nonzero();
238  const double r3 = random::canonical_nonzero();
239  K = -temperature * std::log(r1 * r2 * r3);
240  }
241  energy = K + mass;
242  momentum_radial = sqrt((energy + mass) * (energy - mass));
243  if (random::canonical() < momentum_radial / energy) {
244  break;
245  }
246  }
247  }
248  return momentum_radial;
249 }
250 
251 double sample_momenta_IC_ES(const double temperature) {
252  double momentum_radial;
253  const double a = -std::log(random::canonical_nonzero());
254  const double b = -std::log(random::canonical_nonzero());
255  const double c = -std::log(random::canonical_nonzero());
256  const double d = -std::log(random::canonical_nonzero());
257  momentum_radial = (3.0 / 4.0) * temperature * (a + b + c + d);
258 
259  return momentum_radial;
260 }
261 
262 } // namespace smash
double juttner_distribution_func(const double momentum_radial, const double mass, const double temperature, const double baryon_chemical_potential, const double lam)
Relativistic Juttner distribution function.
double breit_wigner_nonrel(double m, double pole, double width)
Returns a non-relativistic Breit-Wigner distribution, which is essentially a Cauchy distribution with...
double sample_momenta_2M_IC(const double temperature, const double mass)
Samples a momentum from the non-equilibrium distribution 2M_IC from Bazow:2016oky ...
Collection of useful constants that are known at compile time.
double cauchy(double x, double pole, double width)
Returns a Cauchy distribution (sometimes also called Lorentz or non-relativistic Breit-Wigner distrib...
T canonical()
Definition: random.h:110
double sample_momenta_IC_ES(const double temperature)
Sample momenta according to the momentum distribution in Bazow:2016oky
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 ...
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 ...
double breit_wigner(double m, double pole, double width)
Returns a relativistic Breit-Wigner distribution.
double sample_momenta_from_thermal(const double temperature, const double mass)
Samples a momentum from the Maxwell-Boltzmann (thermal) distribution in a faster way, given by Scott Pratt.
double density_integrand(const double energy, const double momentum_sqr, const double temperature)
Returns the Maxwell-Boltzmann distribution.
T canonical_nonzero()
Definition: random.h:119
T uniform(T min, T max)
Definition: random.h:85
double sample_momenta_non_eq_mass(const double temperature, const double mass)
Samples a momentum via rejection method from the non-equilibrium distribution .
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: action.h:24
double density_integrand_mass(const double energy, const double momentum_sqr, const double temperature)
density_integrand_mass - off_equilibrium distribution for massive particles