42   const int max_iter = 50;
    44   double e_previous_step = 0.0;
    45   const double tolerance = 5.e-4;
    47   for (iter = 0; iter < max_iter; iter++) {
    50     if (std::abs(
e_ - e_previous_step) < tolerance) {
    53     const double gamma_inv = std::sqrt(1.0 - 
v_.
sqr());
    57       auto T_mub_mus = eos.
solve_eos(
e_, gamma_inv * nb_, gamma_inv * 
ns_);
    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;
    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();
    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()),
   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();
   124     bool ignore_cells_under_treshold) {
   128   for (
auto &node : *
lat_) {
   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()) >=
   136       node.compute_rest_frame_quantities(
eos_);
   145                                      +0.5 * 
lat_->cell_sizes()[0]),
   147                                      +0.5 * 
lat_->cell_sizes()[1]),
   149                                      +0.5 * 
lat_->cell_sizes()[2]));
   153     ParticleList &plist, 
const FourVector required_total_momentum) {
   154   const auto &log = logger<LogArea::GrandcanThermalizer>();
   158   log.info(
"Required 4-momentum: ", required_total_momentum);
   159   log.info(
"Sampled 4-momentum: ", conserved.momentum());
   161       (required_total_momentum.
threevec() - conserved.momentum().threevec()) /
   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);
   171   const ThreeVector beta_CM_generated = conserved.momentum().velocity();
   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();
   182   double a, a_min, a_max, er;
   183   const int max_iter = 100;
   185   if (E_expected >= E) {
   193     a = 0.5 * (a_min + a_max);
   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);
   206     log.debug(
"Iteration ", iter, 
": a = ", a, 
", Δ = ", er);
   208   } 
