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