Version: SMASH-1.7
hadgas_eos.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2016-
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include <gsl/gsl_sf_bessel.h>
11 
12 #include <fstream>
13 #include <iomanip>
14 #include <iostream>
15 
16 #include <boost/filesystem.hpp>
17 
18 #include "smash/constants.h"
20 #include "smash/fpenvironment.h"
21 #include "smash/hadgas_eos.h"
22 #include "smash/integrate.h"
23 #include "smash/logging.h"
24 #include "smash/pow.h"
25 #include "smash/random.h"
26 
27 namespace smash {
28 
29 EosTable::EosTable(double de, double dnb, size_t n_e, size_t n_nb)
30  : de_(de), dnb_(dnb), n_e_(n_e), n_nb_(n_nb) {
31  table_.resize(n_e_ * n_nb_);
32 }
33 
35  const std::string &eos_savefile_name) {
36  bool table_read_success = false, table_consistency = true;
37  if (boost::filesystem::exists(eos_savefile_name)) {
38  std::cout << "Reading table from file " << eos_savefile_name << std::endl;
39  std::ifstream file;
40  file.open(eos_savefile_name, std::ios::in);
41  file >> de_ >> dnb_;
42  file >> n_e_ >> n_nb_;
43  table_.resize(n_e_ * n_nb_);
44  for (size_t ie = 0; ie < n_e_; ie++) {
45  for (size_t inb = 0; inb < n_nb_; inb++) {
46  double p, T, mub, mus;
47  file >> p >> T >> mub >> mus;
48  table_[index(ie, inb)] = {p, T, mub, mus};
49  }
50  }
51  table_read_success = true;
52  std::cout << "Table consumed successfully." << std::endl;
53  }
54 
55  if (table_read_success) {
56  // Check if the saved table is consistent with the current particle table
57  std::cout << "Checking consistency of the table... " << std::endl;
58  constexpr size_t number_of_steps = 50;
59  const size_t ie_step = 1 + n_e_ / number_of_steps;
60  const size_t inb_step = 1 + n_nb_ / number_of_steps;
61  for (size_t ie = 0; ie < n_e_; ie += ie_step) {
62  for (size_t inb = 0; inb < n_nb_; inb += inb_step) {
63  const table_element x = table_[index(ie, inb)];
64  const bool w = eos.account_for_resonance_widths();
65  const double e_comp = eos.energy_density(x.T, x.mub, x.mus);
66  const double nb_comp = eos.net_baryon_density(x.T, x.mub, x.mus, w);
67  const double ns_comp = eos.net_strange_density(x.T, x.mub, x.mus, w);
68  const double p_comp = eos.pressure(x.T, x.mub, x.mus, w);
69  // Precision is just 10^-3, this is precision of saved data in the file
70  const double eps = 1.e-3;
71  // Only check the physical region, hence T > 0 condition
72  if ((std::abs(de_ * ie - e_comp) > eps ||
73  std::abs(dnb_ * inb - nb_comp) > eps || std::abs(ns_comp) > eps ||
74  std::abs(x.p - p_comp) > eps) &&
75  (x.T > 0.0)) {
76  std::cout << "discrepancy: " << de_ * ie << " = " << e_comp << ", "
77  << dnb_ * inb << " = " << nb_comp << ", " << x.p << " = "
78  << p_comp << ", 0 = " << ns_comp << std::endl;
79  table_consistency = false;
80  goto finish_consistency_check;
81  }
82  }
83  }
84  }
85 finish_consistency_check:
86 
87  if (!table_read_success || !table_consistency) {
88  std::cout << "Compiling an EoS table..." << std::endl;
89  const double ns = 0.0;
90  for (size_t ie = 0; ie < n_e_; ie++) {
91  std::cout << ie << "/" << n_e_ << "\r" << std::flush;
92  const double e = de_ * ie;
93  for (size_t inb = 0; inb < n_nb_; inb++) {
94  const double nb = dnb_ * inb;
95  // It is physically impossible to have energy density > nucleon mass*nb,
96  // therefore eqns have no solutions.
97  if (nb >= e) {
98  table_[index(ie, inb)] = {0.0, 0.0, 0.0, 0.0};
99  continue;
100  }
101  // Take extrapolated (T, mub, mus) as initial approximation
102  std::array<double, 3> init_approx;
103  if (inb >= 2) {
104  const table_element y = table_[index(ie, inb - 2)];
105  const table_element x = table_[index(ie, inb - 1)];
106  init_approx = {2.0 * x.T - y.T, 2.0 * x.mub - y.mub,
107  2.0 * x.mus - y.mus};
108  } else {
109  init_approx = eos.solve_eos_initial_approximation(e, nb);
110  }
111  const std::array<double, 3> res = eos.solve_eos(e, nb, ns, init_approx);
112  const double T = res[0];
113  const double mub = res[1];
114  const double mus = res[2];
115  const bool w = eos.account_for_resonance_widths();
116  table_[index(ie, inb)] = {eos.pressure(T, mub, mus, w), T, mub, mus};
117  }
118  }
119  // Save table to file
120  std::cout << "Saving table to file " << eos_savefile_name << std::endl;
121  std::ofstream file;
122  file.open(eos_savefile_name, std::ios::out);
123  file << de_ << " " << dnb_ << std::endl;
124  file << n_e_ << " " << n_nb_ << std::endl;
125  file << std::setprecision(7);
126  file << std::fixed;
127  for (size_t ie = 0; ie < n_e_; ie++) {
128  for (size_t inb = 0; inb < n_nb_; inb++) {
129  const EosTable::table_element x = table_[index(ie, inb)];
130  file << x.p << " " << x.T << " " << x.mub << " " << x.mus << std::endl;
131  }
132  }
133  }
134 }
135 
136 void EosTable::get(EosTable::table_element &res, double e, double nb) const {
137  const size_t ie = static_cast<size_t>(std::floor(e / de_));
138  const size_t inb = static_cast<size_t>(std::floor(nb / dnb_));
139 
140  if (ie >= n_e_ - 1 || inb >= n_nb_ - 1) {
141  res = {-1.0, -1.0, -1.0, -1.0};
142  } else {
143  // 1st order interpolation
144  const double ae = e / de_ - ie;
145  const double an = nb / dnb_ - inb;
146  const EosTable::table_element s1 = table_[index(ie, inb)];
147  const EosTable::table_element s2 = table_[index(ie + 1, inb)];
148  const EosTable::table_element s3 = table_[index(ie, inb + 1)];
149  const EosTable::table_element s4 = table_[index(ie + 1, inb + 1)];
150  res.p = ae * (an * s4.p + (1.0 - an) * s2.p) +
151  (1.0 - ae) * (an * s3.p + (1.0 - an) * s1.p);
152  res.T = ae * (an * s4.T + (1.0 - an) * s2.T) +
153  (1.0 - ae) * (an * s3.T + (1.0 - an) * s1.T);
154  res.mub = ae * (an * s4.mub + (1.0 - an) * s2.mub) +
155  (1.0 - ae) * (an * s3.mub + (1.0 - an) * s1.mub);
156  res.mus = ae * (an * s4.mus + (1.0 - an) * s2.mus) +
157  (1.0 - ae) * (an * s3.mus + (1.0 - an) * s1.mus);
158  }
159 }
160 
161 HadronGasEos::HadronGasEos(bool tabulate, bool account_for_width)
162  : x_(gsl_vector_alloc(n_equations_)),
163  tabulate_(tabulate),
164  account_for_resonance_widths_(account_for_width) {
165  const gsl_multiroot_fsolver_type *solver_type;
166  solver_type = gsl_multiroot_fsolver_hybrid;
167  solver_ = gsl_multiroot_fsolver_alloc(solver_type, n_equations_);
169  const auto &log = logger<LogArea::Resonances>();
170  log.error(
171  "Compilation of hadron gas EoS table requested with"
172  " account of resonance spectral functions. This is not "
173  "advised, as it will likely take a few days to finish."
174  " Besides, the effect of resonance widths is currently not "
175  "implemented for energy density computation, so the computed"
176  " table will be inconsistent anyways.");
177  }
178  if (tabulate_) {
179  eos_table_.compile_table(*this);
180  }
181 }
182 
184  gsl_multiroot_fsolver_free(solver_);
185  gsl_vector_free(x_);
186 }
187 
189  double mu_over_T) {
190  double x = mu_over_T - m_over_T;
191  if (x < -500.0) {
192  return 0.0;
193  }
194  x = std::exp(x);
195  // In the case of small masses: K_n(z) -> (n-1)!/2 *(2/z)^n, z -> 0,
196  // z*z*K_2(z) -> 2
197  return (m_over_T < really_small)
198  ? 2.0 * x
199  : m_over_T * m_over_T * x * gsl_sf_bessel_Kn_scaled(2, m_over_T);
200 }
201 
203  double beta, double mub, double mus,
204  bool account_for_width) {
205  const double m_over_T = ptype.mass() * beta;
206  double mu_over_T =
207  beta * (ptype.baryon_number() * mub + ptype.strangeness() * mus);
208  const double g = ptype.spin() + 1;
209  if (ptype.is_stable() || !account_for_width) {
210  return g * scaled_partial_density_auxiliary(m_over_T, mu_over_T);
211  } else {
212  // Integral \int_{threshold}^{\infty} A(m) N_{thermal}(m) dm,
213  // where A(m) is the spectral function of the resonance.
214  const double m0 = ptype.mass();
215  const double w0 = ptype.width_at_pole();
216  const double mth = ptype.min_mass_spectral();
217  const double u_min = std::atan(2.0 * (mth - m0) / w0);
218  const double u_max = 0.5 * M_PI;
220  const double result =
221  g * integrate(u_min, u_max, [&](double u) {
222  // One of many possible variable substitutions. Not clear if it has
223  // any advantages, except transforming (m_th, inf) to finite interval.
224  const double tanu = std::tan(u);
225  const double m = m0 + 0.5 * w0 * tanu;
226  const double jacobian = 0.5 * w0 * (1.0 + tanu * tanu);
227  return ptype.spectral_function(m) * jacobian *
228  scaled_partial_density_auxiliary(m * beta, mu_over_T);
229  });
230  return result;
231  }
232 }
233 
234 double HadronGasEos::partial_density(const ParticleType &ptype, double T,
235  double mub, double mus,
236  bool account_for_width) {
237  if (T < really_small) {
238  return 0.0;
239  }
240  return prefactor_ * T * T * T *
241  scaled_partial_density(ptype, 1.0 / T, mub, mus, account_for_width);
242 }
243 
244 double HadronGasEos::energy_density(double T, double mub, double mus) {
245  if (T < really_small) {
246  return 0.0;
247  }
248  const double beta = 1.0 / T;
249  double e = 0.0;
250  for (const ParticleType &ptype : ParticleType::list_all()) {
251  if (!is_eos_particle(ptype)) {
252  continue;
253  }
254  const double z = ptype.mass() * beta;
255  double x = beta * (mub * ptype.baryon_number() + mus * ptype.strangeness() -
256  ptype.mass());
257  if (x < -500.0) {
258  return 0.0;
259  }
260  x = std::exp(x);
261  const size_t g = ptype.spin() + 1;
262  // Small mass case, z*z*K_2(z) -> 2, z*z*z*K_1(z) -> 0 at z->0
263  e += (z < really_small) ? 3.0 * g * x
264  : z * z * g * x *
265  (3.0 * gsl_sf_bessel_Kn_scaled(2, z) +
266  z * gsl_sf_bessel_K1_scaled(z));
267  }
268  e *= prefactor_ * T * T * T * T;
269  return e;
270 }
271 
272 double HadronGasEos::density(double T, double mub, double mus,
273  bool account_for_width) {
274  if (T < really_small) {
275  return 0.0;
276  }
277  const double beta = 1.0 / T;
278  double rho = 0.0;
279  for (const ParticleType &ptype : ParticleType::list_all()) {
280  if (!is_eos_particle(ptype)) {
281  continue;
282  }
283  rho += scaled_partial_density(ptype, beta, mub, mus, account_for_width);
284  }
285  rho *= prefactor_ * T * T * T;
286  return rho;
287 }
288 
289 double HadronGasEos::net_baryon_density(double T, double mub, double mus,
290  bool account_for_width) {
291  if (T < really_small) {
292  return 0.0;
293  }
294  const double beta = 1.0 / T;
295  double rho = 0.0;
296  for (const ParticleType &ptype : ParticleType::list_all()) {
297  if (!ptype.is_baryon() || !is_eos_particle(ptype)) {
298  continue;
299  }
300  rho += scaled_partial_density(ptype, beta, mub, mus, account_for_width) *
301  ptype.baryon_number();
302  }
303  rho *= prefactor_ * T * T * T;
304  return rho;
305 }
306 
307 double HadronGasEos::net_strange_density(double T, double mub, double mus,
308  bool account_for_width) {
309  if (T < really_small) {
310  return 0.0;
311  }
312  const double beta = 1.0 / T;
313  double rho = 0.0;
314  for (const ParticleType &ptype : ParticleType::list_all()) {
315  if (ptype.strangeness() == 0 || !is_eos_particle(ptype)) {
316  continue;
317  }
318  rho += scaled_partial_density(ptype, beta, mub, mus, account_for_width) *
319  ptype.strangeness();
320  }
321  rho *= prefactor_ * T * T * T;
322  return rho;
323 }
324 
326  double beta) {
327  if (ptype.is_stable()) {
328  return ptype.mass();
329  }
330  // Sampling mass m from A(m) x^2 BesselK_2(x), where x = beta m.
331  // Strategy employs the idea of importance sampling:
332  // -- Sample mass from the simple Breit-Wigner first, then
333  // reject by the ratio.
334  // -- Note that f(x) = x^2 BesselK_2(x) monotonously decreases
335  // and has maximum at x = xmin. That is why instead of f(x)
336  // the ratio f(x)/f(xmin) is used.
337 
338  const double max_mass = 5.0; // GeV
339  double m, q;
340  {
341  // Allow underflows in exponentials
342  DisableFloatTraps guard(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
343  const double w0 = ptype.width_at_pole();
344  const double mth = ptype.min_mass_spectral();
345  const double m0 = ptype.mass();
346  double max_ratio =
347  m0 * m0 * std::exp(-beta * m0) * gsl_sf_bessel_Kn_scaled(2, m0 * beta) *
348  ptype.spectral_function(m0) / ptype.spectral_function_simple(m0);
349  // Heuristic adaptive maximum search to find max_ratio
350  constexpr int npoints = 31;
351  double m_lower = mth, m_upper = max_mass, m_where_max = m0;
352 
353  for (size_t n_iterations = 0; n_iterations < 2; n_iterations++) {
354  const double dm = (m_upper - m_lower) / npoints;
355  for (size_t i = 1; i < npoints; i++) {
356  m = m_lower + dm * i;
357  const double thermal_factor =
358  m * m * std::exp(-beta * m) * gsl_sf_bessel_Kn_scaled(2, m * beta);
359  q = ptype.spectral_function(m) * thermal_factor /
360  ptype.spectral_function_simple(m);
361  if (q > max_ratio) {
362  max_ratio = q;
363  m_where_max = m;
364  }
365  }
366  m_lower = m_where_max - (m_where_max - m_lower) * 0.1;
367  m_upper = m_where_max + (m_upper - m_where_max) * 0.1;
368  }
369  // Safety factor
370  max_ratio *= 1.5;
371 
372  do {
373  // sample mass from A(m)
374  do {
375  m = random::cauchy(m0, 0.5 * w0, mth, max_mass);
376  const double thermal_factor =
377  m * m * std::exp(-beta * m) * gsl_sf_bessel_Kn_scaled(2, m * beta);
378  q = ptype.spectral_function(m) * thermal_factor /
379  ptype.spectral_function_simple(m);
380  } while (q < random::uniform(0., max_ratio));
381  if (q > max_ratio) {
382  const auto &log = logger<LogArea::Resonances>();
383  log.warn(ptype.name(), " - maximum increased in",
384  " sample_mass_thermal from ", max_ratio, " to ", q,
385  ", mass = ", m,
386  " previously assumed maximum at m = ", m_where_max);
387  max_ratio = q;
388  m_where_max = m;
389  } else {
390  break;
391  }
392  } while (true);
393  }
394  return m;
395 }
396 
397 double HadronGasEos::mus_net_strangeness0(double T, double mub) {
398  // Binary search
399  double mus_u = mub + T;
400  double mus_l = 0.0;
401  double mus, rhos;
402  size_t iteration = 0;
403  // 50 iterations should give precision 2^-50 ~ 10^-15
404  const size_t max_iteration = 50;
405  do {
406  mus = 0.5 * (mus_u + mus_l);
407  rhos = net_strange_density(T, mub, mus);
408  if (rhos > 0.0) {
409  mus_u = mus;
410  } else {
411  mus_l = mus;
412  }
413  iteration++;
414  } while (std::abs(rhos) > tolerance_ && iteration < max_iteration);
415  if (iteration == max_iteration) {
416  throw std::runtime_error("Solving rho_s = 0: too many iterations.");
417  }
418  return mus;
419 }
420 
421 int HadronGasEos::set_eos_solver_equations(const gsl_vector *x, void *params,
422  gsl_vector *f) {
423  double e = reinterpret_cast<struct rparams *>(params)->e;
424  double nb = reinterpret_cast<struct rparams *>(params)->nb;
425  double ns = reinterpret_cast<struct rparams *>(params)->ns;
426  bool w = reinterpret_cast<struct rparams *>(params)->account_for_width;
427 
428  const double T = gsl_vector_get(x, 0);
429  const double mub = gsl_vector_get(x, 1);
430  const double mus = gsl_vector_get(x, 2);
431 
432  gsl_vector_set(f, 0, energy_density(T, mub, mus) - e);
433  gsl_vector_set(f, 1, net_baryon_density(T, mub, mus, w) - nb);
434  gsl_vector_set(f, 2, net_strange_density(T, mub, mus, w) - ns);
435 
436  return GSL_SUCCESS;
437 }
438 
439 double HadronGasEos::e_equation(double T, void *params) {
440  const double edens = reinterpret_cast<struct eparams *>(params)->edens;
441  return edens - energy_density(T, 0.0, 0.0);
442 }
443 
444 std::array<double, 3> HadronGasEos::solve_eos_initial_approximation(double e,
445  double nb) {
446  assert(e >= 0.0);
447  // 1. Get temperature from energy density assuming zero chemical potentials
448  int degeneracies_sum = 0.0;
449  for (const ParticleType &ptype : ParticleType::list_all()) {
450  if (is_eos_particle(ptype)) {
451  degeneracies_sum += ptype.spin() + 1;
452  }
453  }
454  // Temperature in case of massless gas. For massive it should be larger.
455  const double T_min = std::pow(e / prefactor_ / 6 / degeneracies_sum, 1. / 4.);
456  // Simply assume that the temperature is not higher than 2 GeV.
457  const double T_max = 2.0;
458 
459  struct eparams parameters = {e};
460  gsl_function F = {&e_equation, &parameters};
461  const gsl_root_fsolver_type *T = gsl_root_fsolver_brent;
462  gsl_root_fsolver *e_solver;
463  e_solver = gsl_root_fsolver_alloc(T);
464  gsl_root_fsolver_set(e_solver, &F, T_min, T_max);
465 
466  int iter = 0, status, max_iter = 100;
467  double T_init = 0.0;
468 
469  do {
470  iter++;
471  status = gsl_root_fsolver_iterate(e_solver);
472  if (status != GSL_SUCCESS) {
473  break;
474  }
475  T_init = gsl_root_fsolver_root(e_solver);
476  double x_lo = gsl_root_fsolver_x_lower(e_solver);
477  double x_hi = gsl_root_fsolver_x_upper(e_solver);
478  status = gsl_root_test_interval(x_lo, x_hi, 0.0, 0.001);
479  } while (status == GSL_CONTINUE && iter < max_iter);
480 
481  if (status != GSL_SUCCESS) {
482  std::stringstream err_msg;
483  err_msg << "Solver of equation for temperature with e = " << e
484  << " failed to converge. Maybe Tmax = " << T_max << " is too small?"
485  << std::endl;
486  throw std::runtime_error(gsl_strerror(status) + err_msg.str());
487  }
488 
489  gsl_root_fsolver_free(e_solver);
490 
491  // 2. Get the baryon chemical potential for mus = 0 and previously obtained T
492  double n_only_baryons = 0.0;
493  for (const ParticleType &ptype : ParticleType::list_all()) {
494  if (is_eos_particle(ptype) && ptype.baryon_number() == 1) {
495  n_only_baryons += scaled_partial_density(ptype, 1.0 / T_init, 0.0, 0.0);
496  }
497  }
498  const double nb_scaled = nb / prefactor_ / (T_init * T_init * T_init);
499  double mub_init = T_init * std::asinh(nb_scaled / n_only_baryons / 2.0);
500 
501  // 3. mus = 0 is typically a good initial approximation
502 
503  std::array<double, 3> initial_approximation = {T_init, mub_init, 0.0};
504  return initial_approximation;
505 }
506 
507 std::array<double, 3> HadronGasEos::solve_eos(
508  double e, double nb, double ns,
509  std::array<double, 3> initial_approximation) {
510  int residual_status = GSL_SUCCESS;
511  size_t iter = 0;
512 
513  struct rparams p = {e, nb, ns, account_for_resonance_widths_};
514  gsl_multiroot_function f = {&HadronGasEos::set_eos_solver_equations,
515  n_equations_, &p};
516 
517  gsl_vector_set(x_, 0, initial_approximation[0]);
518  gsl_vector_set(x_, 1, initial_approximation[1]);
519  gsl_vector_set(x_, 2, initial_approximation[2]);
520 
521  gsl_multiroot_fsolver_set(solver_, &f, x_);
522  do {
523  iter++;
524  const auto iterate_status = gsl_multiroot_fsolver_iterate(solver_);
525  // std::cout << print_solver_state(iter);
526 
527  // Avoiding too low temperature
528  if (gsl_vector_get(solver_->x, 0) < 0.015) {
529  return {0.0, 0.0, 0.0};
530  }
531 
532  // check if solver is stuck
533  if (iterate_status) {
534  break;
535  }
536  residual_status = gsl_multiroot_test_residual(solver_->f, tolerance_);
537  } while (residual_status == GSL_CONTINUE && iter < 1000);
538 
539  if (residual_status != GSL_SUCCESS) {
540  std::stringstream solver_parameters;
541  solver_parameters << "\nSolver run with "
542  << "e = " << e << ", nb = " << nb << ", ns = " << ns
543  << ", init. approx.: " << initial_approximation[0] << " "
544  << initial_approximation[1] << " "
545  << initial_approximation[2] << std::endl;
546  const auto &log = logger<LogArea::HadronGasEos>();
547  log.warn(gsl_strerror(residual_status) + solver_parameters.str() +
548  print_solver_state(iter));
549  }
550 
551  return {gsl_vector_get(solver_->x, 0), gsl_vector_get(solver_->x, 1),
552  gsl_vector_get(solver_->x, 2)};
553 }
554 
555 std::string HadronGasEos::print_solver_state(size_t iter) const {
556  std::stringstream s;
557  // clang-format off
558  s << "iter = " << iter << ","
559  << " x = " << gsl_vector_get(solver_->x, 0) << " "
560  << gsl_vector_get(solver_->x, 1) << " "
561  << gsl_vector_get(solver_->x, 2) << ", "
562  << "f(x) = " << gsl_vector_get(solver_->f, 0) << " "
563  << gsl_vector_get(solver_->f, 1) << " "
564  << gsl_vector_get(solver_->f, 2) << std::endl;
565  // clang-format on
566  return s.str();
567 }
568 
569 } // namespace smash
static double net_baryon_density(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute net baryon density.
Definition: hadgas_eos.cc:289
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
static double scaled_partial_density(const ParticleType &ptype, double beta, double mub, double mus, bool account_for_width=false)
Compute (unnormalized) density of one hadron sort - helper functions used to reduce code duplication...
Definition: hadgas_eos.cc:202
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
double mub
Net baryochemical potential.
Definition: hadgas_eos.h:61
std::array< double, 3 > solve_eos(double e, double nb, double ns, std::array< double, 3 > initial_approximation)
Compute temperature and chemical potentials given energy-, net baryon-, net strangeness density and a...
Definition: hadgas_eos.cc:507
int baryon_number() const
Definition: particletype.h:206
bool is_stable() const
Definition: particletype.h:236
Class to handle the equation of state (EoS) of the hadron gas, consisting of all hadrons included int...
Definition: hadgas_eos.h:112
Guard type that safely disables floating point traps for the scope in which it is placed...
Definition: fpenvironment.h:79
Collection of useful constants that are known at compile time.
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:421
double mus
Net strangeness potential.
Definition: hadgas_eos.h:63
double T
Temperature.
Definition: hadgas_eos.h:59
std::string print_solver_state(size_t iter) const
Helpful printout, useful for debugging if gnu equation solving goes crazy.
Definition: hadgas_eos.cc:555
double dnb_
Step in net-baryon density.
Definition: hadgas_eos.h:93
double spectral_function(double m) const
Full spectral function of the resonance (relativistic Breit-Wigner distribution with mass-dependent ...
static constexpr size_t n_equations_
Number of equations in the system of equations to be solved.
Definition: hadgas_eos.h:388
EosTable(double de, double dnb, size_t n_e, size_t n_b)
Sets up a table p/T/muB/mus versus (e, nb), where e is energy density, nb is net baryon density...
Definition: hadgas_eos.cc:29
static bool is_eos_particle(const ParticleType &ptype)
Check if a particle belongs to the EoS.
Definition: hadgas_eos.h:308
void get(table_element &res, double e, double nb) const
Obtain interpolated p/T/muB/muS from the tabulated equation of state given energy density and net bar...
Definition: hadgas_eos.cc:136
static double density(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute particle number density.
Definition: hadgas_eos.cc:272
static double partial_density(const ParticleType &ptype, double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute partial density of one hadron sort.
Definition: hadgas_eos.cc:234
EosTable eos_table_
EOS Table to be used.
Definition: hadgas_eos.h:391
static constexpr double prefactor_
Constant factor, that appears in front of many thermodyn. expressions.
Definition: hadgas_eos.h:381
size_t n_nb_
Number of steos in net-baryon density.
Definition: hadgas_eos.h:97
static constexpr double tolerance_
Precision of equation solving.
Definition: hadgas_eos.h:385
size_t n_e_
Number of steps in energy density.
Definition: hadgas_eos.h:95
static const ParticleTypeList & list_all()
Definition: particletype.cc:55
double mass() const
Definition: particletype.h:144
gsl_multiroot_fsolver * solver_
Definition: hadgas_eos.h:402
const bool account_for_resonance_widths_
Use pole masses of resonances or integrate over spectral functions.
Definition: hadgas_eos.h:408
const std::string & name() const
Definition: particletype.h:141
Particle type contains the static properties of a particle species.
Definition: particletype.h:97
HadronGasEos(bool tabulate, bool account_for_widths)
Constructor of HadronGasEos.
Definition: hadgas_eos.cc:161
A structure for passing equation parameters to the gnu library.
Definition: hadgas_eos.h:322
double min_mass_spectral() const
The minimum mass of the resonance, where the spectral function is non-zero.
size_t index(size_t ie, size_t inb) const
proper index in a 1d vector, where the 2d table is stored
Definition: hadgas_eos.h:87
static double pressure(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute pressure .
Definition: hadgas_eos.h:180
static double sample_mass_thermal(const ParticleType &ptype, double beta)
Sample resonance mass in a thermal medium.
Definition: hadgas_eos.cc:325
T uniform(T min, T max)
Definition: random.h:88
int strangeness() const
Definition: particletype.h:209
Define the data structure for one element of the table.
Definition: hadgas_eos.h:55
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:307
std::array< double, 3 > solve_eos_initial_approximation(double e, double nb)
Compute a reasonable initial approximation for solve_eos.
Definition: hadgas_eos.cc:444
gsl_vector * x_
Variables used by gnu equation solver.
Definition: hadgas_eos.h:399
constexpr int p
Proton.
double width_at_pole() const
Definition: particletype.h:150
A C++ interface for numerical integration in one dimension with the GSL CQUAD integration functions...
Definition: integrate.h:106
const bool tabulate_
Create an EoS table or not?
Definition: hadgas_eos.h:405
Another structure for passing energy density to the gnu library.
Definition: hadgas_eos.h:334
static double mus_net_strangeness0(double T, double mub)
Compute strangeness chemical potential, requiring that net strangeness = 0.
Definition: hadgas_eos.cc:397
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:188
bool account_for_resonance_widths() const
If resonance spectral functions are taken into account.
Definition: hadgas_eos.h:316
double de_
Step in energy density.
Definition: hadgas_eos.h:91
std::vector< table_element > table_
Storage for the tabulated equation of state.
Definition: hadgas_eos.h:89
double spectral_function_simple(double m) const
This one is the most simple form of the spectral function, using a Cauchy distribution (non-relativis...
static double e_equation(double T, void *params)
Definition: hadgas_eos.cc:439
unsigned int spin() const
Definition: particletype.h:191
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
Definition: random.h:329
static double net_strange_density(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute net strangeness density.
Definition: hadgas_eos.cc:307
Definition: action.h:24
static Integrator integrate
Definition: decaytype.cc:147
static double energy_density(double T, double mub, double mus)
Compute energy density.
Definition: hadgas_eos.cc:244