while (std::abs(er) > tolerance && iter < max_iter);
   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);
   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) {
   250     const double gamma = 1.0 / std::sqrt(1.0 - cell.
v().
sqr());
   251     const double N_this_cell =
   259   for (
int i = 0; i < 
mult_int_[type_index]; i++) {
   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];
   268     const int cell_index = cells_to_sample_[index_only_thermalized];
   281     particle.
set_4momentum(m, phitheta.threevec() * momentum_radial);
   285     plist.push_back(particle);
   290                                              double time, 
int ntest) {
   291   const auto &log = logger<LogArea::GrandcanThermalizer>();
   296     const double gamma = 1.0 / std::sqrt(1.0 - cell.
v().
sqr());
   297     for (
size_t i = 0; i < 
N_sorts_; i++) {
   306   for (
size_t i = 0; i < 
N_sorts_; i++) {
   317     const auto Nbar_antibar = bessel_sampler_B.sample();
   324     for (
size_t i = 0; i < 
N_sorts_; i++) {
   328     std::pair<int, int> NS_antiS;
   334       NS_antiS = bessel_sampler_S.
sample();
   336       NS_antiS = std::make_pair(
   339       if (NS_antiS.first - NS_antiS.second !=
   349     for (
size_t i = 0; i < 
N_sorts_; i++) {
   353     std::pair<int, int> NC_antiC;
   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) {
   376     for (
size_t itype = 0; itype < 
N_sorts_; itype++) {
   381       const double e_init = conserved_initial.
momentum().
x0();
   384         e_tot += particle.momentum().x0();
   386       if (std::abs(e_tot - e_init) > 0.01 * e_init) {
   387         log.info(
"Rejecting: energy ", e_tot, 
" too far from ", e_init);
   398   int S_plus = 0, S_minus = 0, B_plus = 0, B_minus = 0, E_plus = 0, E_minus = 0;
   400   auto condition1 = [](int, int, int) { 
return true; };
   402   while (conserved_initial.
momentum().
x0() > energy ||
   413   auto condition2 = [](
int S, int, int) { 
return (S < 0); };
   415   while (S_plus + S_minus > conserved_initial.
strangeness()) {
   419     if (S_plus + S_minus + s_part >= conserved_initial.
strangeness()) {
   426   auto condition3 = [](
int S, int, int) { 
return (S == 0); };
   431   while (conserved_remaining.
momentum().
x0() > energy ||
   442   auto condition4 = [](
int S, 
int B, int) { 
return (S == 0) && (B < 0); };
   444   while (B_plus + B_minus > conserved_remaining.
baryon_number()) {
   447     if (B_plus + B_minus + bar >= conserved_remaining.
baryon_number()) {
   454   auto condition5 = [](
int S, 
int B, int) { 
return (S == 0) && (B == 0); };
   455   conserved_remaining = conserved_initial - QuantumNumbers(
sampled_list_);
   458   while (conserved_remaining.
momentum().
x0() > energy ||
   459          E_plus < conserved_remaining.
charge()) {
   469   auto condition6 = [](
int S, 
int B, 
int C) {
   470     return (S == 0) && (B == 0) && (C < 0);
   473   while (E_plus + E_minus > conserved_remaining.
charge()) {
   476     if (E_plus + E_minus + charge >= conserved_remaining.
charge()) {
   483   auto condition7 = [](
int S, 
int B, 
int C) {
   484     return (S == 0) && (B == 0) && (C == 0);
   486   conserved_remaining = conserved_initial - QuantumNumbers(
sampled_list_);
   489   while (conserved_remaining.
momentum().
x0() > energy) {
   498   const auto &log = logger<LogArea::GrandcanThermalizer>();
   499   log.info(
"Starting forced thermalization, time ", time, 
" fm/c");
   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_) {
   523   log.info(
"Removed ", 
to_remove_.size(), 
" particles.");
   531   const size_t lattice_total_cells = 
lat_->size();
   532   for (
size_t i = 0; i < lattice_total_cells; i++) {
   537   log.info(
"Number of cells in the thermalization region = ",
   551       throw std::invalid_argument(
   552           "This thermalization algorithm is"   553           " not yet implemented");
   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;
   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;
   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;
   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;
   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
 int charge() const 
The charge of the particle. 
 
static double net_baryon_density(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute net baryon density. 
 
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. 
 
PdgCode pdgcode() const 
Get the pdgcode of the particle. 
 
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 . 
 
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. 
 
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...
 
int baryon_number() const 
 
Class to handle the equation of state (EoS) of the hadron gas, consisting of all hadrons included int...
 
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 
 
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. 
 
int baryon_number() const 
 
double abs() const 
calculate the lorentz invariant absolute value 
 
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. 
 
double e() const 
Get energy density in the rest frame. 
 
ThreeVector threevec() const 
 
LatticeUpdate
Enumerator option for lattice updates. 
 
std::pair< int, int > sample()
Sample two numbers from given Poissonians with a fixed difference. 
 
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? 
 
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. 
 
void set_formation_time(const double &form_time)
Set the absolute formation time. 
 
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. 
 
ThreeVector velocity() const 
Get the velocity (3-vector divided by zero component). 
 
ThreeVector v() const 
Get 3-velocity of the rest frame. 
 
void set_4momentum(const FourVector &momentum_vector)
Set the particle's 4-momentum directly. 
 
Non-strange mesons (S = 0) with electric cherge Q < 0. 
 
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 . 
 
Mesons with strangeness S < 0. 
 
The intention of this class is to efficiently sample  from the Bessel distribution ...
 
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. 
 
Define the data structure for one element of the table. 
 
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. 
 
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. 
 
double nb_
Net baryon density of the cell in the computational frame. 
 
void set_4position(const FourVector &pos)
Set the particle's 4-position directly. 
 
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. 
 
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...
 
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. 
 
The Particles class abstracts the storage and manipulation of particles. 
 
DensityType
Allows to choose which kind of density to calculate. 
 
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Convenience: dereferences the ActionPtr to Action. 
 
double mult_class(const HadronClass cl) const 
 
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature. 
 
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. 
 
void boost_momentum(const ThreeVector &v)
Apply a Lorentz-boost to only the momentum. 
 
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. 
 
const FourVector & momentum() const 
Get the particle's 4-momentum. 
 
static double energy_density(double T, double mub, double mus)
Compute energy density. 
 
FourVector Tmu0() const 
Get Four-momentum flow of the cell.