Version: SMASH-3.4
smash::HadronGasEos Class Reference

#include <hadgas_eos.h>

Class to handle the equation of state (EoS) of the hadron gas, consisting of all hadrons included in SMASH.

This implementation deals with an ideal Boltzmann gas and allows to compute:

  • energy density \(\epsilon\), pressure \(p\), density \(n\), net baryon density \(n_B\), net strangeness \(n_S\) and net charge density \(n_Q\) as a function of temperature \(T\), baryon chemical potential \(\mu_B\), strange chemical potential \(\mu_S\) and charge chemical potential \(\mu_Q\).
  • Temperature and chemical potentials given energy-, net baryon- and net strangeness density. This requires solving a system of nonlinear equations.

Definition at line 124 of file hadgas_eos.h.

Collaboration diagram for smash::HadronGasEos:
[legend]

Classes

struct  eparams
 Another structure for passing energy density to the gnu library. More...
 
struct  rparams
 A structure for passing equation parameters to the gnu library. More...
 

Public Member Functions

 HadronGasEos (bool tabulate, bool account_for_widths)
 Constructor of HadronGasEos. More...
 
 ~HadronGasEos ()
 
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 charge density and an inital approximation. More...
 
std::array< double, 4 > solve_eos (double e, double nb, double ns, double nq)
 Compute temperature and chemical potentials given energy-, net baryon-, net strangeness- and net charge density without an inital approximation. More...
 
std::array< double, 4 > solve_eos_initial_approximation (double e, double nb, double nq)
 Compute a reasonable initial approximation for solve_eos. More...
 
void from_table (EosTable::table_element &res, double e, double nb, double nq) const
 Get the element of eos table. More...
 
bool is_tabulated () const
 Create an EoS table or not? More...
 
bool account_for_resonance_widths () const
 If resonance spectral functions are taken into account. More...
 

Static Public Member Functions

static double energy_density (double T, double mub, double mus, double muq)
 Compute energy density. More...
 
