Thermal-FIST 1.6
Package for hadron resonance gas model applications
Loading...
Searching...
No Matches
EffectiveMassModel.cpp
Go to the documentation of this file.
2
3#include <iostream>
4#include <vector>
5
6using namespace std;
7
8namespace thermalfist {
11 m_Particle(particle), m_FieldPressure(FieldPressure)
12 {
13 m_T = -1.;
14 m_Mu = 0.;
15 m_isSolved = false;
16 m_isBEC = false;
17 m_TBEC = 0.050;
18 m_Meff = m_Particle.Mass();
19 m_Pressure = m_Density = m_DensityScalar = m_EntropyDensity = m_Chi2 = 0.;
20 }
21
23 {
24 if (m_FieldPressure != NULL)
25 delete m_FieldPressure;
26 m_FieldPressure = NULL;
27 }
28
31 m_Particle(other.m_Particle), m_FieldPressure(NULL)
32 {
33 m_T = other.m_T;
34 m_Mu = other.m_Mu;
35 m_isSolved = other.m_isSolved;
36 m_isBEC = other.m_isBEC;
37 m_TBEC = other.m_TBEC;
38 m_Meff = other.m_Meff;
39 m_Pressure = other.m_Pressure;
40 m_Density = other.m_Density;
41 m_DensityScalar = other.m_DensityScalar;
42 m_EntropyDensity = other.m_EntropyDensity;
43 m_Chi2 = other.m_Chi2;
44
45 // Use previous value of TBEC as starting guess
46 m_FieldPressure = other.m_FieldPressure->clone();
47 }
48
49 double EffectiveMassModel::ComputeTBEC(double Mu, double TBECinit) const
50 {
51 // Assume effective mass always larger than vacuum mass (repulsive interaction only)
52 if (m_Particle.Statistics() != -1 || Mu <= m_Particle.Mass())
53 return 0.0;
54
55 if ((Mu - m_Particle.Mass()) < 1.e-9)
56 return 0.;
57
58 // Use previous value of TBEC as strating guess
59 if (TBECinit < 0.)
60 TBECinit = m_TBEC;
61
62 // Use small non-zero initial value of TBEC
63 if (TBECinit == 0.0)
64 TBECinit = 0.001;
65
66 BroydenEquationsEMMTBEC eqs(this, Mu);
67 Broyden broydn(&eqs);
68
70
71 vector<double> vars(1, log(TBECinit / m_Particle.Mass()));
72 vars = broydn.Solve(vars, &criterium);
73
74 double TBEC = m_Particle.Mass() * exp(vars[0]);
75
76 // Fit did not converge, assume there is no condensation for given chemical potential
77 if (broydn.Iterations() == broydn.MaxIterations() || vars[0] != vars[0] || std::isinf(vars[0]))
78 TBEC = 0.;
79
80 return TBEC;
81 }
82
83 void EffectiveMassModel::SetParameters(double T, double Mu)
84 {
85 if (m_T == 0.) {
86 m_TBEC = 0.;
87 m_isBEC = (Mu > m_Particle.Mass());
88 }
89 else if (m_Particle.Statistics() == -1 && (m_T < 0. || Mu != m_Mu)) {
90 m_TBEC = ComputeTBEC(Mu);
91 m_isBEC = (T <= m_TBEC);
92 }
93
94 if (T != m_T || Mu != m_Mu)
95 m_isSolved = false;
96
97 m_T = T;
98 m_Mu = Mu;
99 }
100
101 void EffectiveMassModel::SolveMeff(double meffinit)
102 {
103 if (!m_isSolved) {
104 if (m_T == 0.0) {
105 if (!IsBECPhase())
106 m_Meff = m_Particle.Mass();
107 else
108 m_Meff = m_Mu;
109 m_isSolved = true;
110 return;
111 }
112 if (!IsBECPhase()) {
113 if (meffinit < 0.)
114 meffinit = m_Meff;
115
116 if (std::isnan(meffinit))
117 meffinit = m_Particle.Mass();
118
119 BroydenEquations* eqs;
120 if (m_Particle.Statistics() == -1 && m_Mu > m_Particle.Mass())
122 else
123 eqs = new BroydenEquationsEMMMeff(this);
124 Broyden broydn(eqs);
125
127
128 vector<double> vars(1, meffinit);
129 vars = broydn.Solve(vars, &criterium);
130
131 if (m_Particle.Statistics() == -1 && m_Mu > m_Particle.Mass())
132 m_Meff = m_Mu * (1. + exp(vars[0]));
133 else
134 m_Meff = vars[0];
135
136 delete eqs;
137 }
138 else {
139 m_Meff = m_Mu;
140 }
141 m_isSolved = true;
142 }
143 }
144
146 {
147 if (!IsSolved())
148 return 0.0;
149
150 if (m_T == 0.0) {
151 if (IsBECPhase())
152 return m_FieldPressure->pf(m_Meff);
153 else
154 return 0.;
155 }
156
158 params.T = m_T;
159
160 return IdealGasFunctions::IdealGasQuantity(IdealGasFunctions::Pressure, IdealGasFunctions::Quadratures, m_Particle.Statistics(), m_T, m_Mu, m_Meff, m_Particle.Degeneracy())
161 + m_FieldPressure->pf(m_Meff);
162 }
163
165 {
166 if (!IsSolved())
167 return 0.0;
168
169 if (m_T == 0.0) {
170 if (IsBECPhase())
171 return m_FieldPressure->Dpf(m_Meff);
172 else
173 return 0.;
174 }
175
176 if (!IsBECPhase()) {
177 return IdealGasFunctions::IdealGasQuantity(IdealGasFunctions::ParticleDensity, IdealGasFunctions::Quadratures, m_Particle.Statistics(), m_T, m_Mu, m_Meff, m_Particle.Degeneracy());
178 }
179 else {
180 return IdealGasFunctions::IdealGasQuantity(IdealGasFunctions::ParticleDensity, IdealGasFunctions::Quadratures, m_Particle.Statistics(), m_T, m_Mu, m_Meff, m_Particle.Degeneracy())
181 - IdealGasFunctions::IdealGasQuantity(IdealGasFunctions::ScalarDensity, IdealGasFunctions::Quadratures, m_Particle.Statistics(), m_T, m_Mu, m_Meff, m_Particle.Degeneracy())
182 + m_FieldPressure->Dpf(m_Meff);
183 }
184 }
185
187 {
188 if (!IsSolved())
189 return 0.0;
190
191 if (m_T == 0.0)
192 return 0.;
193
194 return IdealGasFunctions::IdealGasQuantity(IdealGasFunctions::EntropyDensity, IdealGasFunctions::Quadratures, m_Particle.Statistics(), m_T, m_Mu, m_Meff, m_Particle.Degeneracy());
195 }
196
198 {
199 if (!IsSolved())
200 return 0.0;
201
202 return -Pressure() + m_T * EntropyDensity() + m_Mu * Density();
203 }
204
205 double EffectiveMassModel::Quantity(IdealGasFunctions::Quantity quantity, double T, double mu)
206 {
207 SetParameters(T, mu);
208 SolveMeff();
209
211 return Density();
212
213 if (quantity == IdealGasFunctions::EnergyDensity)
214 return EnergyDensity();
215
216 if (quantity == IdealGasFunctions::EntropyDensity)
217 return EntropyDensity();
218
219 if (quantity == IdealGasFunctions::Pressure)
220 return Pressure();
221
222 // Chi2: evaluate using numerical derivative
223 if (quantity == IdealGasFunctions::chi2difull) {
224 double dmu = 0.001 * m_Particle.Mass();
225 double n1 = Quantity(IdealGasFunctions::ParticleDensity, T, mu - 0.5 * dmu);
226 double n2 = Quantity(IdealGasFunctions::ParticleDensity, T, mu + 0.5 * dmu);
227 SetParameters(T, mu);
228 double ret = (n2 - n1) / dmu;
229 ret /= xMath::GeVtoifm3();
230 return ret;
231 }
232
233 // Chi3: evaluate using numerical derivative
234 if (quantity == IdealGasFunctions::chi3difull) {
235 double dmu = 0.001 * m_Particle.Mass();
237 double nm1 = Quantity(IdealGasFunctions::ParticleDensity, T, mu - dmu);
238 double np1 = Quantity(IdealGasFunctions::ParticleDensity, T, mu + dmu);
239 double ret = (np1 - 2.*n0 + nm1) / dmu / dmu;
240 SetParameters(T, mu);
241 ret /= xMath::GeVtoifm3();
242 return ret;
243 }
244
245 // Chi4: evaluate using numerical derivative
246 if (quantity == IdealGasFunctions::chi4difull) {
247 double dmu = 0.001 * m_Particle.Mass();
248 //double n0 = Quantity(IdealGasFunctions::ParticleDensity, T, mu);
249 double nm2 = Quantity(IdealGasFunctions::ParticleDensity, T, mu - 2. * dmu);
250 double nm1 = Quantity(IdealGasFunctions::ParticleDensity, T, mu - dmu);
251 double np1 = Quantity(IdealGasFunctions::ParticleDensity, T, mu + dmu);
252 double np2 = Quantity(IdealGasFunctions::ParticleDensity, T, mu + 2. * dmu);
253 double ret = (0.5 * np2 - np1 + nm1 - 0.5 * nm2) / dmu / dmu / dmu;
254 SetParameters(T, mu);
255 ret /= xMath::GeVtoifm3();
256 return ret;
257 }
258
259 if (quantity == IdealGasFunctions::chi2) {
260 return Quantity(IdealGasFunctions::chi2difull, T, mu) / T / T;
261 }
262
263 if (quantity == IdealGasFunctions::chi3) {
264 return Quantity(IdealGasFunctions::chi3difull, T, mu) / T;
265 }
266
267 if (quantity == IdealGasFunctions::chi4) {
269 }
270
271 // Temperature derivatives: dQ/dT = (dQ^id/dT)|_{m*} + (dQ^id/dm*)|_T * dm*/dT
272 // In BEC phase m* = mu (fixed), so dm*/dT = 0
273
274 if (quantity == IdealGasFunctions::dndT) {
275 if (m_T == 0.0)
276 return 0.;
277
278 if (!IsBECPhase()) {
279 // Normal phase: dn/dT = (dn^id/dT)|_{m*} + (dn^id/dm*) * dm*/dT
281 m_Particle.Statistics(), m_T, m_Mu, m_Meff, m_Particle.Degeneracy());
283 return dndT_fixedm + dndm * DmeffDT();
284 }
285 else {
286 // BEC phase: n = n^id - rho_scalar^id + p_f'(m*), with m* = mu fixed
287 // dn/dT = (dn^id/dT)|_{m*} - (drho_scalar^id/dT)|_{m*}
289 m_Particle.Statistics(), m_T, m_Mu, m_Meff, m_Particle.Degeneracy());
290 // d(rho_scalar)/dT at fixed m* via finite differences
291 double dT = 1.e-4 * m_T;
293 m_Particle.Statistics(), m_T + 0.5 * dT, m_Mu, m_Meff, m_Particle.Degeneracy());
295 m_Particle.Statistics(), m_T - 0.5 * dT, m_Mu, m_Meff, m_Particle.Degeneracy());
296 double drhosdT = (rhos_p - rhos_m) / dT;
297 return dndT_fixedm - drhosdT;
298 }
299 }
300
301 if (quantity == IdealGasFunctions::d2ndT2) {
302 // Use numerical finite differences of dndT
303 if (m_T == 0.0)
304 return 0.;
305 double dT = 1.e-4 * m_T;
306 double dndT_p = Quantity(IdealGasFunctions::dndT, T + 0.5 * dT, mu);
307 double dndT_m = Quantity(IdealGasFunctions::dndT, T - 0.5 * dT, mu);
308 SetParameters(T, mu);
309 SolveMeff();
310 return (dndT_p - dndT_m) / dT;
311 }
312
313 if (quantity == IdealGasFunctions::dedT) {
314 if (m_T == 0.0)
315 return 0.;
316 // de/dT = T * ds/dT + s + mu * dn/dT (from e = -P + Ts + mu*n)
317 // Or use numerical finite differences for simplicity and consistency
318 double dT = 1.e-4 * m_T;
319 double e_p = Quantity(IdealGasFunctions::EnergyDensity, T + 0.5 * dT, mu);
320 double e_m = Quantity(IdealGasFunctions::EnergyDensity, T - 0.5 * dT, mu);
321 SetParameters(T, mu);
322 SolveMeff();
323 return (e_p - e_m) / dT;
324 }
325
326 if (quantity == IdealGasFunctions::dedmu) {
327 // de/dmu at fixed T: use finite differences
328 double dmu = 0.001 * m_Particle.Mass();
329 double e_p = Quantity(IdealGasFunctions::EnergyDensity, T, mu + 0.5 * dmu);
330 double e_m = Quantity(IdealGasFunctions::EnergyDensity, T, mu - 0.5 * dmu);
331 SetParameters(T, mu);
332 SolveMeff();
333 return (e_p - e_m) / dmu;
334 }
335
336 if (quantity == IdealGasFunctions::dchi2dT) {
337 // dchi2/dT where chi2 = T^{-2} * dn/dmu (dimensionless)
338 // Use numerical finite differences of chi2
339 if (m_T == 0.0)
340 return 0.;
341 double dT = 1.e-4 * m_T;
342 double chi2_p = Quantity(IdealGasFunctions::chi2, T + 0.5 * dT, mu);
343 double chi2_m = Quantity(IdealGasFunctions::chi2, T - 0.5 * dT, mu);
344 SetParameters(T, mu);
345 SolveMeff();
346 return (chi2_p - chi2_m) / dT;
347 }
348
349 if (quantity == IdealGasFunctions::dsdT) {
350 if (m_T == 0.0)
351 return 0.;
352
353 // ds/dT = (ds^id/dT)|_{m*} + (ds^id/dm*)|_T * dm*/dT
354 // The entropy is s = s^id(T, mu, m*) regardless of BEC phase
355 // In BEC phase m* = mu (fixed), dm*/dT = 0
357 m_Particle.Statistics(), m_T, m_Mu, m_Meff, m_Particle.Degeneracy());
358 if (!IsBECPhase()) {
360 return dsdT_fixedm + dsdm * DmeffDT();
361 }
362 else {
363 return dsdT_fixedm;
364 }
365 }
366
367 throw std::runtime_error("**ERROR** EffectiveMassModel::Quantity(): Calculate " + std::to_string(static_cast<int>(quantity)) + " quantity is not implemented!");
368
369 return 0.0;
370 }
371
373 {
374 if (!IsSolved() || m_T == 0.0)
375 return 0.;
376
377 // In BEC phase, m* = mu which is independent of T
378 if (IsBECPhase())
379 return 0.;
380
381 // Gap equation: p_f'(m*) = rho_scalar(T, mu, m*)
382 // Implicit differentiation:
383 // p_f''(m*) * dm*/dT = (d rho_scalar/dT)|_{m*} + (d rho_scalar/dm*)|_T * dm*/dT
384 // => dm*/dT = (d rho_scalar/dT)|_{m*} / [p_f''(m*) - (d rho_scalar/dm*)|_T]
385
386 // d rho_scalar / dT at fixed m*
387 double dT = 1.e-4 * m_T;
389 m_Particle.Statistics(), m_T + 0.5 * dT, m_Mu, m_Meff, m_Particle.Degeneracy());
391 m_Particle.Statistics(), m_T - 0.5 * dT, m_Mu, m_Meff, m_Particle.Degeneracy());
392 double drhosdT = (rhos_p - rhos_m) / dT;
393
394 // d rho_scalar / dm* at fixed T
396
397 double D2pf = m_FieldPressure->D2pf(m_Meff);
398 double denom = D2pf - drhosdm;
399
400 // If denominator is too small, the gap equation is degenerate
401 if (std::abs(denom) < 1.e-20)
402 return 0.;
403
404 return drhosdT / denom;
405 }
406
408 {
409 if (!IsSolved() || m_T == 0.0)
410 return 0.;
411
412 double dm = 1.e-4 * m_Meff;
413 if (dm < 1.e-8)
414 dm = 1.e-8;
415
417 m_Particle.Statistics(), m_T, m_Mu, m_Meff + 0.5 * dm, m_Particle.Degeneracy());
419 m_Particle.Statistics(), m_T, m_Mu, m_Meff - 0.5 * dm, m_Particle.Degeneracy());
420
421 return (Q_p - Q_m) / dm;
422 }
423
424 std::vector<double> EffectiveMassModel::BroydenEquationsEMMTBEC::Equations(const std::vector<double> &x)
425 {
426 double TBEC = m_EMM->m_Particle.Mass() * exp(x[0]);
427 double ret = m_EMM->m_FieldPressure->Dpf(m_MuBEC) /
428 IdealGasFunctions::IdealGasQuantity(IdealGasFunctions::ScalarDensity, IdealGasFunctions::Quadratures, m_EMM->m_Particle.Statistics(), TBEC, m_MuBEC, m_MuBEC, m_EMM->m_Particle.Degeneracy())
429 - 1.;
430 return std::vector<double>(1, ret);
431 }
432
433 std::vector<double> EffectiveMassModel::BroydenEquationsEMMMeff::Equations(const std::vector<double>& x)
434 {
435 double ret = m_EMM->m_FieldPressure->Dpf(x[0]) /
436 IdealGasFunctions::IdealGasQuantity(IdealGasFunctions::ScalarDensity, IdealGasFunctions::Quadratures, m_EMM->m_Particle.Statistics(), m_EMM->m_T, m_EMM->m_Mu, x[0], m_EMM->m_Particle.Degeneracy())
437 - 1.;
438 return std::vector<double>(1, ret);
439 }
440
441 std::vector<double> EffectiveMassModel::BroydenEquationsEMMMeffConstrained::Equations(const std::vector<double>& x)
442 {
443 double meff = m_EMM->m_Mu * (1. + exp(x[0]));
444 double ret = m_EMM->m_FieldPressure->Dpf(meff) /
445 IdealGasFunctions::IdealGasQuantity(IdealGasFunctions::ScalarDensity, IdealGasFunctions::Quadratures, m_EMM->m_Particle.Statistics(), m_EMM->m_T, m_EMM->m_Mu, meff, m_EMM->m_Particle.Degeneracy())
446 - 1.;
447 return std::vector<double>(1, ret);
448 }
449
450
452 {
453 if (!IsSolved() || !IsBECPhase())
454 return 0.0;
455
456 double n0 = m_FieldPressure->Dpf(m_Meff);
457 if (m_T != 0.0)
458 n0 -= IdealGasFunctions::IdealGasQuantity(IdealGasFunctions::ScalarDensity, IdealGasFunctions::Quadratures, m_Particle.Statistics(), m_T, m_Mu, m_Meff, m_Particle.Degeneracy());
459
460 return n0 / Density();
461 }
462
463}
Header with effective mass model implementation, including the Bose-condensed phase.
map< string, double > params
Sub-class where it is determined whether the required accuracy is achieved in the Broyden's method.
Definition Broyden.h:144
Abstract class which defines the system of non-linear equations to be solved by the Broyden's method.
Definition Broyden.h:32
Class implementing the Broyden method to solve a system of non-linear equations.
Definition Broyden.h:132
virtual std::vector< double > Solve(const std::vector< double > &x0, BroydenSolutionCriterium *solcrit=NULL, int max_iterations=MAX_ITERS)
Definition Broyden.cpp:83
int Iterations() const
Definition Broyden.h:229
int MaxIterations() const
Definition Broyden.h:234
Base class implementing field pressure contribution function in the effective mass model....
virtual EMMFieldPressure * clone() const
Creates a clone of this EMMFieldPressure object.
Class implementing the effective mass model gap equation with constraints. Uses variable transformati...
std::vector< double > Equations(const std::vector< double > &x)
Implements the equations to be solved.
Class implementing the effective mass model gap equation. To be solved using Broyden's method.
std::vector< double > Equations(const std::vector< double > &x)
Implements the equations to be solved.
Class implementing the effective mass model equation to determine BEC onset. To be solved using Broyd...
std::vector< double > Equations(const std::vector< double > &x)
Implements the equations to be solved.
double ComputeTBEC(double Mu, double TBECinit=-1.) const
Calculates the temperature of BEC formation for a given chemical potential.
bool IsSolved() const
Checks if the EMM equations are solved.
void SetParameters(double T, double Mu)
Sets the temperature and chemical potential of the particle.
virtual bool IsBECPhase() const
Checks if the particle is in a Bose-Einstein condensed phase.
void SolveMeff(double meffinit=-1.)
Solves for the effective mass using the given parameters.
double Density() const
Calculates the number density in 1/fm^3.
double EnergyDensity() const
Calculates the energy density in GeV/fm^3.
double DmeffDT() const
Computes the temperature derivative of the effective mass dm_eff/dT at fixed mu.
EffectiveMassModel(const ThermalParticle &particle=ThermalParticle(true, "pi", 211, 1.0, -1, 0.135, 0, 0, 1), EMMFieldPressure *FieldPressure=NULL)
Constructor for the EffectiveMassModel class.
double Pressure() const
Calculates the pressure in GeV/fm^3.
double IdealGasQuantityMassDerivative(IdealGasFunctions::Quantity quantity) const
Computes the derivative of an ideal gas quantity with respect to mass, (dQ^id/dm)|_{T,...
virtual double Quantity(IdealGasFunctions::Quantity quantity, double T, double mu)
Calculates a thermodynamic quantity.
virtual double BECFraction() const
Calculates the fraction of particles in the BEC phase.
double EntropyDensity() const
Calculates the entropy density in 1/fm^3.
virtual ~EffectiveMassModel(void)
Destructor for the EffectiveMassModel class.
Class containing all information about a particle specie.
double IdealGasQuantity(Quantity quantity, QStatsCalculationType calctype, int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Calculation of a generic ideal gas function.
Quantity
Identifies the thermodynamic function.
constexpr double GeVtoifm3()
A constant to transform GeV into fm .
Definition xMath.h:31
The main namespace where all classes and functions of the Thermal-FIST library reside.
Definition CosmicEoS.h:9
Structure containing all thermal parameters of the model.