10 #include <gsl/gsl_sf_bessel.h> 
   16 #include <boost/filesystem.hpp> 
   30     : de_(de), dnb_(dnb), dq_(dq), n_e_(n_e), n_nb_(n_nb), n_q_(n_q) {
 
   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;
 
   40     file.open(eos_savefile_name, std::ios::in);
 
   44     for (
size_t ie = 0; ie < 
n_e_; ie++) {
 
   45       for (
size_t inb = 0; inb < 
n_nb_; inb++) {
 
   46         for (
size_t iq = 0; iq < 
n_q_; iq++) {
 
   47           double p, T, mub, mus, muq;
 
   48           file >> 
p >> T >> mub >> mus >> muq;
 
   53     table_read_success = 
true;
 
   54     std::cout << 
"Table consumed successfully." << std::endl;
 
   57   if (table_read_success) {
 
   59     std::cout << 
"Checking consistency of the table... " << std::endl;
 
   60     constexpr 
size_t number_of_steps = 50;
 
   61     const size_t ie_step = 1 + 
n_e_ / number_of_steps;
 
   62     const size_t inb_step = 1 + 
n_nb_ / number_of_steps;
 
   63     const size_t iq_step = 1 + 
n_q_ / number_of_steps;
 
   64     for (
size_t ie = 0; ie < 
n_e_; ie += ie_step) {
 
   65       for (
size_t inb = 0; inb < 
n_nb_; inb += inb_step) {
 
   66         for (
size_t iq = 0; iq < 
n_q_; iq += iq_step) {
 
   70           const double nb_comp =
 
   72           const double ns_comp =
 
   75           const double nq_comp =
 
   79           const double eps = 1.e-3;
 
   81           if ((std::abs(
de_ * ie - e_comp) > eps ||
 
   82                std::abs(
dnb_ * inb - nb_comp) > eps ||
 
   83                std::abs(ns_comp) > eps || std::abs(x.
p - p_comp) > eps ||
 
   84                std::abs(
dq_ * iq - nq_comp) > eps) &&
 
   86             std::cout << 
"discrepancy: " << 
de_ * ie << 
" = " << e_comp << 
", " 
   87                       << 
dnb_ * inb << 
" = " << nb_comp << 
", " << x.
p << 
" = " 
   88                       << p_comp << 
", 0 = " << ns_comp << 
", " << 
dq_ * iq
 
   89                       << 
" = " << nq_comp << std::endl;
 
   90             table_consistency = 
false;
 
   91             goto finish_consistency_check;
 
   97 finish_consistency_check:
 
   99   if (!table_read_success || !table_consistency) {
 
  100     std::cout << 
"Compiling an EoS table..." << std::endl;
 
  101     const double ns = 0.0;
 
  102     for (
size_t ie = 0; ie < 
n_e_; ie++) {
 
  103       std::cout << ie << 
"/" << 
n_e_ << 
"\r" << std::flush;
 
  104       const double e = 
de_ * ie;
 
  105       for (
size_t inb = 0; inb < 
n_nb_; inb++) {
 
  106         const double nb = 
dnb_ * inb;
 
  107         for (
size_t iq = 0; iq < 
n_q_; iq++) {
 
  108           const double q = 
dq_ * iq;
 
  111           if (nb >= e || q >= e) {
 
  112             table_[
index(ie, inb, iq)] = {0.0, 0.0, 0.0, 0.0, 0.0};
 
  116           std::array<double, 4> init_approx;
 
  120             init_approx = {2.0 * x.
T - y.
T, 2.0 * x.
mub - y.
mub,
 
  122           } 
else if (iq >= 2) {
 
  125             init_approx = {2.0 * x.
T - y.
T, 2.0 * x.
mub - y.
mub,
 
  130           const std::array<double, 4> res =
 
  131               eos.
solve_eos(e, nb, ns, q, init_approx);
 
  132           const double T = res[0];
 
  133           const double mub = res[1];
 
  134           const double mus = res[2];
 
  135           const double muq = res[3];
 
  143     std::cout << 
"Saving table to file " << eos_savefile_name << std::endl;
 
  145     file.open(eos_savefile_name, std::ios::out);
 
  146     file << 
de_ << 
" " << 
dnb_ << 
" " << 
dq_ << std::endl;
 
  148     file << std::setprecision(7);
 
  150     for (
size_t ie = 0; ie < 
n_e_; ie++) {
 
  151       for (
size_t inb = 0; inb < 
n_nb_; inb++) {
 
  152         for (
size_t iq = 0; iq < 
n_q_; iq++) {
 
  154           file << x.
p << 
" " << x.
T << 
" " << x.
mub << 
" " << x.
mus << 
" " 
  155                << x.
muq << std::endl;
 
  164   const size_t ie = 
static_cast<size_t>(std::floor(e / 
de_));
 
  165   const size_t inb = 
static_cast<size_t>(std::floor(nb / 
dnb_));
 
  166   const size_t iq = 
static_cast<size_t>(std::floor(q / 
dq_));
 
  169     res = {-1.0, -1.0, -1.0, -1.0, -1.0};
 
  172     const double ae = e / 
de_ - ie;
 
  173     const double an = nb / 
dnb_ - inb;
 
  174     const double aq = q / 
dq_ - iq;
 
  198     : x_(gsl_vector_alloc(n_equations_)),
 
  200       account_for_resonance_widths_(account_for_width) {
 
  201   const gsl_multiroot_fsolver_type *solver_type;
 
  202   solver_type = gsl_multiroot_fsolver_hybrid;
 
  206         "Compilation of hadron gas EoS table requested with" 
  207         " account of resonance spectral functions. This is not " 
  208         "advised, as it will likely take a few days to finish." 
  209         " Besides, the effect of resonance widths is currently not " 
  210         "implemented for energy density computation, so the computed" 
  211         " table will be inconsistent anyways.");
 
  219   gsl_multiroot_fsolver_free(
solver_);
 
  225   double x = mu_over_T - m_over_T;
 
  234              : m_over_T * m_over_T * x * gsl_sf_bessel_Kn_scaled(2, m_over_T);
 
  238                                             double beta, 
double mub, 
double mus,
 
  240                                             bool account_for_width) {
 
  241   const double m_over_T = ptype.
mass() * 
beta;
 
  244   const double g = ptype.
spin() + 1;
 
  245   if (ptype.
is_stable() || !account_for_width) {
 
  250     const double m0 = ptype.
mass();
 
  253     const double u_min = std::atan(2.0 * (mth - m0) / w0);
 
  254     const double u_max = 0.5 * M_PI;
 
  256     const double result =
 
  257         g * 
integrate(u_min, u_max, [&](
double u) {
 
  260           const double tanu = std::tan(u);
 
  261           const double m = m0 + 0.5 * w0 * tanu;
 
  262           const double jacobian = 0.5 * w0 * (1.0 + tanu * tanu);
 
  271                                      double mub, 
double mus, 
double muq,
 
  272                                      bool account_for_width) {
 
  286   const double beta = 1.0 / T;
 
  292     const double z = ptype.mass() * 
beta;
 
  293     double x = 
beta * (mub * ptype.baryon_number() + mus * ptype.strangeness() +
 
  294                        muq * ptype.charge() - ptype.mass());
 
  299     const size_t g = ptype.spin() + 1;
 
  303                                   (3.0 * gsl_sf_bessel_Kn_scaled(2, z) +
 
  304                                    z * gsl_sf_bessel_K1_scaled(z));
 
  311                              bool account_for_width) {
 
  315   const double beta = 1.0 / T;
 
  329                                         double muq, 
bool account_for_width) {
 
  333   const double beta = 1.0 / T;
 
  341         ptype.baryon_number();
 
  348                                          double muq, 
bool account_for_width) {
 
  352   const double beta = 1.0 / T;
 
  367                                         double muq, 
bool account_for_width) {
 
  371   const double beta = 1.0 / T;
 
  398   const double max_mass = 5.0;  
 
  405     const double m0 = ptype.
mass();
 
  407         m0 * m0 * std::exp(-
beta * m0) * gsl_sf_bessel_Kn_scaled(2, m0 * 
beta) *
 
  410     constexpr 
int npoints = 31;
 
  411     double m_lower = mth, m_upper = max_mass, m_where_max = m0;
 
  413     for (
size_t n_iterations = 0; n_iterations < 2; n_iterations++) {
 
  414       const double dm = (m_upper - m_lower) / npoints;
 
  415       for (
size_t i = 1; i < npoints; i++) {
 
  416         m = m_lower + dm * i;
 
  417         const double thermal_factor =
 
  418             m * m * std::exp(-
beta * m) * gsl_sf_bessel_Kn_scaled(2, m * 
beta);
 
  426       m_lower = m_where_max - (m_where_max - m_lower) * 0.1;
 
  427       m_upper = m_where_max + (m_upper - m_where_max) * 0.1;
 
  436         const double thermal_factor =
 
  437             m * m * std::exp(-
beta * m) * gsl_sf_bessel_Kn_scaled(2, m * 
beta);
 
  443             ptype.
name(), 
" - maximum increased in",
 
  444             " sample_mass_thermal from ", max_ratio, 
" to ", q, 
", mass = ", m,
 
  445             " previously assumed maximum at m = ", m_where_max);
 
  458   double mus_u = mub + T;
 
  461   size_t iteration = 0;
 
  463   const size_t max_iteration = 50;
 
  465     mus = 0.5 * (mus_u + mus_l);
 
  473   } 
while (std::abs(rhos) > 
tolerance_ && iteration < max_iteration);
 
  474   if (iteration == max_iteration) {
 
  475     throw std::runtime_error(
"Solving rho_s = 0: too many iterations.");
 
  482   double e = 
reinterpret_cast<struct 
rparams *
>(params)->e;
 
  483   double nb = 
reinterpret_cast<struct 
rparams *
>(params)->nb;
 
  484   double ns = 
reinterpret_cast<struct 
rparams *
>(params)->ns;
 
  485   double nq = 
reinterpret_cast<struct 
rparams *
>(params)->nq;
 
  486   bool w = 
reinterpret_cast<struct 
rparams *
>(params)->account_for_width;
 
  488   const double T = gsl_vector_get(x, 0);
 
  489   const double mub = gsl_vector_get(x, 1);
 
  490   const double mus = gsl_vector_get(x, 2);
 
  491   const double muq = gsl_vector_get(x, 3);
 
  502   const double edens = 
reinterpret_cast<struct 
eparams *
>(params)->edens;
 
  511   int degeneracies_sum = 0.0;
 
  514       degeneracies_sum += ptype.spin() + 1;
 
  518   const double T_min = std::pow(e / 
prefactor_ / 6 / degeneracies_sum, 1. / 4.);
 
  520   const double T_max = 2.0;
 
  522   struct eparams parameters = {e};
 
  524   const gsl_root_fsolver_type *T = gsl_root_fsolver_brent;
 
  525   gsl_root_fsolver *e_solver;
 
  526   e_solver = gsl_root_fsolver_alloc(T);
 
  527   gsl_root_fsolver_set(e_solver, &F, T_min, T_max);
 
  529   int iter = 0, status, max_iter = 100;
 
  534     status = gsl_root_fsolver_iterate(e_solver);
 
  535     if (status != GSL_SUCCESS) {
 
  538     T_init = gsl_root_fsolver_root(e_solver);
 
  539     double x_lo = gsl_root_fsolver_x_lower(e_solver);
 
  540     double x_hi = gsl_root_fsolver_x_upper(e_solver);
 
  541     status = gsl_root_test_interval(x_lo, x_hi, 0.0, 0.001);
 
  542   } 
while (status == GSL_CONTINUE && iter < max_iter);
 
  544   if (status != GSL_SUCCESS) {
 
  545     std::stringstream err_msg;
 
  546     err_msg << 
"Solver of equation for temperature with e = " << e
 
  547             << 
" failed to converge. Maybe Tmax = " << T_max << 
" is too small?" 
  549     throw std::runtime_error(gsl_strerror(status) + err_msg.str());
 
  552   gsl_root_fsolver_free(e_solver);
 
  556   double n_only_baryons = 0.0;
 
  563   const double nb_scaled = nb / 
prefactor_ / (T_init * T_init * T_init);
 
  564   double mub_init = T_init * std::asinh(nb_scaled / n_only_baryons / 2.0);
 
  568   double n_only_charge_1_particles = 0.0;
 
  571       n_only_charge_1_particles +=
 
  575   const double q_scaled = nq / 
prefactor_ / (T_init * T_init * T_init);
 
  577       T_init * std::asinh(q_scaled / n_only_charge_1_particles / 2.0);
 
  581   std::array<double, 4> initial_approximation = {T_init, mub_init, 0.0,
 
  583   return initial_approximation;
 
  587     double e, 
double nb, 
double ns, 
double nq,
 
  588     std::array<double, 4> initial_approximation) {
 
  589   int residual_status = GSL_SUCCESS;
 
  596   gsl_vector_set(
x_, 0, initial_approximation[0]);
 
  597   gsl_vector_set(
x_, 1, initial_approximation[1]);
 
  598   gsl_vector_set(
x_, 2, initial_approximation[2]);
 
  599   gsl_vector_set(
x_, 3, initial_approximation[3]);
 
  601   gsl_multiroot_fsolver_set(
solver_, &f, 
x_);
 
  604     const auto iterate_status = gsl_multiroot_fsolver_iterate(
solver_);
 
  608     if (gsl_vector_get(
solver_->x, 0) < 0.015) {
 
  609       return {0.0, 0.0, 0.0, 0.0};
 
  613     if (iterate_status) {
 
  617   } 
while (residual_status == GSL_CONTINUE && iter < 1000);
 
  619   if (residual_status != GSL_SUCCESS) {
 
  620     std::stringstream solver_parameters;
 
  621     solver_parameters << 
"\nSolver run with " 
  622                       << 
"e = " << e << 
", nb = " << nb << 
", ns = " << ns
 
  624                       << 
", init. approx.: " << initial_approximation[0] << 
" " 
  625                       << initial_approximation[1] << 
" " 
  626                       << initial_approximation[2] << 
" " 
  627                       << initial_approximation[3] << std::endl;
 
  632   return {gsl_vector_get(
solver_->x, 0), gsl_vector_get(
solver_->x, 1),
 
  639   s << 
"iter = " << iter << 
"," 
  640     << 
" x = " << gsl_vector_get(
solver_->x, 0) << 
" " 
  641                << gsl_vector_get(
solver_->x, 1) << 
" " 
  642                << gsl_vector_get(
solver_->x, 2) << 
", " 
  643                << gsl_vector_get(
solver_->x, 3) << 
", " 
  644     << 
"f(x) = " << gsl_vector_get(
solver_->f, 0) << 
" " 
  645                  << gsl_vector_get(
solver_->f, 1) << 
" " 
  646                  << gsl_vector_get(
solver_->f, 2) << 
" " 
  647                  << gsl_vector_get(
solver_->f, 3) << std::endl;
 
Guard type that safely disables floating point traps for the scope in which it is placed.
 
std::vector< table_element > table_
Storage for the tabulated equation of state.
 
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...
 
size_t index(size_t ie, size_t inb, size_t inq) const
proper index in a 1d vector, where the 3d table is stored
 
double dnb_
Step in net-baryon density.
 
size_t n_q_
Number of steps in net-charge density.
 
double de_
Step in energy density.
 
EosTable(double de, double dnb, double dq, size_t n_e, size_t n_b, size_t n_q)
Sets up a table p/T/muB/mus/muQ versus (e, nb, nq), where e - energy density, nb - net baryon density...
 
size_t n_e_
Number of steps in energy density.
 
double dq_
Step in net-charge density.
 
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,...
 
size_t n_nb_
Number of steps in net-baryon density.
 
Class to handle the equation of state (EoS) of the hadron gas, consisting of all hadrons included in ...
 
gsl_multiroot_fsolver * solver_
 
static double net_charge_density(double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute net charge density.
 
static constexpr double prefactor_
Constant factor, that appears in front of many thermodyn. expressions.
 
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.
 
static double sample_mass_thermal(const ParticleType &ptype, double beta)
Sample resonance mass in a thermal medium.
 
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...
 
static double scaled_partial_density_auxiliary(double m_over_T, double mu_over_T)
Function used to avoid duplications in density calculations.
 
EosTable eos_table_
EOS Table to be used.
 
gsl_vector * x_
Variables used by gnu equation solver.
 
static double mus_net_strangeness0(double T, double mub, double muq)
Compute strangeness chemical potential, requiring that net strangeness = 0.
 
bool account_for_resonance_widths() const
If resonance spectral functions are taken into account.
 
static double density(double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute particle number density.
 
const bool tabulate_
Create an EoS table or not?
 
static bool is_eos_particle(const ParticleType &ptype)
Check if a particle belongs to the EoS.
 
static int set_eos_solver_equations(const gsl_vector *x, void *params, gsl_vector *f)
Interface EoS equations to be solved to gnu library.
 
std::string print_solver_state(size_t iter) const
Helpful printout, useful for debugging if gnu equation solving goes crazy.
 
static double e_equation(double T, void *params)
 
static double net_baryon_density(double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute net baryon density.
 
static double energy_density(double T, double mub, double mus, double muq)
Compute energy density.
 
static double net_strange_density(double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute net strangeness density.
 
const bool account_for_resonance_widths_
Use pole masses of resonances or integrate over spectral functions.
 
std::array< double, 4 > solve_eos_initial_approximation(double e, double nb, double nq)
Compute a reasonable initial approximation for solve_eos.
 
static constexpr size_t n_equations_
Number of equations in the system of equations to be solved.
 
HadronGasEos(bool tabulate, bool account_for_widths)
Constructor of HadronGasEos.
 
static double pressure(double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute pressure .
 
static constexpr double tolerance_
Precision of equation solving.
 
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.
 
A C++ interface for numerical integration in one dimension with the GSL CQUAD integration functions.
 
Particle type contains the static properties of a particle species.
 
double min_mass_spectral() const
The minimum mass of the resonance, where the spectral function is non-zero.
 
double spectral_function(double m) const
Full spectral function  of the resonance (relativistic Breit-Wigner distribution with mass-dependent ...
 
const std::string & name() const
 
int32_t charge() const
The charge of the particle.
 
static const ParticleTypeList & list_all()
 
double spectral_function_simple(double m) const
This one is the most simple form of the spectral function, using a Cauchy distribution (non-relativis...
 
double width_at_pole() const
 
unsigned int spin() const
 
int baryon_number() const
 
Collection of useful constants that are known at compile time.
 
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
 
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of  is .
 
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...
 
static Integrator integrate
 
T interpolate_trilinear(T ax, T ay, T az, T f1, T f2, T f3, T f4, T f5, T f6, T f7, T f8)
Perform a trilinear 1st order interpolation.
 
static constexpr int LResonances
 
constexpr double really_small
Numerical error tolerance.
 
Define the data structure for one element of the table.
 
double mub
Net baryochemical potential.
 
double muq
Net charge chemical potential.
 
double mus
Net strangeness potential.
 
Another structure for passing energy density to the gnu library.
 
A structure for passing equation parameters to the gnu library.