static double density (double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
 Compute particle number density. More...
 
static double pressure (double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
 Compute pressure \( p = n T \). More...
 
static double net_baryon_density (double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
 Compute net baryon density. More...
 
static double net_strange_density (double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
 Compute net strangeness density. More...
 
static double net_charge_density (double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
 Compute net charge density. More...
 
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. More...
 
static double sample_mass_thermal (const ParticleType &ptype, double beta)
 Sample resonance mass in a thermal medium. More...
 
static double mus_net_strangeness0 (double T, double mub, double muq)
 Compute strangeness chemical potential, requiring that net strangeness = 0. More...
 
static bool is_eos_particle (const ParticleType &ptype)
 Check if a particle belongs to the EoS. More...
 

Private Member Functions

std::string print_solver_state (size_t iter) const
 Helpful printout, useful for debugging if gnu equation solving goes crazy. More...
 

Static Private Member Functions

static double scaled_partial_density_auxiliary (double m_over_T, double mu_over_T)
 Function used to avoid duplications in density calculations. More...
 
static double scaled_partial_density (const ParticleType &ptype, double beta, double mub, double mus, double muq, bool account_for_width=false)
 Compute (unnormalized) density of one hadron sort - helper functions used to reduce code duplication. More...
 
static int set_eos_solver_equations (const gsl_vector *x, void *params, gsl_vector *f)
 Interface EoS equations to be solved to gnu library. More...
 
static double e_equation (double T, void *params)
 

Private Attributes

EosTable eos_table_ = EosTable(1.e-1, 1.e-1, 1.e-1, 90, 90, 90)
 EOS Table to be used. More...
 
gsl_vector * x_
 Variables used by gnu equation solver. More...
 
gsl_multiroot_fsolver * solver_
 
const bool tabulate_
 Create an EoS table or not? More...
 
const bool account_for_resonance_widths_
 Use pole masses of resonances or integrate over spectral functions. More...
 

Static Private Attributes

static constexpr double prefactor_
 Constant factor, that appears in front of many thermodyn. expressions. More...
 
static constexpr double tolerance_ = 1.e-8
 Precision of equation solving. More...
 
static constexpr size_t n_equations_ = 4
 Number of equations in the system of equations to be solved. More...
 

Constructor & Destructor Documentation

◆ HadronGasEos()

smash::HadronGasEos::HadronGasEos ( bool  tabulate,
bool  account_for_widths 
)

Constructor of HadronGasEos.

Parameters
[in]tabulateWhether the equation of state should be tabulated Tabulation takes time once (typically around 5 minutes), but makes the further usage of the class much faster. Tabulated values are saved in a file and loaded at the next run.
[in]account_for_widthsWhether equation of state should account for resonance spectral functions. Normally one wants to do it, if HadronGasEos is used for density calculations, for example in the box initialization. However, it is not recommended to account for spectral functions if EoS is tabulated (tabulate = true), because this makes tabulation incredibly slow. Therefore, for HadronGasEos to be used in thermalizer, this option has to be false. Also note that presently width account is not implemented for energy density calculation.

Definition at line 200 of file hadgas_eos.cc.

201  : x_(gsl_vector_alloc(n_equations_)),
202  tabulate_(tabulate),
203  account_for_resonance_widths_(account_for_width) {
204  const gsl_multiroot_fsolver_type *solver_type;
205  solver_type = gsl_multiroot_fsolver_hybrid;
206  solver_ = gsl_multiroot_fsolver_alloc(solver_type, n_equations_);
208  logg[LResonances].error(
209  "Compilation of hadron gas EoS table requested with"
210  " account of resonance spectral functions. This is not "
211  "advised, as it will likely take a few days to finish."
212  " Besides, the effect of resonance widths is currently not "
213  "implemented for energy density computation, so the computed"
214  " table will be inconsistent anyways.");
215  }
216  if (tabulate_) {
217  eos_table_.compile_table(*this);
218  }
219 }
void compile_table(HadronGasEos &eos, const std::string &eos_savefile_name="hadgas_eos.dat")
Computes the actual content of the table (for EosTable description see documentation of the construct...
Definition: hadgas_eos.cc:34
gsl_multiroot_fsolver * solver_
Definition: hadgas_eos.h:451
EosTable eos_table_
EOS Table to be used.
Definition: hadgas_eos.h:440
gsl_vector * x_
Variables used by gnu equation solver.
Definition: hadgas_eos.h:448
const bool tabulate_
Create an EoS table or not?
Definition: hadgas_eos.h:454
const bool account_for_resonance_widths_
Use pole masses of resonances or integrate over spectral functions.
Definition: hadgas_eos.h:457
static constexpr size_t n_equations_
Number of equations in the system of equations to be solved.
Definition: hadgas_eos.h:437
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & logg
An array that stores all pre-configured Logger objects.
Definition: logging.h:245
static constexpr int LResonances
Here is the call graph for this function:

◆ ~HadronGasEos()

smash::HadronGasEos::~HadronGasEos ( )

Definition at line 221 of file hadgas_eos.cc.

221  {
222  gsl_multiroot_fsolver_free(solver_);
223  gsl_vector_free(x_);
224 }

Member Function Documentation

◆ energy_density()

double smash::HadronGasEos::energy_density ( double  T,
double  mub,
double  mus,
double  muq 
)
static

Compute energy density.

Grand-canonical Boltzmann ideal gas, consisting of all hadrons in SMASH:

\[ \epsilon = \sum \frac{g_i m_i^2 T^2}{2\pi^2(\hbar c)^3} exp \left(\frac{\mu_B B_i + \mu_S S_i + \mu_Q Q_i}{T} \right) \times \left[ 3 K_2\left( \frac{m_i}{T}\right) + \frac{m_i}{T} K_1\left( \frac{m_i}{T}\right)\right] \]

Parameters
[in]Ttemperature [GeV]
[in]mubbaryon chemical potential [GeV]
[in]musstrangeness chemical potential [GeV]
[in]muqcharge chemical potential [GeV]
Returns
energy density e [GeV/fm \(^3\)]

Definition at line 284 of file hadgas_eos.cc.

285  {
286  if (T < really_small) {
287  return 0.0;
288  }
289  const double beta = 1.0 / T;
290  double e = 0.0;
291  for (const ParticleType &ptype : ParticleType::list_all()) {
292  if (!is_eos_particle(ptype)) {
293  continue;
294  }
295  const double z = ptype.mass() * beta;
296  double x = beta * (mub * ptype.baryon_number() + mus * ptype.strangeness() +
297  muq * ptype.charge() - ptype.mass());
298  if (x < -500.0) {
299  return 0.0;
300  }
301  x = std::exp(x);
302  const size_t g = ptype.spin() + 1;
303  // Small mass case, z*z*K_2(z) -> 2, z*z*z*K_1(z) -> 0 at z->0
304  e += (z < really_small) ? 3.0 * g * x
305  : z * z * g * x *
306  (3.0 * gsl_sf_bessel_Kn_scaled(2, z) +
307  z * gsl_sf_bessel_K1_scaled(z));
308  }
309  e *= prefactor_ * T * T * T * T;
310  return e;
311 }
static constexpr double prefactor_
Constant factor, that appears in front of many thermodyn. expressions.
Definition: hadgas_eos.h:430
static bool is_eos_particle(const ParticleType &ptype)
Check if a particle belongs to the EoS.
Definition: hadgas_eos.h:354
static const ParticleTypeList & list_all()
Definition: particletype.cc:51
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
Definition: random.h:373
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:41
Here is the call graph for this function:
Here is the caller graph for this function:

◆ density()

double smash::HadronGasEos::density ( double  T,
double  mub,
double  mus,
double  muq,
bool  account_for_resonance_widths = false 
)
static

Compute particle number density.

Grand-canonical Boltzmann ideal gas, consisting of all hadrons in SMASH:

\[ n = \sum \frac{g_i m_i^2 T}{2\pi^2(\hbar c)^3} exp \left(\frac{\mu_B B_i + \mu_S S_i + \mu_Q Q_i}{T} \right) K_2\left( \frac{m_i}{T}\right) \]

Parameters
[in]Ttemperature [GeV]
[in]mubbaryon chemical potential [GeV]
[in]musstrangeness chemical potential [GeV]
[in]muqcharge chemical potential [GeV]
[in]account_for_resonance_widthsif false, pole masses are used; if true, then integration over spectral function is included
Returns
particle number density n [fm \(^{-3}\)]

Definition at line 313 of file hadgas_eos.cc.

314  {
315  if (T < really_small) {
316  return 0.0;
317  }
318  const double beta = 1.0 / T;
319  double rho = 0.0;
320  for (const ParticleType &ptype : ParticleType::list_all()) {
321  if (!is_eos_particle(ptype)) {
322  continue;
323  }
324  rho +=
325  scaled_partial_density(ptype, beta, mub, mus, muq, account_for_width);
326  }
327  rho *= prefactor_ * T * T * T;
328  return rho;
329 }
static double scaled_partial_density(const ParticleType &ptype, double beta, double mub, double mus, double muq, bool account_for_width=false)
Compute (unnormalized) density of one hadron sort - helper functions used to reduce code duplication.
Definition: hadgas_eos.cc:240
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pressure()

static double smash::HadronGasEos::pressure ( double  T,
double  mub,
double  mus,
double  muq,
bool  account_for_resonance_widths = false 
)
inlinestatic

Compute pressure \( p = n T \).

Parameters
[in]Ttemperature [GeV]
[in]mubbaryon chemical potential [GeV]
[in]musstrangeness chemical potential [GeV]
[in]muqcharge chemical potential [GeV]
[in]account_for_resonance_widthsif false, pole masses are used; if true, then integration over spectral function is included
Returns
pressure p [GeV/fm \(^{-3}\)]

Definition at line 194 of file hadgas_eos.h.

195  {
196  return T * density(T, mub, mus, muq, account_for_resonance_widths);
197  }
bool account_for_resonance_widths() const
If resonance spectral functions are taken into account.
Definition: hadgas_eos.h:362
static double density(double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute particle number density.
Definition: hadgas_eos.cc:313
Here is the call graph for this function:
Here is the caller graph for this function:

◆ net_baryon_density()

double smash::HadronGasEos::net_baryon_density ( double  T,
double  mub,
double  mus,
double  muq,
bool  account_for_resonance_widths = false 
)
static

Compute net baryon density.

Grand-canonical Boltzmann ideal gas, consisting of all hadrons in SMASH:

\[ n_B = \sum B_i \frac{g_i m_i^2 T}{2\pi^2(\hbar c)^3} exp \left(\frac{\mu_B B_i + \mu_S S_i + \mu_Q Q_i}{T} \right) K_2\left( \frac{m_i}{T}\right) \]

Parameters
[in]Ttemperature [GeV]
[in]mubbaryon chemical potential [GeV]
[in]musstrangeness chemical potential [GeV]
[in]muqcharge chemical potential [GeV]
[in]account_for_resonance_widthsif false, pole masses are used; if true, then integration over spectral function is included
Returns
net baryon density \(n_B\) [fm \(^{-3}\)]

Definition at line 331 of file hadgas_eos.cc.

332  {
333  if (T < really_small) {
334  return 0.0;
335  }
336  const double beta = 1.0 / T;
337  double rho = 0.0;
338  for (const ParticleType &ptype : ParticleType::list_all()) {
339  if (!ptype.is_baryon() || !is_eos_particle(ptype)) {
340  continue;
341  }
342  rho +=
343  scaled_partial_density(ptype, beta, mub, mus, muq, account_for_width) *
344  ptype.baryon_number();
345  }
346  rho *= prefactor_ * T * T * T;
347  return rho;
348 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ net_strange_density()

double smash::HadronGasEos::net_strange_density ( double  T,
double  mub,
double  mus,
double  muq,
bool  account_for_resonance_widths = false 
)
static

Compute net strangeness density.

Grand-canonical Boltzmann ideal gas, consisting of all hadrons in SMASH:

\[ n_S = \sum S_i \frac{g_i m_i^2 T}{2\pi^2(\hbar c)^3} exp \left(\frac{\mu_B B_i + \mu_S S_i + \mu_Q Q_i}{T} \right) K_2\left( \frac{m_i}{T}\right) \]

Parameters
[in]Ttemperature [GeV]
[in]mubbaryon chemical potential [GeV]
[in]musstrangeness chemical potential [GeV]
[in]muqcharge chemical potential [GeV]
[in]account_for_resonance_widthsif false, pole masses are used; if true, then integration over spectral function is included
Returns
net strangeness density density \(n_S\) [fm \(^{-3}\)]

Definition at line 350 of file hadgas_eos.cc.

351  {
352  if (T < really_small) {
353  return 0.0;
354  }
355  const double beta = 1.0 / T;
356  double rho = 0.0;
357  for (const ParticleType &ptype : ParticleType::list_all()) {
358  if (ptype.strangeness() == 0 || !is_eos_particle(ptype)) {
359  continue;
360  }
361  rho +=
362  scaled_partial_density(ptype, beta, mub, mus, muq, account_for_width) *
363  ptype.strangeness();
364  }
365  rho *= prefactor_ * T * T * T;
366  return rho;
367 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ net_charge_density()

double smash::HadronGasEos::net_charge_density ( double  T,
double  mub,
double  mus,
double  muq,
bool  account_for_resonance_widths = false 
)
static

Compute net charge density.

Grand-canonical Boltzmann ideal gas, consisting of all hadrons in SMASH:

\[ n_Q = \sum Q_i \frac{g_i m_i^2 T}{2\pi^2(\hbar c)^3} exp \left(\frac{\mu_B B_i + \mu_S S_i + \mu_Q Q_i}{T} \right) K_2\left( \frac{m_i}{T}\right) \]

Parameters
[in]Ttemperature [GeV]
[in]mubbaryon chemical potential [GeV]
[in]musstrangeness chemical potential [GeV]
[in]muqcharge chemical potential [GeV]
[in]account_for_resonance_widthsif false, pole masses are used; if true, then integration over spectral function is included
Returns
net charge density density \(n_S\) [fm \(^{-3}\)]

Definition at line 369 of file hadgas_eos.cc.

370  {
371  if (T < really_small) {
372  return 0.0;
373  }
374  const double beta = 1.0 / T;
375  double rho = 0.0;
376  for (const ParticleType &ptype : ParticleType::list_all()) {
377  if (ptype.charge() == 0 || !is_eos_particle(ptype)) {
378  continue;
379  }
380  rho +=
381  scaled_partial_density(ptype, beta, mub, mus, muq, account_for_width) *
382  ptype.charge();
383  }
384  rho *= prefactor_ * T * T * T;
385  return rho;
386 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ partial_density()

double smash::HadronGasEos::partial_density ( const ParticleType ptype,
double  T,
double  mub,
double  mus,
double  muq,
bool  account_for_resonance_widths = false 
)
static

Compute partial density of one hadron sort.

Grand-canonical Boltzmann ideal gas:

\[ n = \frac{g m^2 T}{2\pi^2(\hbar c)^3} exp \left(\frac{\mu_B B + \mu_S S + \mu_Q Q_i}{T} \right) K_2\left( \frac{m}{T}\right) \]

Parameters
[in]ptypethe hadron sort, for which partial density is computed
[in]Ttemperature [GeV]
[in]mubbaryon chemical potential [GeV]
[in]musstrangeness chemical potential [GeV]
[in]muqcharge chemical potential [GeV]
[in]account_for_resonance_widthsif false, pole masses are used; if true, then integration over spectral function is included
Returns
partial density of the given hadron sort \(n\) [fm \(^{-3}\)]

Definition at line 273 of file hadgas_eos.cc.

275  {
276  if (T < really_small) {
277  return 0.0;
278  }
279  return prefactor_ * T * T * T *
280  scaled_partial_density(ptype, 1.0 / T, mub, mus, muq,
281  account_for_width);
282 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sample_mass_thermal()

double smash::HadronGasEos::sample_mass_thermal ( const ParticleType ptype,
double  beta 
)
static

Sample resonance mass in a thermal medium.

Samples mass from the distribution

\[ dN/dm \sim A(m) m^2 K_2\left( \frac{m}{T}\right) \]

For stable particles always returns pole mass.

Parameters
[in]ptypethe hadron sort, for which mass is sampled
[in]betainverse temperature 1/T [1/GeV]
Returns
sampled mass

Definition at line 388 of file hadgas_eos.cc.

389  {
390  if (ptype.is_stable()) {
391  return ptype.mass();
392  }
393  // Sampling mass m from A(m) x^2 BesselK_2(x), where x = beta m.
394  // Strategy employs the idea of importance sampling:
395  // -- Sample mass from the simple Breit-Wigner first, then
396  // reject by the ratio.
397  // -- Note that f(x) = x^2 BesselK_2(x) monotonously decreases
398  // and has maximum at x = xmin. That is why instead of f(x)
399  // the ratio f(x)/f(xmin) is used.
400 
401  const double max_mass = 5.0; // GeV
402  double m, q;
403  {
404  // Allow underflows in exponentials
405  DisableFloatTraps guard(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
406  const double w0 = ptype.width_at_pole();
407  const double mth = ptype.min_mass_spectral();
408  const double m0 = ptype.mass();
409  double max_ratio = m0 * m0 * std::exp(-beta * m0) *
410  gsl_sf_bessel_Kn_scaled(2, m0 * beta) *
411  ptype.full_spectral_function(m0) /
412  ptype.breit_wigner_spectral_function(m0);
413  // Heuristic adaptive maximum search to find max_ratio
414  constexpr int npoints = 31;
415  double m_lower = mth, m_upper = max_mass, m_where_max = m0;
416 
417  for (size_t n_iterations = 0; n_iterations < 2; n_iterations++) {
418  const double dm = (m_upper - m_lower) / npoints;
419  for (size_t i = 1; i < npoints; i++) {
420  m = m_lower + dm * i;
421  const double thermal_factor =
422  m * m * std::exp(-beta * m) * gsl_sf_bessel_Kn_scaled(2, m * beta);
423  q = ptype.full_spectral_function(m) * thermal_factor /
424  ptype.breit_wigner_spectral_function(m);
425  if (q > max_ratio) {
426  max_ratio = q;
427  m_where_max = m;
428  }
429  }
430  m_lower = m_where_max - (m_where_max - m_lower) * 0.1;
431  m_upper = m_where_max + (m_upper - m_where_max) * 0.1;
432  }
433  // Safety factor
434  max_ratio *= 1.5;
435 
436  do {
437  // sample mass from A(m)
438  do {
439  m = random::cauchy(m0, 0.5 * w0, mth, max_mass);
440  const double thermal_factor =
441  m * m * std::exp(-beta * m) * gsl_sf_bessel_Kn_scaled(2, m * beta);
442  q = ptype.full_spectral_function(m) * thermal_factor /
443  ptype.breit_wigner_spectral_function(m);
444  } while (q < random::uniform(0., max_ratio));
445  if (q > max_ratio) {
446  logg[LResonances].warn(
447  ptype.name(), " - maximum increased in",
448  " sample_mass_thermal from ", max_ratio, " to ", q, ", mass = ", m,
449  " previously assumed maximum at m = ", m_where_max);
450  max_ratio = q;
451  m_where_max = m;
452  } else {
453  break;
454  }
455  } while (true);
456  }
457  return m;
458 }
T uniform(T min, T max)
Definition: random.h:91
T cauchy(T pole, T width, T min, T max)
Draws a random number from a Cauchy distribution (sometimes also called Lorentz or non-relativistic B...
Definition: random.h:351
Here is the call graph for this function:
Here is the caller graph for this function:

◆ solve_eos() [1/2]

std::array< double, 4 > smash::HadronGasEos::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 charge density and an inital approximation.

Parameters
[in]eenergy density [GeV/fm \(^3\)]
[in]nbnet baryon density [fm \(^{-3}\)]
[in]nsnet strangeness density [fm \(^{-3}\)]
[in]nqnet charge density [fm \(^{-3}\)]
[in]initial_approximation(T [GeV], mub [GeV], mus [GeV]) to use as starting point
Returns
array of 4 values: temperature, baryon chemical potential, strange chemical potential and charge chemical potential

Definition at line 590 of file hadgas_eos.cc.

592  {
593  int residual_status = GSL_SUCCESS;
594  size_t iter = 0;
595 
596  struct rparams p = {e, nb, ns, nq, account_for_resonance_widths_};
597  gsl_multiroot_function f = {&HadronGasEos::set_eos_solver_equations,
598  n_equations_, &p};
599 
600  gsl_vector_set(x_, 0, initial_approximation[0]);
601  gsl_vector_set(x_, 1, initial_approximation[1]);
602  gsl_vector_set(x_, 2, initial_approximation[2]);
603  gsl_vector_set(x_, 3, initial_approximation[3]);
604 
605  gsl_multiroot_fsolver_set(solver_, &f, x_);
606  do {
607  iter++;
608  const auto iterate_status = gsl_multiroot_fsolver_iterate(solver_);
609  // std::cout << print_solver_state(iter);
610 
611  // Avoiding too low temperature
612  if (gsl_vector_get(solver_->x, 0) < 0.015) {
613  return {0.0, 0.0, 0.0, 0.0};
614  }
615 
616  // check if solver is stuck
617  if (iterate_status) {
618  break;
619  }
620  residual_status = gsl_multiroot_test_residual(solver_->f, tolerance_);
621  } while (residual_status == GSL_CONTINUE && iter < 1000);
622 
623  if (residual_status != GSL_SUCCESS) {
624  std::stringstream solver_parameters;
625  solver_parameters << "\nSolver run with "
626  << "e = " << e << ", nb = " << nb << ", ns = " << ns
627  << ", nq = " << nq
628  << ", init. approx.: " << initial_approximation[0] << " "
629  << initial_approximation[1] << " "
630  << initial_approximation[2] << " "
631  << initial_approximation[3] << std::endl;
632  logg[LResonances].warn(gsl_strerror(residual_status) +
633  solver_parameters.str() + print_solver_state(iter));
634  }
635 
636  return {gsl_vector_get(solver_->x, 0), gsl_vector_get(solver_->x, 1),
637  gsl_vector_get(solver_->x, 2), gsl_vector_get(solver_->x, 3)};
638 }
static int set_eos_solver_equations(const gsl_vector *x, void *params, gsl_vector *f)
Interface EoS equations to be solved to gnu library.
Definition: hadgas_eos.cc:484
std::string print_solver_state(size_t iter) const
Helpful printout, useful for debugging if gnu equation solving goes crazy.
Definition: hadgas_eos.cc:640
static constexpr double tolerance_
Precision of equation solving.
Definition: hadgas_eos.h:434
constexpr int p
Proton.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ solve_eos() [2/2]

std::array<double, 4> smash::HadronGasEos::solve_eos ( double  e,
double  nb,
double  ns,
double  nq 
)
inline

Compute temperature and chemical potentials given energy-, net baryon-, net strangeness- and net charge density without an inital approximation.

Parameters
[in]eenergy density [GeV/fm \(^3\)]
[in]nbnet baryon density [fm \(^{-3}\)]
[in]nsnet strangeness density [fm \(^{-3}\)]
[in]nqnet charge density [fm \(^{-3}\)]
Returns
array of 4 values: temperature, baryon chemical potential and strange chemical potential and charge

Definition at line 321 of file hadgas_eos.h.

321  {
322  return solve_eos(e, nb, ns, nq, solve_eos_initial_approximation(e, nb, nq));
323  }
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:590
std::array< double, 4 > solve_eos_initial_approximation(double e, double nb, double nq)
Compute a reasonable initial approximation for solve_eos.
Definition: hadgas_eos.cc:510
Here is the call graph for this function:

◆ solve_eos_initial_approximation()

std::array< double, 4 > smash::HadronGasEos::solve_eos_initial_approximation ( double  e,
double  nb,
double  nq 
)

Compute a reasonable initial approximation for solve_eos.

Parameters
[in]eenergy density [GeV/fm \(^3\)]
[in]nbnet baryon density [fm \(^{-3}\)]
[in]nqnet charge density [fm \(^{-3}\)]
Returns
array of 3 values: temperature, baryon chemical potential and strange chemical potential

Definition at line 510 of file hadgas_eos.cc.

512  {
513  assert(e >= 0.0);
514  // 1. Get temperature from energy density assuming zero chemical potentials
515  int degeneracies_sum = 0.0;
516  for (const ParticleType &ptype : ParticleType::list_all()) {
517  if (is_eos_particle(ptype)) {
518  degeneracies_sum += ptype.spin() + 1;
519  }
520  }
521  // Temperature in case of massless gas. For massive it should be larger.
522  const double T_min = std::pow(e / prefactor_ / 6 / degeneracies_sum, 1. / 4.);
523  // Simply assume that the temperature is not higher than 2 GeV.
524  const double T_max = 2.0;
525 
526  struct eparams parameters = {e};
527  gsl_function F = {&e_equation, &parameters};
528  const gsl_root_fsolver_type *T = gsl_root_fsolver_brent;
529  gsl_root_fsolver *e_solver;
530  e_solver = gsl_root_fsolver_alloc(T);
531  gsl_root_fsolver_set(e_solver, &F, T_min, T_max);
532 
533  int iter = 0, status, max_iter = 100;
534  double T_init = 0.0;
535 
536  do {
537  iter++;
538  status = gsl_root_fsolver_iterate(e_solver);
539  if (status != GSL_SUCCESS) {
540  break;
541  }
542  T_init = gsl_root_fsolver_root(e_solver);
543  double x_lo = gsl_root_fsolver_x_lower(e_solver);
544  double x_hi = gsl_root_fsolver_x_upper(e_solver);
545  status = gsl_root_test_interval(x_lo, x_hi, 0.0, 0.001);
546  } while (status == GSL_CONTINUE && iter < max_iter);
547 
548  if (status != GSL_SUCCESS) {
549  std::stringstream err_msg;
550  err_msg << "Solver of equation for temperature with e = " << e
551  << " failed to converge. Maybe Tmax = " << T_max << " is too small?"
552  << std::endl;
553  throw std::runtime_error(gsl_strerror(status) + err_msg.str());
554  }
555 
556  gsl_root_fsolver_free(e_solver);
557 
558  // 2. Get the baryon chemical potential for muS = muQ = 0 with previously
559  // obtained T
560  double n_only_baryons = 0.0;
561  for (const ParticleType &ptype : ParticleType::list_all()) {
562  if (is_eos_particle(ptype) && ptype.baryon_number() == 1) {
563  n_only_baryons +=
564  scaled_partial_density(ptype, 1.0 / T_init, 0.0, 0.0, 0.0);
565  }
566  }
567  const double nb_scaled = nb / prefactor_ / (T_init * T_init * T_init);
568  double mub_init = T_init * std::asinh(nb_scaled / n_only_baryons / 2.0);
569 
570  // 3. Get the charge chemical potential assuming muB = muS = 0 with previously
571  // obtained T
572  double n_only_charge_1_particles = 0.0;
573  for (const ParticleType &ptype : ParticleType::list_all()) {
574  if (is_eos_particle(ptype) && ptype.charge() == 1) {
575  n_only_charge_1_particles +=
576  scaled_partial_density(ptype, 1.0 / T_init, 0.0, 0.0, 0.0);
577  }
578  }
579  const double q_scaled = nq / prefactor_ / (T_init * T_init * T_init);
580  double muq_init =
581  T_init * std::asinh(q_scaled / n_only_charge_1_particles / 2.0);
582 
583  // 4. Get the strange chemical potential, where mus = 0 is typically a good
584  // initial approximation
585  std::array<double, 4> initial_approximation = {T_init, mub_init, 0.0,
586  muq_init};
587  return initial_approximation;
588 }
static double e_equation(double T, void *params)
Definition: hadgas_eos.cc:505
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mus_net_strangeness0()

double smash::HadronGasEos::mus_net_strangeness0 ( double  T,
double  mub,
double  muq 
)
static

Compute strangeness chemical potential, requiring that net strangeness = 0.

Parameters
[in]Ttemperature [GeV]
[in]mubbaryon chemical potential [GeV]
[in]muqcharge chemical potential [GeV]
Returns
strangeness chemical potential [GeV]

Definition at line 460 of file hadgas_eos.cc.

460  {
461  // Binary search
462  double mus_u = mub + T;
463  double mus_l = 0.0;
464  double mus, rhos;
465  size_t iteration = 0;
466  // 50 iterations should give precision 2^-50 ~ 10^-15
467  const size_t max_iteration = 50;
468  do {
469  mus = 0.5 * (mus_u + mus_l);
470  rhos = net_strange_density(T, mub, mus, muq);
471  if (rhos > 0.0) {
472  mus_u = mus;
473  } else {
474  mus_l = mus;
475  }
476  iteration++;
477  } while (std::abs(rhos) > tolerance_ && iteration < max_iteration);
478  if (iteration == max_iteration) {
479  throw std::runtime_error("Solving rho_s = 0: too many iterations.");
480  }
481  return mus;
482 }
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:350
Here is the call graph for this function:

◆ from_table()

void smash::HadronGasEos::from_table ( EosTable::table_element res,
double  e,
double  nb,
double  nq 
) const
inline

Get the element of eos table.

Definition at line 348 of file hadgas_eos.h.

349  {
350  eos_table_.get(res, e, nb, nq);
351  }
void get(table_element &res, double e, double nb, double nq) const
Obtain interpolated p/T/muB/muS/muQ from the tabulated equation of state given energy density,...
Definition: hadgas_eos.cc:162
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_eos_particle()

static bool smash::HadronGasEos::is_eos_particle ( const ParticleType ptype)
inlinestatic

Check if a particle belongs to the EoS.

Definition at line 354 of file hadgas_eos.h.

354  {
355  return ptype.is_hadron() && !ptype.pdgcode().is_heavy_flavor();
356  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_tabulated()

bool smash::HadronGasEos::is_tabulated ( ) const
inline

Create an EoS table or not?

Definition at line 359 of file hadgas_eos.h.

359 { return tabulate_; }
Here is the caller graph for this function:

◆ account_for_resonance_widths()

bool smash::HadronGasEos::account_for_resonance_widths ( ) const
inline

If resonance spectral functions are taken into account.

Definition at line 362 of file hadgas_eos.h.

362  {
364  }
Here is the caller graph for this function:

◆ scaled_partial_density_auxiliary()

double smash::HadronGasEos::scaled_partial_density_auxiliary ( double  m_over_T,
double  mu_over_T 
)
staticprivate

Function used to avoid duplications in density calculations.

Parameters
[in]m_over_Tmass to temperature ratio \( m/T \)
[in]mu_over_Tchemical potential to temperature ratio \( \mu/T \)
Returns
calculated \( (m/T)^2 exp(\mu/T) K_2(m/T) \)

Definition at line 226 of file hadgas_eos.cc.

227  {
228  double x = mu_over_T - m_over_T;
229  if (x < -500.0) {
230  return 0.0;
231  }
232  x = std::exp(x);
233  // In the case of small masses: K_n(z) -> (n-1)!/2 *(2/z)^n, z -> 0,
234  // z*z*K_2(z) -> 2
235  return (m_over_T < really_small)
236  ? 2.0 * x
237  : m_over_T * m_over_T * x * gsl_sf_bessel_Kn_scaled(2, m_over_T);
238 }
Here is the caller graph for this function:

◆ scaled_partial_density()

double smash::HadronGasEos::scaled_partial_density ( const ParticleType ptype,
double  beta,
double  mub,
double  mus,
double  muq,
bool  account_for_width = false 
)
staticprivate

Compute (unnormalized) density of one hadron sort - helper functions used to reduce code duplication.

Parameters
[in]ptypethe hadron sort, for which partial density is computed
[in]betainverse temperature [1/GeV]
[in]mubbaryon chemical potential [GeV]
[in]musstrangeness chemical potential [GeV]
[in]muqcharge chemical potential [GeV]
[in]account_for_widthTake hadron spectral functions into account or not. When taken into account, they result in a considerable slow down.
Returns
partial (unnormalized) density of the given hadron sort \(n\) [fm \(^{-3}\)]

Definition at line 240 of file hadgas_eos.cc.

243  {
244  const double m_over_T = ptype.mass() * beta;
245  double mu_over_T = beta * (ptype.baryon_number() * mub +
246  ptype.strangeness() * mus + ptype.charge() * muq);
247  const double g = ptype.spin() + 1;
248  if (ptype.is_stable() || !account_for_width) {
249  return g * scaled_partial_density_auxiliary(m_over_T, mu_over_T);
250  } else {
251  // Integral \int_{threshold}^{\infty} A(m) N_{thermal}(m) dm,
252  // where A(m) is the spectral function of the resonance.
253  const double m0 = ptype.mass();
254  const double w0 = ptype.width_at_pole();
255  const double mth = ptype.min_mass_spectral();
256  const double u_min = std::atan(2.0 * (mth - m0) / w0);
257  const double u_max = 0.5 * M_PI;
258  Integrator integrate;
259  const double result =
260  g * integrate(u_min, u_max, [&](double u) {
261  // One of many possible variable substitutions. Not clear if it has
262  // any advantages, except transforming (m_th, inf) to finite interval.
263  const double tanu = std::tan(u);
264  const double m = m0 + 0.5 * w0 * tanu;
265  const double jacobian = 0.5 * w0 * (1.0 + tanu * tanu);
266  return ptype.full_spectral_function(m) * jacobian *
267  scaled_partial_density_auxiliary(m * beta, mu_over_T);
268  });
269  return result;
270  }
271 }
static double scaled_partial_density_auxiliary(double m_over_T, double mu_over_T)
Function used to avoid duplications in density calculations.
Definition: hadgas_eos.cc:226
static Integrator integrate
Definition: decaytype.cc:143
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_eos_solver_equations()

int smash::HadronGasEos::set_eos_solver_equations ( const gsl_vector *  x,
void *  params,
gsl_vector *  f 
)
staticprivate

Interface EoS equations to be solved to gnu library.

Definition at line 484 of file hadgas_eos.cc.

485  {
486  double e = reinterpret_cast<struct rparams *>(params)->e;
487  double nb = reinterpret_cast<struct rparams *>(params)->nb;
488  double ns = reinterpret_cast<struct rparams *>(params)->ns;
489  double nq = reinterpret_cast<struct rparams *>(params)->nq;
490  bool w = reinterpret_cast<struct rparams *>(params)->account_for_width;
491 
492  const double T = gsl_vector_get(x, 0);
493  const double mub = gsl_vector_get(x, 1);
494  const double mus = gsl_vector_get(x, 2);
495  const double muq = gsl_vector_get(x, 3);
496 
497  gsl_vector_set(f, 0, energy_density(T, mub, mus, muq) - e);
498  gsl_vector_set(f, 1, net_baryon_density(T, mub, mus, muq, w) - nb);
499  gsl_vector_set(f, 2, net_strange_density(T, mub, mus, muq, w) - ns);
500  gsl_vector_set(f, 3, net_charge_density(T, mub, mus, muq, w) - nq);
501 
502  return GSL_SUCCESS;
503 }
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:369
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:331
static double energy_density(double T, double mub, double mus, double muq)
Compute energy density.
Definition: hadgas_eos.cc:284
Here is the call graph for this function:
Here is the caller graph for this function:

◆ e_equation()

double smash::HadronGasEos::e_equation ( double  T,
void *  params 
)
staticprivate
See also
set_eos_solver_equations()

Definition at line 505 of file hadgas_eos.cc.

505  {
506  const double edens = reinterpret_cast<struct eparams *>(params)->edens;
507  return edens - energy_density(T, 0.0, 0.0, 0.0);
508 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ print_solver_state()

std::string smash::HadronGasEos::print_solver_state ( size_t  iter) const
private

Helpful printout, useful for debugging if gnu equation solving goes crazy.

Parameters
[in]itercurrent value of iterator
Returns
debug output string with iter, x and f(x) from solver

Definition at line 640 of file hadgas_eos.cc.

640  {
641  std::stringstream s;
642  // clang-format off
643  s << "iter = " << iter << ","
644  << " x = " << gsl_vector_get(solver_->x, 0) << " "
645  << gsl_vector_get(solver_->x, 1) << " "
646  << gsl_vector_get(solver_->x, 2) << ", "
647  << gsl_vector_get(solver_->x, 3) << ", "
648  << "f(x) = " << gsl_vector_get(solver_->f, 0) << " "
649  << gsl_vector_get(solver_->f, 1) << " "
650  << gsl_vector_get(solver_->f, 2) << " "
651  << gsl_vector_get(solver_->f, 3) << std::endl;
652  // clang-format on
653  return s.str();
654 }
Here is the caller graph for this function:

Member Data Documentation

◆ prefactor_

constexpr double smash::HadronGasEos::prefactor_
staticconstexprprivate
Initial value:
=
0.5 * M_1_PI * M_1_PI / (hbarc * hbarc * hbarc)
constexpr double hbarc
GeV <-> fm conversion factor.
Definition: constants.h:29

Constant factor, that appears in front of many thermodyn. expressions.

Definition at line 430 of file hadgas_eos.h.

◆ tolerance_

constexpr double smash::HadronGasEos::tolerance_ = 1.e-8
staticconstexprprivate

Precision of equation solving.

Definition at line 434 of file hadgas_eos.h.

◆ n_equations_

constexpr size_t smash::HadronGasEos::n_equations_ = 4
staticconstexprprivate

Number of equations in the system of equations to be solved.

Definition at line 437 of file hadgas_eos.h.

◆ eos_table_

EosTable smash::HadronGasEos::eos_table_ = EosTable(1.e-1, 1.e-1, 1.e-1, 90, 90, 90)
private

EOS Table to be used.

Definition at line 440 of file hadgas_eos.h.

◆ x_

gsl_vector* smash::HadronGasEos::x_
private

Variables used by gnu equation solver.

They are stored here to allocate and deallocate memory for them only once. It is expected that this class will be used for solving the EoS many times, so multiple allocations and frees are unwanted.

Definition at line 448 of file hadgas_eos.h.

◆ solver_

gsl_multiroot_fsolver* smash::HadronGasEos::solver_
private
See also
x_

Definition at line 451 of file hadgas_eos.h.

◆ tabulate_

const bool smash::HadronGasEos::tabulate_
private

Create an EoS table or not?

Definition at line 454 of file hadgas_eos.h.

◆ account_for_resonance_widths_

const bool smash::HadronGasEos::account_for_resonance_widths_
private

Use pole masses of resonances or integrate over spectral functions.

Definition at line 457 of file hadgas_eos.h.


The documentation for this class was generated from the following files: