Version: SMASH-2.0
chemicalpotential.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2020-
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
11 
12 #include <gsl/gsl_errno.h>
13 #include <gsl/gsl_integration.h>
14 #include <gsl/gsl_multiroots.h>
15 #include <cmath>
16 #include <cstdlib>
17 #include <iostream>
18 #include <sstream>
19 
20 #include "smash/constants.h"
21 #include "smash/distributions.h"
22 #include "smash/logging.h"
23 
24 namespace smash {
25 
30  double degeneracy, double mass, double temperature,
31  double effective_chemical_potential, double statistics,
32  Integrator *integrator) {
33  const auto integral = (*integrator)(0.0, 1.0, [&](double x) {
34  return ((1.0 - x) * (1.0 - x) / (x * x * x * x)) *
35  juttner_distribution_func((1.0 - x) / x, mass, temperature,
36  effective_chemical_potential, statistics);
37  });
38  const double integrated_number_density =
39  (degeneracy / (2.0 * M_PI * M_PI)) * integral;
40 
41  return integrated_number_density;
42 }
43 
44 /*
45  * Root equations and procedure for finding the effective chemical potential
46  * for a given particle species.
47  */
48 
50  double degeneracy, double mass, double number_density, double temperature,
51  double effective_chemical_potential, double statistics,
52  Integrator *integrator) {
53  const double integrated_number_density =
54  density_one_species(degeneracy, mass, temperature,
55  effective_chemical_potential, statistics, integrator);
56 
57  return number_density - integrated_number_density;
58 }
59 
61  const gsl_vector *roots_array, void *parameters, gsl_vector *function) {
62  struct ParametersForChemPotSolver *par =
63  static_cast<ParametersForChemPotSolver *>(parameters);
64 
65  const double degeneracy = (par->degeneracy);
66  const double mass = (par->mass);
67  const double number_density = (par->number_density);
68  const double temperature = (par->temperature);
69  const double statistics = (par->statistics);
70  Integrator *integrator = (par->integrator);
71 
72  const double effective_chemical_potential = gsl_vector_get(roots_array, 0);
73 
74  gsl_vector_set(function, 0,
76  degeneracy, mass, number_density, temperature,
77  effective_chemical_potential, statistics, integrator));
78 
79  return GSL_SUCCESS;
80 }
81 
83  unsigned int iter, gsl_multiroot_fsolver *solver) {
84  printf(
85  "\n***\nfind_effective_chemical_potential(): iter = %3u \t"
86  "x = % .3f \t"
87  "f(x) = % .3e \n",
88  iter, gsl_vector_get(solver->x, 0), gsl_vector_get(solver->f, 0));
89 }
90 
92  double degeneracy, double mass, double number_density, double temperature,
93  double statistics, double mu_initial_guess, double solution_precision,
94  Integrator *integrator, double *effective_chemical_potential) {
95  const gsl_multiroot_fsolver_type *Solver_name;
96  gsl_multiroot_fsolver *Root_finder;
97 
98  int status;
99  size_t iter = 0;
100 
101  const size_t problem_dimension = 1;
102 
103  struct ParametersForChemPotSolver parameters = {
104  degeneracy, mass, number_density, temperature, statistics, integrator};
105 
106  gsl_multiroot_function EffectiveChemicalPotential = {
109  problem_dimension, &parameters};
110 
111  double roots_array_initial[problem_dimension] = {mu_initial_guess};
112 
113  gsl_vector *roots_array = gsl_vector_alloc(problem_dimension);
114  gsl_vector_set(roots_array, 0, roots_array_initial[0]);
115 
116  Solver_name = gsl_multiroot_fsolver_hybrids;
117  Root_finder = gsl_multiroot_fsolver_alloc(Solver_name, problem_dimension);
118  gsl_multiroot_fsolver_set(Root_finder, &EffectiveChemicalPotential,
119  roots_array);
120 
121  // print_state_effective_chemical_potential (iter, Root_finder);
122 
123  do {
124  iter++;
125 
126  /*
127  * gsl_multiroot_fsolver_iterate returns either 0 for a correct behavior,
128  * or an error code (a positive integer) when the solver is stuck
129  */
130  status = gsl_multiroot_fsolver_iterate(Root_finder);
131 
132  // print_state_effective_chemical_potential (iter, Root_finder);
133 
134  /*
135  * Check whether the solver is stuck
136  */
137  if (status) {
138  std::cout << "\nGSL error message:\n"
139  << gsl_strerror(status) << "\n\n"
140  << std::endl;
141  const double conversion_factor =
143  logg[LogArea::Main::id].warn(
144  "\n\nThe GSL solver\nfind_effective_chemical_potential\nis stuck!"
145  "\n\nInput parameters:"
146  "\n degeneracy = ",
147  degeneracy, "\n mass [GeV] = ", mass,
148  "\nnumber_density [fm^-3] = ", number_density / (conversion_factor),
149  "\n temperature [GeV] = ", temperature,
150  "\n statistics = ", statistics,
151  "\n solution_precision = ", solution_precision,
152  "\n\n"
153  "Initialization cannot continue without calculating the "
154  "chemical potential. \nTry adjusting the initial "
155  "guess or the solution precision.\n\n\n");
156  throw std::runtime_error(
157  "Chemical potential calculation returned no result.\n\n");
158  continue;
159  }
160 
161  status = gsl_multiroot_test_residual(Root_finder->f, solution_precision);
162 
163  if (status == GSL_SUCCESS) {
164  effective_chemical_potential[0] = gsl_vector_get(Root_finder->x, 0);
165  }
166  } while (status == GSL_CONTINUE && iter < 100000);
167 
168  gsl_multiroot_fsolver_free(Root_finder);
169  gsl_vector_free(roots_array);
170 
171  return 0;
172 }
173 
174 /*
175  * A convenience wrapper for finding the effective chemical potential for a
176  * given particle species and performing sanity checks.
177  */
178 
180  double degeneracy, double mass, double number_density, double temperature,
181  double statistics, double solution_precision) {
182  assert(temperature > 0); // zero temperature case is not considered here
183  assert(degeneracy > 0);
184  assert(mass > 0);
185  /*
186  * The initial guess for the GSL chemical potential finding
187  * procedure; the guess has to be different for Bose and Fermi
188  * particles.
189  */
190  double initial_guess = 0.0;
191  if (statistics == -1.0) {
192  /*
193  * Such initial guess allows one to sample really close to the Bose
194  * condensate region; at the same time, it works fine in other regions.
195  */
196  initial_guess = 0.999999 * mass;
197  } else {
198  initial_guess = 1.05 * mass;
199  }
200 
202  const double integration_precision = 0.1 * solution_precision;
203  integrator_.set_precision(integration_precision, integration_precision);
204 
205  /*
206  * Array for the GSL chemical potential finder.
207  * Use of array is motivated by anticipating a generalization or overloading
208  * of this solver to include effective mass calculation, which will lead to
209  * multidimensional root finding, in which case the result is best passed as
210  * an array.
211  */
212  double chemical_potential[1];
213  chemical_potential[0] = 0.0;
214 
215  /*
216  * Call the GSL effective chemical potential finding procedure.
217  */
219  degeneracy, mass, number_density, temperature, statistics, initial_guess,
220  solution_precision, &integrator_, chemical_potential);
221 
222  /*
223  * Sanity checks are performed for the obtained value of the chemical
224  * potential .
225  */
226 
227  /*
228  * Check that the calculated chemical potential reproduces the input number
229  * density within acceptable error.
230  */
231  // precision for number density in units of fm^-3
232  const double precision_fm = 1e-3;
233  const double conversion_factor = smash::hbarc * smash::hbarc * smash::hbarc;
234  double nDensityCheck =
235  density_one_species(degeneracy, mass, temperature, chemical_potential[0],
236  statistics, &integrator_);
237 
238  if (abs((number_density - nDensityCheck) / conversion_factor) >
239  precision_fm) {
240  logg[LogArea::Main::id].warn(
241  "\n\nThe calculated chemical potential = ", chemical_potential[0],
242  " [GeV] does not reproduce the input number density to within ",
243  precision_fm,
244  "!"
245  "\nnumber_density [GeV^3] = ",
246  number_density, "\n nDensityCheck [GeV^3] = ", nDensityCheck,
247  "\nnumber_density [fm^-3] = ", number_density / (conversion_factor),
248  "\n nDensityCheck [fm^-3] = ", nDensityCheck / (conversion_factor),
249  "\n\n"
250  "Input parameters:"
251  "\n degeneracy = ",
252  degeneracy, "\n mass [GeV] = ", mass,
253  "\nnumber_density [fm^-3] = ", number_density / (conversion_factor),
254  "\n temperature [GeV] = ", temperature,
255  "\n statistics = ", statistics,
256  "\n solution_precision = ", solution_precision,
257  "\n\n"
258  "Initialization cannot continue without a correct "
259  "calculation of the chemical potential."
260  "\nTry adjusting the initial guess or the solution precision.\n\n\n");
261  throw std::runtime_error(
262  "Chemical potential calculation does not reproduce the "
263  "input number density.\n\n");
264  }
265 
266  /*
267  * Check if the obtained value of the effective chemical potential indicates
268  * that the number density is such that for bosons one has encountered the
269  * Bose-Einstein condensate. We need mu < mass in order for the system NOT to
270  * be in the Bose-Einstein condensate region.
271  */
272  if ((statistics == -1) && (chemical_potential[0] > mass)) {
273  logg[LogArea::Main::id].warn(
274  "\n\nThe calculated chemical potential indicates the "
275  "input number density is such that Bose-Einstein "
276  "condensate is encountered."
277  "Input parameters:"
278  "\n degeneracy = ",
279  degeneracy, "\n mass [GeV] = ", mass,
280  "\nnumber_density [fm^-3] = ", number_density / (conversion_factor),
281  "\n temperature [GeV] = ", temperature,
282  "\n statistics = ", statistics,
283  "\n solution_precision = ", solution_precision,
284  "\n\n"
285  "Initialization cannot proceed with a pathological "
286  "distribution function leading to the Bose-Einstein "
287  "condensate. \nTry increasing the temperature or "
288  "decreasing the number density.\n\n\n");
289  throw std::runtime_error(
290  "Chemical potential calculation indicates that the Bose-Einstein "
291  "condensate is produced.");
292  }
293 
294  /*
295  * Check if the distribution is pathological, i.e., has negative values
296  * for low momenta (Bose statistics, in the Bose-Einstein condensate regime,
297  * may produce pathological distributions for which f(p) < 0 ).
298  */
300  const double small_p = 0.005;
301  const double distribution_at_small_p = juttner_distribution_func(
302  small_p, mass, temperature, chemical_potential[0], statistics);
303  if (distribution_at_small_p < 0.0) {
304  logg[LogArea::Main::id].warn(
305  "\n\nNegative values of the distribution function at "
306  "small momenta indicate that Bose-Einstein "
307  "condensate is encountered."
308  "Input parameters:"
309  "\n degeneracy = ",
310  degeneracy, "\n mass [GeV] = ", mass,
311  "\nnumber_density [fm^-3] = ", number_density / (conversion_factor),
312  "\n temperature [GeV] = ", temperature,
313  "\n statistics = ", statistics,
314  "\n solution_precision = ", solution_precision, "\n\nf(p=", small_p,
315  ") = ", distribution_at_small_p,
316  "\n\n"
317  "Initialization cannot proceed with a pathological "
318  "distribution function leading to the Bose-Einstein "
319  "condensate. \nTry increasing the temperature or "
320  "decreasing the number density.\n\n\n");
321  throw std::runtime_error(
322  "Negative values of the distribution function at low momenta "
323  "indicate that the Bose-Einstein condensate is produced.");
324  }
325 
326  return chemical_potential[0];
327 }
328 
329 } // namespace smash
smash::ChemicalPotentialSolver::integrator_
Integrator integrator_
A wrapper for gsl numerical integration.
Definition: chemicalpotential.h:184
smash
Definition: action.h:24
smash::ChemicalPotentialSolver::ParametersForChemPotSolver::degeneracy
double degeneracy
degeneracy g of the particle species
Definition: chemicalpotential.h:61
smash::ChemicalPotentialSolver::effective_chemical_potential
double effective_chemical_potential(double degeneracy, double mass, double number_density, double temperature, double statistics, double solution_precision)
Convenience wrapper for finding the effective chemical potential for a given particle species and per...
Definition: chemicalpotential.cc:179
smash::ChemicalPotentialSolver::density_one_species
static double density_one_species(double degeneracy, double mass, double temperature, double effective_chemical_potential, double statistics, Integrator *integrator)
Vector number density of one particle species, obtained through integrating the Juttner distribution ...
Definition: chemicalpotential.cc:29
smash::Integrator::set_precision
void set_precision(double absolute, double relative)
Set precision for the absolute and relative error of the integration.
Definition: integrate.h:168
smash::ChemicalPotentialSolver::ParametersForChemPotSolver::mass
double mass
(pole) mass m of the particle species
Definition: chemicalpotential.h:64
smash::ChemicalPotentialSolver::root_equation_effective_chemical_potential_for_GSL
static int root_equation_effective_chemical_potential_for_GSL(const gsl_vector *roots_array, void *parameters, gsl_vector *function)
Root equation for finding the value of the effective chemical potential for one particle species,...
Definition: chemicalpotential.cc:60
smash::ChemicalPotentialSolver::print_state_effective_chemical_potential
static void print_state_effective_chemical_potential(unsigned int iter, gsl_multiroot_fsolver *solver)
A GSL utility which allows for printing out the status of the solver during the root finding procedur...
Definition: chemicalpotential.cc:82
smash::Integrator
A C++ interface for numerical integration in one dimension with the GSL CQUAD integration functions.
Definition: integrate.h:106
smash::ChemicalPotentialSolver::ParametersForChemPotSolver::integrator
Integrator * integrator
wrapper for gsl numerical integration
Definition: chemicalpotential.h:79
smash::hbarc
constexpr double hbarc
GeV <-> fm conversion factor.
Definition: constants.h:25
smash::logg
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
smash::ChemicalPotentialSolver::root_equation_effective_chemical_potential
static double root_equation_effective_chemical_potential(double degeneracy, double mass, double number_density, double temperature, double effective_chemical_potential, double statistics, Integrator *integrator)
Root equation for finding the value of the effective chemical potential for one particle species.
Definition: chemicalpotential.cc:49
smash::ChemicalPotentialSolver::ParametersForChemPotSolver::statistics
double statistics
statistics quantum statistics of the particles species (+1 for Fermi, -1 for Bose,...
Definition: chemicalpotential.h:76
smash::ChemicalPotentialSolver::ParametersForChemPotSolver::temperature
double temperature
temperature T of the system [GeV]
Definition: chemicalpotential.h:70
smash::juttner_distribution_func
double juttner_distribution_func(double momentum_radial, double mass, double temperature, double effective_chemical_potential, double statistics)
Relativistic Juttner distribution function is just a convenience wrapper for displaying Fermi,...
Definition: distributions.cc:79
smash::ChemicalPotentialSolver::find_effective_chemical_potential
static int find_effective_chemical_potential(double degeneracy, double mass, double number_density, double temperature, double statistics, double mu_initial_guess, double solution_precision, Integrator *integrator, double *effective_chemical_potential)
A GSL root solver for finding the effective chemical potential.
Definition: chemicalpotential.cc:91
chemicalpotential.h
distributions.h
smash::ChemicalPotentialSolver::ParametersForChemPotSolver::number_density
double number_density
number density n of the particle species [GeV^3]
Definition: chemicalpotential.h:67
constants.h
logging.h
smash::ChemicalPotentialSolver::ParametersForChemPotSolver
Struct, root equations, and procedure for finding the effective chemical potential for a given partic...
Definition: chemicalpotential.h:59