Version: SMASH-1.7
grandcan_thermalizer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-
3  * SMASH Team
4  *
5  * GNU General Public License (GPLv3 or later)
6  */
7 
9 
10 #include <time.h>
11 
12 #include "smash/angles.h"
13 #include "smash/cxx14compat.h"
14 #include "smash/distributions.h"
16 #include "smash/logging.h"
17 #include "smash/particles.h"
18 #include "smash/quantumnumbers.h"
19 #include "smash/random.h"
20 
21 namespace smash {
22 
24  : Tmu0_(FourVector()),
25  nb_(0.0),
26  ns_(0.0),
27  e_(0.0),
28  p_(0.0),
29  v_(ThreeVector()),
30  T_(0.0),
31  mub_(0.0),
32  mus_(0.0) {}
33 
34 void ThermLatticeNode::add_particle(const ParticleData &part, double factor) {
35  Tmu0_ += part.momentum() * factor;
36  nb_ += static_cast<double>(part.type().baryon_number()) * factor;
37  ns_ += static_cast<double>(part.type().strangeness()) * factor;
38 }
39 
42  const int max_iter = 50;
43  v_ = ThreeVector(0.0, 0.0, 0.0);
44  double e_previous_step = 0.0;
45  const double tolerance = 5.e-4;
46  int iter;
47  for (iter = 0; iter < max_iter; iter++) {
48  e_previous_step = e_;
49  e_ = Tmu0_.x0() - Tmu0_.threevec() * v_;
50  if (std::abs(e_ - e_previous_step) < tolerance) {
51  break;
52  }
53  const double gamma_inv = std::sqrt(1.0 - v_.sqr());
54  EosTable::table_element tabulated;
55  eos.from_table(tabulated, e_, gamma_inv * nb_);
56  if (!eos.is_tabulated() || tabulated.p < 0.0) {
57  auto T_mub_mus = eos.solve_eos(e_, gamma_inv * nb_, gamma_inv * ns_);
58  T_ = T_mub_mus[0];
59  mub_ = T_mub_mus[1];
60  mus_ = T_mub_mus[2];
62  } else {
63  p_ = tabulated.p;
64  T_ = tabulated.T;
65  mub_ = tabulated.mub;
66  mus_ = tabulated.mus;
67  }
68  v_ = Tmu0_.threevec() / (Tmu0_.x0() + p_);
69  }
70  if (iter == max_iter) {
71  std::cout << "Warning from solver: max iterations exceeded."
72  << " Accuracy: " << std::abs(e_ - e_previous_step)
73  << " is less than tolerance " << tolerance << std::endl;
74  }
75 }
76 
77 void ThermLatticeNode::set_rest_frame_quantities(double T0, double mub0,
78  double mus0,
79  const ThreeVector v0) {
80  T_ = T0;
81  mub_ = mub0;
82  mus_ = mus0;
83  v_ = v0;
88 }
89 
90 std::ostream &operator<<(std::ostream &out, const ThermLatticeNode &node) {
91  return out << "T[mu,0]: " << node.Tmu0() << ", nb: " << node.nb()
92  << ", ns: " << node.ns() << ", v: " << node.v()
93  << ", e: " << node.e() << ", p: " << node.p()
94  << ", T: " << node.T() << ", mub: " << node.mub()
95  << ", mus: " << node.mus();
96 }
97 
98 GrandCanThermalizer::GrandCanThermalizer(const std::array<double, 3> lat_sizes,
99  const std::array<int, 3> n_cells,
100  const std::array<double, 3> origin,
101  bool periodicity, double e_critical,
102  double t_start, double delta_t,
104  bool BF_microcanonical)
105  : eos_typelist_(list_eos_particles()),
106  N_sorts_(eos_typelist_.size()),
107  e_crit_(e_critical),
108  t_start_(t_start),
109  period_(delta_t),
110  algorithm_(algo),
111  BF_enforce_microcanonical_(BF_microcanonical) {
113  lat_ = make_unique<RectangularLattice<ThermLatticeNode>>(
114  lat_sizes, n_cells, origin, periodicity, upd);
115  const std::array<double, 3> abc = lat_->cell_sizes();
116  cell_volume_ = abc[0] * abc[1] * abc[2];
117  cells_to_sample_.resize(50000);
118  mult_sort_.resize(N_sorts_);
119  mult_int_.resize(N_sorts_);
120 }
121 
123  const Particles &particles, const DensityParameters &dens_par,
124  bool ignore_cells_under_treshold) {
125  const DensityType dens_type = DensityType::Hadron;
127  update_lattice(lat_.get(), update, dens_type, dens_par, particles);
128  for (auto &node : *lat_) {
129  /* If energy density is definitely below e_crit -
130  no need to find T, mu, etc. So if e = T00 - T0i*vi <=
131  T00 + sum abs(T0i) < e_crit, no efforts are necessary. */
132  if (!ignore_cells_under_treshold ||
133  node.Tmu0().x0() + std::abs(node.Tmu0().x1()) +
134  std::abs(node.Tmu0().x2()) + std::abs(node.Tmu0().x3()) >=
135  e_crit_) {
136  node.compute_rest_frame_quantities(eos_);
137  } else {
138  node = ThermLatticeNode();
139  }
140  }
141 }
142 
144  return ThreeVector(random::uniform(-0.5 * lat_->cell_sizes()[0],
145  +0.5 * lat_->cell_sizes()[0]),
146  random::uniform(-0.5 * lat_->cell_sizes()[1],
147  +0.5 * lat_->cell_sizes()[1]),
148  random::uniform(-0.5 * lat_->cell_sizes()[2],
149  +0.5 * lat_->cell_sizes()[2]));
150 }
151 
153  ParticleList &plist, const FourVector required_total_momentum) {
154  const auto &log = logger<LogArea::GrandcanThermalizer>();
155 
156  // Centralize momenta
157  QuantumNumbers conserved = QuantumNumbers(plist);
158  log.info("Required 4-momentum: ", required_total_momentum);
159  log.info("Sampled 4-momentum: ", conserved.momentum());
160  const ThreeVector mom_to_add =
161  (required_total_momentum.threevec() - conserved.momentum().threevec()) /
162  plist.size();
163  log.info("Adjusting momenta by ", mom_to_add);
164  for (auto &particle : plist) {
165  particle.set_4momentum(particle.type().mass(),
166  particle.momentum().threevec() + mom_to_add);
167  }
168 
169  // Boost every particle to the common center of mass frame
170  conserved = QuantumNumbers(plist);
171  const ThreeVector beta_CM_generated = conserved.momentum().velocity();
172  const ThreeVector beta_CM_required = required_total_momentum.velocity();
173 
174  double E = 0.0;
175  double E_expected = required_total_momentum.abs();
176  for (auto &particle : plist) {
177  particle.boost_momentum(beta_CM_generated);
178  E += particle.momentum().x0();
179  }
180  // Renorm. momenta by factor (1+a) to get the right energy, binary search
181  const double tolerance = really_small;
182  double a, a_min, a_max, er;
183  const int max_iter = 100;
184  int iter = 0;
185  if (E_expected >= E) {
186  a_min = 0.0;
187  a_max = 10.0;
188  } else {
189  a_min = -1.0;
190  a_max = 0.0;
191  }
192  do {
193  a = 0.5 * (a_min + a_max);
194  E = 0.0;
195  for (const auto &particle : plist) {
196  const double p2 = particle.momentum().threevec().sqr();
197  const double E2 = particle.momentum().x0() * particle.momentum().x0();
198  E += std::sqrt(E2 + a * (a + 2.0) * p2);
199  }
200  er = E - E_expected;
201  if (er >= 0.0) {
202  a_max = a;
203  } else {
204  a_min = a;
205  }
206  log.debug("Iteration ", iter, ": a = ", a, ", Δ = ", er);
207  iter++;
208  } while (std::abs(er) > tolerance && iter < max_iter);
209 
210  log.info("Renormalizing momenta by factor 1+a, a = ", a);
211  for (auto &particle : plist) {
212  particle.set_4momentum(particle.type().mass(),
213  (1 + a) * particle.momentum().threevec());
214  particle.boost_momentum(-beta_CM_required);
215  }
216 }
217 
219  int N_to_sample) {
220  /* The array mult_sort_ contains real numbers \f$ a_i \f$. The numbers \f$
221  * n_i \f$ are saved in the mult_int_ array. Only particles of class
222  * particle_class are sampled, where particle_class is defined by the
223  * get_class function. */
224  double sum = mult_class(particle_class);
225  for (size_t i_type = 0; (i_type < N_sorts_) && (N_to_sample > 0); i_type++) {
226  if (get_class(i_type) != particle_class) {
227  continue;
228  }
229  const double p = mult_sort_[i_type] / sum;
230  mult_int_[i_type] = random::binomial(N_to_sample, p);
232  /*std::cout << eos_typelist_[i_type]->name() <<
233  ": mult_sort = " << mult_sort_[i_type] <<
234  ", sum = " << sum <<
235  ", p = " << p <<
236  ", N to sample = " << N_to_sample <<
237  ", mult_int_ = " << mult_int_[i_type] << std::endl;*/
238  sum -= mult_sort_[i_type];
239  N_to_sample -= mult_int_[i_type];
240  }
241 }
242 
244  const double time,
245  size_t type_index) {
246  N_in_cells_.clear();
247  N_total_in_cells_ = 0.0;
248  for (auto cell_index : cells_to_sample_) {
249  const ThermLatticeNode cell = (*lat_)[cell_index];
250  const double gamma = 1.0 / std::sqrt(1.0 - cell.v().sqr());
251  const double N_this_cell =
252  cell_volume_ * gamma *
253  HadronGasEos::partial_density(*eos_typelist_[type_index], cell.T(),
254  cell.mub(), cell.mus());
255  N_in_cells_.push_back(N_this_cell);
256  N_total_in_cells_ += N_this_cell;
257  }
258 
259  for (int i = 0; i < mult_int_[type_index]; i++) {
260  // Choose random cell, probability = N_in_cell/N_total
261  double r = random::uniform(0.0, N_total_in_cells_);
262  double partial_sum = 0.0;
263  int index_only_thermalized = -1;
264  while (partial_sum < r) {
265  index_only_thermalized++;
266  partial_sum += N_in_cells_[index_only_thermalized];
267  }
268  const int cell_index = cells_to_sample_[index_only_thermalized];
269  const ThermLatticeNode cell = (*lat_)[cell_index];
270  const ThreeVector cell_center = lat_->cell_center(cell_index);
271 
272  ParticleData particle(*eos_typelist_[type_index]);
273  // Note: it's pole mass for resonances!
274  const double m = eos_typelist_[type_index]->mass();
275  // Position
276  particle.set_4position(FourVector(time, cell_center + uniform_in_cell()));
277  // Momentum
278  double momentum_radial = sample_momenta_from_thermal(cell.T(), m);
279  Angles phitheta;
280  phitheta.distribute_isotropically();
281  particle.set_4momentum(m, phitheta.threevec() * momentum_radial);
282  particle.boost_momentum(-cell.v());
283  particle.set_formation_time(time);
284 
285  plist.push_back(particle);
286  }
287 }
288 
290  double time, int ntest) {
291  const auto &log = logger<LogArea::GrandcanThermalizer>();
292 
293  std::fill(mult_sort_.begin(), mult_sort_.end(), 0.0);
294  for (auto cell_index : cells_to_sample_) {
295  const ThermLatticeNode cell = (*lat_)[cell_index];
296  const double gamma = 1.0 / std::sqrt(1.0 - cell.v().sqr());
297  for (size_t i = 0; i < N_sorts_; i++) {
298  // N_i = n u^mu dsigma_mu = (isochronous hypersurface) n * V * gamma
299  mult_sort_[i] += cell_volume_ * gamma * ntest *
301  *eos_typelist_[i], cell.T(), cell.mub(), cell.mus());
302  }
303  }
304 
305  std::fill(mult_classes_.begin(), mult_classes_.end(), 0.0);
306  for (size_t i = 0; i < N_sorts_; i++) {
307  mult_classes_[static_cast<size_t>(get_class(i))] += mult_sort_[i];
308  }
309 
312  conserved_initial.baryon_number());
313 
314  while (true) {
315  sampled_list_.clear();
316  std::fill(mult_int_.begin(), mult_int_.end(), 0);
317  const auto Nbar_antibar = bessel_sampler_B.sample();
318 
319  sample_multinomial(HadronClass::Baryon, Nbar_antibar.first);
320  sample_multinomial(HadronClass::Antibaryon, Nbar_antibar.second);
321 
322  // Count strangeness of the sampled particles
323  int S_sampled = 0;
324  for (size_t i = 0; i < N_sorts_; i++) {
325  S_sampled += eos_typelist_[i]->strangeness() * mult_int_[i];
326  }
327 
328  std::pair<int, int> NS_antiS;
330  random::BesselSampler bessel_sampler_S(
333  conserved_initial.strangeness() - S_sampled);
334  NS_antiS = bessel_sampler_S.sample();
336  NS_antiS = std::make_pair(
339  if (NS_antiS.first - NS_antiS.second !=
340  conserved_initial.strangeness() - S_sampled) {
341  continue;
342  }
343  }
344 
347  // Count charge of the sampled particles
348  int ch_sampled = 0;
349  for (size_t i = 0; i < N_sorts_; i++) {
350  ch_sampled += eos_typelist_[i]->charge() * mult_int_[i];
351  }
352 
353  std::pair<int, int> NC_antiC;
355  random::BesselSampler bessel_sampler_C(
358  conserved_initial.charge() - ch_sampled);
359  NC_antiC = bessel_sampler_C.sample();
361  NC_antiC = std::make_pair(
364  if (NC_antiC.first - NC_antiC.second !=
365  conserved_initial.charge() - ch_sampled) {
366  continue;
367  }
368  }
369 
375 
376  for (size_t itype = 0; itype < N_sorts_; itype++) {
378  }
380  double e_tot;
381  const double e_init = conserved_initial.momentum().x0();
382  e_tot = 0.0;
383  for (auto &particle : sampled_list_) {
384  e_tot += particle.momentum().x0();
385  }
386  if (std::abs(e_tot - e_init) > 0.01 * e_init) {
387  log.info("Rejecting: energy ", e_tot, " too far from ", e_init);
388  continue;
389  }
390  }
391  break;
392  }
393 }
394 
396  QuantumNumbers &conserved_initial, double time) {
397  double energy = 0.0;
398  int S_plus = 0, S_minus = 0, B_plus = 0, B_minus = 0, E_plus = 0, E_minus = 0;
399  // Mode 1: sample until energy is conserved, take only strangeness < 0
400  auto condition1 = [](int, int, int) { return true; };
401  compute_N_in_cells_mode_algo(condition1);
402  while (conserved_initial.momentum().x0() > energy ||
403  S_plus < conserved_initial.strangeness()) {
404  ParticleData p = sample_in_random_cell_mode_algo(time, condition1);
405  energy += p.momentum().x0();
406  if (p.pdgcode().strangeness() > 0) {
407  sampled_list_.push_back(p);
408  S_plus += p.pdgcode().strangeness();
409  }
410  }
411 
412  // Mode 2: sample until strangeness is conserved
413  auto condition2 = [](int S, int, int) { return (S < 0); };
414  compute_N_in_cells_mode_algo(condition2);
415  while (S_plus + S_minus > conserved_initial.strangeness()) {
416  ParticleData p = sample_in_random_cell_mode_algo(time, condition2);
417  const int s_part = p.pdgcode().strangeness();
418  // Do not allow particles with S = -2 or -3 spoil the total sum
419  if (S_plus + S_minus + s_part >= conserved_initial.strangeness()) {
420  sampled_list_.push_back(p);
421  S_minus += s_part;
422  }
423  }
424 
425  // Mode 3: sample non-strange baryons
426  auto condition3 = [](int S, int, int) { return (S == 0); };
427  QuantumNumbers conserved_remaining =
428  conserved_initial - QuantumNumbers(sampled_list_);
429  energy = 0.0;
430  compute_N_in_cells_mode_algo(condition3);
431  while (conserved_remaining.momentum().x0() > energy ||
432  B_plus < conserved_remaining.baryon_number()) {
433  ParticleData p = sample_in_random_cell_mode_algo(time, condition3);
434  energy += p.momentum().x0();
435  if (p.pdgcode().baryon_number() > 0) {
436  sampled_list_.push_back(p);
437  B_plus += p.pdgcode().baryon_number();
438  }
439  }
440 
441  // Mode 4: sample non-strange anti-baryons
442  auto condition4 = [](int S, int B, int) { return (S == 0) && (B < 0); };
443  compute_N_in_cells_mode_algo(condition4);
444  while (B_plus + B_minus > conserved_remaining.baryon_number()) {
445  ParticleData p = sample_in_random_cell_mode_algo(time, condition4);
446  const int bar = p.pdgcode().baryon_number();
447  if (B_plus + B_minus + bar >= conserved_remaining.baryon_number()) {
448  sampled_list_.push_back(p);
449  B_minus += bar;
450  }
451  }
452 
453  // Mode 5: sample non_strange mesons, but take only with charge > 0
454  auto condition5 = [](int S, int B, int) { return (S == 0) && (B == 0); };
455  conserved_remaining = conserved_initial - QuantumNumbers(sampled_list_);
456  energy = 0.0;
457  compute_N_in_cells_mode_algo(condition5);
458  while (conserved_remaining.momentum().x0() > energy ||
459  E_plus < conserved_remaining.charge()) {
460  ParticleData p = sample_in_random_cell_mode_algo(time, condition5);
461  energy += p.momentum().x0();
462  if (p.pdgcode().charge() > 0) {
463  sampled_list_.push_back(p);
464  E_plus += p.pdgcode().charge();
465  }
466  }
467 
468  // Mode 6: sample non_strange mesons to conserve charge
469  auto condition6 = [](int S, int B, int C) {
470  return (S == 0) && (B == 0) && (C < 0);
471  };
472  compute_N_in_cells_mode_algo(condition6);
473  while (E_plus + E_minus > conserved_remaining.charge()) {
474  ParticleData p = sample_in_random_cell_mode_algo(time, condition6);
475  const int charge = p.pdgcode().charge();
476  if (E_plus + E_minus + charge >= conserved_remaining.charge()) {
477  sampled_list_.push_back(p);
478  E_minus += charge;
479  }
480  }
481 
482  // Mode 7: sample neutral non-strange mesons to conserve energy
483  auto condition7 = [](int S, int B, int C) {
484  return (S == 0) && (B == 0) && (C == 0);
485  };
486  conserved_remaining = conserved_initial - QuantumNumbers(sampled_list_);
487  energy = 0.0;
488  compute_N_in_cells_mode_algo(condition7);
489  while (conserved_remaining.momentum().x0() > energy) {
490  ParticleData p = sample_in_random_cell_mode_algo(time, condition7);
491  sampled_list_.push_back(p);
492  energy += p.momentum().x0();
493  }
494 }
495 
496 void GrandCanThermalizer::thermalize(const Particles &particles, double time,
497  int ntest) {
498  const auto &log = logger<LogArea::GrandcanThermalizer>();
499  log.info("Starting forced thermalization, time ", time, " fm/c");
500  to_remove_.clear();
501  sampled_list_.clear();
502  /* Remove particles from the cells with e > e_crit_,
503  * sum up their conserved quantities */
504  QuantumNumbers conserved_initial = QuantumNumbers();
505  ThermLatticeNode node;
506  for (auto &particle : particles) {
507  const bool is_on_lattice =
508  lat_->value_at(particle.position().threevec(), node);
509  if (is_on_lattice && node.e() > e_crit_) {
510  to_remove_.push_back(particle);
511  }
512  }
513  /* Do not thermalize too small number of particles: for the number
514  * of particles < 30 the algorithm tends to hang or crash too often. */
515  if (to_remove_.size() > 30) {
516  for (auto &particle : to_remove_) {
517  conserved_initial.add_values(particle);
518  }
519  } else {
520  to_remove_.clear();
521  conserved_initial = QuantumNumbers();
522  }
523  log.info("Removed ", to_remove_.size(), " particles.");
524 
525  // Exit if there is nothing to thermalize
526  if (conserved_initial == QuantumNumbers()) {
527  return;
528  }
529  // Save the indices of cells inside the volume with e > e_crit_
530  cells_to_sample_.clear();
531  const size_t lattice_total_cells = lat_->size();
532  for (size_t i = 0; i < lattice_total_cells; i++) {
533  if ((*lat_)[i].e() > e_crit_) {
534  cells_to_sample_.push_back(i);
535  }
536  }
537  log.info("Number of cells in the thermalization region = ",
538  cells_to_sample_.size(), ", its total volume [fm^3]: ",
539  cells_to_sample_.size() * cell_volume_, ", in % of lattice: ",
540  100.0 * cells_to_sample_.size() / lattice_total_cells);
541 
542  switch (algorithm_) {
545  thermalize_BF_algo(conserved_initial, time, ntest);
546  break;
548  thermalize_mode_algo(conserved_initial, time);
549  break;
550  default:
551  throw std::invalid_argument(
552  "This thermalization algorithm is"
553  " not yet implemented");
554  }
555  log.info("Sampled ", sampled_list_.size(), " particles.");
556 
557  // Adjust momenta
558  renormalize_momenta(sampled_list_, conserved_initial.momentum());
559 }
560 
562  struct to_average {
563  double T;
564  double mub;
565  double mus;
566  double nb;
567  double ns;
568  };
569  struct to_average on_lattice = {0.0, 0.0, 0.0, 0.0, 0.0};
570  struct to_average in_therm_reg = {0.0, 0.0, 0.0, 0.0, 0.0};
571  double e_sum_on_lattice = 0.0, e_sum_in_therm_reg = 0.0;
572  int node_counter = 0;
573  for (const auto &node : *lat_) {
574  const double e = node.e();
575  on_lattice.T += node.T() * e;
576  on_lattice.mub += node.mub() * e;
577  on_lattice.mus += node.mus() * e;
578  on_lattice.nb += node.nb() * e;
579  on_lattice.ns += node.ns() * e;
580  e_sum_on_lattice += e;
581  if (e >= e_crit_) {
582  in_therm_reg.T += node.T() * e;
583  in_therm_reg.mub += node.mub() * e;
584  in_therm_reg.mus += node.mus() * e;
585  in_therm_reg.nb += node.nb() * e;
586  in_therm_reg.ns += node.ns() * e;
587  e_sum_in_therm_reg += e;
588  node_counter++;
589  }
590  }
591  if (e_sum_on_lattice > really_small) {
592  on_lattice.T /= e_sum_on_lattice;
593  on_lattice.mub /= e_sum_on_lattice;
594  on_lattice.mus /= e_sum_on_lattice;
595  on_lattice.nb /= e_sum_on_lattice;
596  on_lattice.ns /= e_sum_on_lattice;
597  }
598  if (e_sum_in_therm_reg > really_small) {
599  in_therm_reg.T /= e_sum_in_therm_reg;
600  in_therm_reg.mub /= e_sum_in_therm_reg;
601  in_therm_reg.mus /= e_sum_in_therm_reg;
602  in_therm_reg.nb /= e_sum_in_therm_reg;
603  in_therm_reg.ns /= e_sum_in_therm_reg;
604  }
605 
606  std::cout << "Current time [fm/c]: " << clock.current_time() << std::endl;
607  std::cout << "Averages on the lattice - T[GeV], mub[GeV], mus[GeV], "
608  << "nb[fm^-3], ns[fm^-3]: " << on_lattice.T << " " << on_lattice.mub
609  << " " << on_lattice.mus << " " << on_lattice.nb << " "
610  << on_lattice.ns << std::endl;
611  std::cout << "Averages in therm. region - T[GeV], mub[GeV], mus[GeV], "
612  << "nb[fm^-3], ns[fm^-3]: " << in_therm_reg.T << " "
613  << in_therm_reg.mub << " " << in_therm_reg.mus << " "
614  << in_therm_reg.nb << " " << in_therm_reg.ns << std::endl;
615  std::cout << "Volume with e > e_crit [fm^3]: " << cell_volume_ * node_counter
616  << std::endl;
617 }
618 
619 } // namespace smash
int charge() const
The charge of the particle.
Definition: pdgcode.h:470
static double net_baryon_density(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute net baryon density.
Definition: hadgas_eos.cc:289
const double e_crit_
Critical energy density above which cells are thermalized.
void add_particle(const ParticleData &p, double factor)
Add particle contribution to Tmu0, nb and ns May look like unused at first glance, but it is actually used by update_lattice, where the node type of the lattice is templated.
A class to pre-calculate and store parameters relevant for density calculation.
Definition: density.h:106
PdgCode pdgcode() const
Get the pdgcode of the particle.
Definition: particledata.h:81
ThermalizationAlgorithm
Defines the algorithm used for the forced thermalization.
HadronClass get_class(size_t typelist_index) const
Defines the class of hadrons by quantum numbers.
const size_t N_sorts_
Number of different species to be sampled.
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
double p() const
Get pressure in the rest frame.
void sample_multinomial(HadronClass particle_class, int N)
The sample_multinomial function samples integer numbers n_i distributed according to the multinomial ...
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
ThermLatticeNode()
Default constructor of thermal quantities on the lattice returning thermodynamic quantities in comput...
std::array< double, 3 > solve_eos(double e, double nb, double ns, std::array< double, 3 > initial_approximation)
Compute temperature and chemical potentials given energy-, net baryon-, net strangeness density and a...
Definition: hadgas_eos.cc:507
int baryon_number() const
Definition: particletype.h:206
Class to handle the equation of state (EoS) of the hadron gas, consisting of all hadrons included int...
Definition: hadgas_eos.h:112
FourVector Tmu0_
Four-momentum flow of the cell.
GrandCanThermalizer(const std::array< double, 3 > lat_sizes, const std::array< int, 3 > n_cells, const std::array< double, 3 > origin, bool periodicity, double e_critical, double t_start, double delta_t, ThermalizationAlgorithm algo, bool BF_microcanonical)
Default constructor for the GranCanThermalizer to allocate the lattice.
void thermalize(const Particles &particles, double time, int ntest)
Main thermalize function, that chooses the algorithm to follow (BF or mode sampling).
int baryon_number() const
Definition: pdgcode.h:308
double sqr() const
Definition: threevector.h:259
double mub() const
Get the net baryon chemical potential.
double ns() const
Get net strangeness density of the cell in the computational frame.
void update_lattice(RectangularLattice< T > *lat, const LatticeUpdate update, const DensityType dens_type, const DensityParameters &par, const Particles &particles, const bool compute_gradient=false)
Updates the contents on the lattice.
Definition: density.h:400
int baryon_number() const
double abs() const
calculate the lorentz invariant absolute value
Definition: fourvector.h:454
void thermalize_BF_algo(QuantumNumbers &conserved_initial, double time, int ntest)
Samples particles according to the BF algorithm by making use of the.
void from_table(EosTable::table_element &res, double e, double nb) const
Get the element of eos table.
Definition: hadgas_eos.h:303
double e() const
Get energy density in the rest frame.
ThreeVector threevec() const
Definition: fourvector.h:319
LatticeUpdate
Enumerator option for lattice updates.
Definition: lattice.h:35
std::pair< int, int > sample()
Sample two numbers from given Poissonians with a fixed difference.
Definition: random.cc:68
virtual double current_time() const =0
double mus() const
Get the net strangeness chemical potential.
double T() const
Get the temperature.
bool is_tabulated() const
Create an EoS table or not?
Definition: hadgas_eos.h:313
void print_statistics(const Clock &clock) const
Generates standard output with information about the thermodynamic properties of the lattice...
const ThermalizationAlgorithm algorithm_
Algorithm to choose for sampling of particles obeying conservation laws.
static double partial_density(const ParticleType &ptype, double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute partial density of one hadron sort.
Definition: hadgas_eos.cc:234
double x0() const
Definition: fourvector.h:303
void set_formation_time(const double &form_time)
Set the absolute formation time.
Definition: particledata.h:232
void add_values(const ParticleData &p)
Add the quantum numbers of a single particle to the collection.
void set_rest_frame_quantities(double T0, double mub0, double mus0, const ThreeVector v0)
Set all the rest frame quantities to some values, this is useful for testing.
void update_thermalizer_lattice(const Particles &particles, const DensityParameters &par, bool ignore_cells_under_threshold=true)
Compute all the thermodynamical quantities on the lattice from particles.
ThreeVector v_
Velocity of the rest frame.
double p_
Pressure in the rest frame.
double ns_
Net strangeness density of the cell in the computational frame.
const bool BF_enforce_microcanonical_
Enforce energy conservation as part of BF sampling algorithm or not.
double mub_
Net baryon chemical potential.
ParticleList sampled_list_
Newly generated particles by thermalizer.
int strangeness() const
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
Definition: fourvector.h:323
ThreeVector v() const
Get 3-velocity of the rest frame.
void set_4momentum(const FourVector &momentum_vector)
Set the particle&#39;s 4-momentum directly.
Definition: particledata.h:145
Non-strange mesons (S = 0) with electric cherge Q < 0.
int strangeness() const
Definition: pdgcode.h:446
A container for storing conserved values.
void compute_rest_frame_quantities(HadronGasEos &eos)
Temperature, chemical potentials and rest frame velocity are calculated given the hadron gas equation...
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 (see Pratt:2014vja) APPENDIX: ALGORITHM FOR GENERATING PARTICLES math trick: for distribution, sample x by: where are uniform random numbers between [0,1) for : , where is used as rejection weight.
void compute_N_in_cells_mode_algo(F &&condition)
Computes average number of particles in each cell for the mode algorithm.
std::vector< size_t > cells_to_sample_
Cells above critical energy density.
static double pressure(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute pressure .
Definition: hadgas_eos.h:180
Mesons with strangeness S < 0.
The intention of this class is to efficiently sample from the Bessel distribution ...
Definition: random.h:377
T uniform(T min, T max)
Definition: random.h:88
double N_total_in_cells_
Total number of particles over all cells in thermalization region.
void thermalize_mode_algo(QuantumNumbers &conserved_initial, double time)
Samples particles to the according to the mode algorithm.
const ParticleType & type() const
Get the type of the particle.
Definition: particledata.h:109
int strangeness() const
Definition: particletype.h:209
Define the data structure for one element of the table.
Definition: hadgas_eos.h:55
void renormalize_momenta(ParticleList &plist, const FourVector required_total_momentum)
Changes energy and momenta of the particles in plist to match the required_total_momentum.
Clock tracks the time in the simulation.
Definition: clock.h:68
Neutral non-strange mesons.
Non-strange mesons (S = 0) with electric cherge Q > 0.
ParticleData sample_in_random_cell_mode_algo(const double time, F &&condition)
Samples one particle and the species, cell, momentum and coordinate are chosen from the corresponding...
std::vector< double > mult_sort_
Real number multiplicity for each particle type.
ParticleList to_remove_
Particles to be removed after this thermalization step.
FourVector momentum() const
Mesons with strangeness S > 0.
std::vector< double > N_in_cells_
Number of particles to be sampled in one cell.
int binomial(const int N, const T &p)
Returns a binomially distributed random number.
Definition: random.h:238
double nb_
Net baryon density of the cell in the computational frame.
constexpr int p
Proton.
void set_4position(const FourVector &pos)
Set the particle&#39;s 4-position directly.
Definition: particledata.h:190
double e_
Energy density in the rest frame.
The ThermLatticeNode class is intended to compute thermodynamical quantities in a cell given a set of...
HadronClass
Specifier to classify the different hadron species according to their quantum numbers.
std::vector< int > mult_int_
Integer multiplicity for each particle type.
double mus_
Net strangeness chemical potential.
int poisson(const T &lam)
Returns a Poisson distributed random number.
Definition: random.h:226
ThreeVector uniform_in_cell() const
void sample_in_random_cell_BF_algo(ParticleList &plist, const double time, size_t type_index)
The total number of particles of species type_index is defined by mult_int_ array that is returned by...
std::array< double, 7 > mult_classes_
The different hadron species according to the enum defined in.
double nb() const
Get net baryon density of the cell in the computational frame.
Angles provides a common interface for generating directions: i.e., two angles that should be interpr...
Definition: angles.h:59
std::unique_ptr< RectangularLattice< ThermLatticeNode > > lat_
The lattice on which the thermodynamic quantities are calculated.
void distribute_isotropically()
Populate the object with a new direction.
Definition: angles.h:188
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
DensityType
Allows to choose which kind of density to calculate.
Definition: density.h:34
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Convenience: dereferences the ActionPtr to Action.
Definition: action.h:463
double mult_class(const HadronClass cl) const
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
double cell_volume_
Volume of a single cell, necessary to convert thermal densities to actual particle numbers...
HadronGasEos eos_
Hadron gas equation of state.
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:52
void boost_momentum(const ThreeVector &v)
Apply a Lorentz-boost to only the momentum.
Definition: particledata.h:313
const ParticleTypePtrList eos_typelist_
List of particle types from which equation of state is computed.
static double net_strange_density(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute net strangeness density.
Definition: hadgas_eos.cc:307
Definition: action.h:24
const FourVector & momentum() const
Get the particle&#39;s 4-momentum.
Definition: particledata.h:139
static double energy_density(double T, double mub, double mus)
Compute energy density.
Definition: hadgas_eos.cc:244
FourVector Tmu0() const
Get Four-momentum flow of the cell.