Thermal-FIST  1.3
Package for hadron resonance gas model applications
ThermalModelCanonical.cpp
Go to the documentation of this file.
1 /*
2  * Thermal-FIST package
3  *
4  * Copyright (c) 2015-2019 Volodymyr Vovchenko
5  *
6  * GNU General Public License (GPLv3 or later)
7  */
9 
10 #include <iostream>
11 #include <cmath>
12 #include <cstdlib>
13 #include <algorithm>
14 
15 #include "HRGBase/xMath.h"
17 
18 using namespace std;
19 
20 namespace thermalfist {
21 
22  ThermalModelCanonical::ThermalModelCanonical(ThermalParticleSystem *TPS_, const ThermalModelParameters& params) :
23  ThermalModelBase(TPS_, params), m_BCE(1), m_QCE(1), m_SCE(1), m_CCE(1), m_IntegrationIterationsMultiplier(1)
24  {
25 
26  m_TAG = "ThermalModelCanonical";
27 
28  m_Ensemble = CE;
30 
31  m_modelgce = NULL;
32 
33  m_Banalyt = false;
34  }
35 
36 
38  {
39  CleanModelGCE();
40  }
41 
44  }
45 
47  {
48  m_BMAX = 0;
49  m_QMAX = 0;
50  m_SMAX = 0;
51  m_CMAX = 0;
52 
53 
54  for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
55  ThermalParticle &part = m_TPS->Particle(i);
56 
57  if (part.Statistics() != 0 && IsParticleCanonical(part)) {
59 
60  m_BMAX = max(m_BMAX, abs(part.BaryonCharge() * part.ClusterExpansionOrder()));
61  m_QMAX = max(m_QMAX, abs(part.ElectricCharge() * part.ClusterExpansionOrder()));
62  m_SMAX = max(m_SMAX, abs(part.Strangeness() * part.ClusterExpansionOrder()));
63  m_CMAX = max(m_CMAX, abs(part.Charm() * part.ClusterExpansionOrder()));
64  }
65  else {
66  m_BMAX = max(m_BMAX, abs(part.BaryonCharge()));
67  m_QMAX = max(m_QMAX, abs(part.ElectricCharge()));
68  m_SMAX = max(m_SMAX, abs(part.Strangeness()));
69  m_CMAX = max(m_CMAX, abs(part.Charm()));
70  }
71  }
72 
77 
78  if (computeFluctuations) {
79  m_BMAX *= 2;
80  m_QMAX *= 2;
81  m_SMAX *= 2;
82  m_CMAX *= 2;
83  }
84 
85  // Some charges may be treated grand-canonically
86  m_BMAX *= m_BCE;
87  m_QMAX *= m_QCE;
88  m_SMAX *= m_SCE;
89  m_CMAX *= m_CCE;
90 
91  printf("BMAX = %d\tQMAX = %d\tSMAX = %d\tCMAX = %d\n", m_BMAX, m_QMAX, m_SMAX, m_CMAX);
92 
93  m_QNMap.clear();
94  m_QNvec.resize(0);
95 
96  m_Corr.resize(0);
97  m_PartialZ.resize(0);
98 
99  int ind = 0;
100  for (int iB = -m_BMAX; iB <= m_BMAX; ++iB)
101  for (int iQ = -m_QMAX; iQ <= m_QMAX; ++iQ)
102  for (int iS = -m_SMAX; iS <= m_SMAX; ++iS)
103  for (int iC = -m_CMAX; iC <= m_CMAX; ++iC) {
104 
105  QuantumNumbers qn(iB, iQ, iS, iC);
106  m_QNMap[qn] = ind;
107  m_QNvec.push_back(qn);
108 
109  m_PartialZ.push_back(0.);
110  m_Corr.push_back(1.);
111 
112 
113  ind++;
114  }
115 
116  }
117 
119  m_QuantumStats = stats;
120  for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
121  m_TPS->Particle(i).UseStatistics(stats);
122 
123  // Only cluster expansion method supported for particles with canonically conserved charges
124  if (stats && IsParticleCanonical(m_TPS->Particle(i)))
126  }
127  m_PartialZ.clear();
128  //CalculateQuantumNumbersRange();
129  }
130 
132  {
133  m_ConstrainMuB &= !m_BCE;
134  m_ConstrainMuQ &= !m_QCE;
135  m_ConstrainMuS &= !m_SCE;
136  m_ConstrainMuC &= !m_CCE;
138  }
139 
141  {
142  m_ConstrainMuB &= !m_BCE;
143  m_ConstrainMuQ &= !m_QCE;
144  m_ConstrainMuS &= !m_SCE;
145  m_ConstrainMuC &= !m_CCE;
147  }
148 
149 
151  m_FluctuationsCalculated = false;
152 
153  if (m_PartialZ.size() == 0)
155 
156  if (m_BMAX_list == 1 && m_BCE && m_QCE && m_SCE && m_CCE && !UsePartialChemicalEquilibrium()) {
157  m_Banalyt = true;
158  m_Parameters.muB = 0.0;
159  m_Parameters.muQ = 0.0;
160  m_Parameters.muS = 0.0;
161  m_Parameters.muC = 0.0;
162  }
163  else {
164  m_Banalyt = false;
165  if (m_BCE)
166  m_Parameters.muB = 0.0;
167  if (m_QCE)
168  m_Parameters.muQ = 0.0;
169  if (m_SCE)
170  m_Parameters.muS = 0.0;
171  if (m_CCE)
172  m_Parameters.muC = 0.0;
173 
174  //PrepareModelGCE(); // Plan B, may work better when quantum numbers are large
175  }
176 
178 
179  for (size_t i = 0; i < m_densities.size(); ++i) {
180  ThermalParticle &tpart = m_TPS->Particle(i);
181  m_densities[i] = 0.;
182 
183  if (!IsParticleCanonical(tpart)) {
185  }
186  else if (tpart.Statistics() == 0
188  {
189  int ind = m_QNMap[QuantumNumbers(m_BCE * tpart.BaryonCharge(), m_QCE * tpart.ElectricCharge(), m_SCE * tpart.Strangeness(), m_CCE * tpart.Charm())];
190 
191  if (ind < static_cast<int>(m_Corr.size()))
193  }
194  else {
195  for (int n = 1; n <= tpart.ClusterExpansionOrder(); ++n) {
196  int ind = m_QNMap[QuantumNumbers(m_BCE*n*tpart.BaryonCharge(), m_QCE*n*tpart.ElectricCharge(), m_SCE*n*tpart.Strangeness(), m_CCE*n*tpart.Charm())];
197  if (ind < static_cast<int>(m_Corr.size()))
199  }
200  }
201  }
202 
203  m_Calculated = true;
205  }
206 
208  {
210 
211  char cc[1000];
212 
213  double TOL = 1.e-4;
214 
215  // Checking that the CE calculation is valid
216  if (m_BCE && m_BMAX != 0) {
217  double totB = CalculateBaryonDensity() * m_Parameters.SVc;
218  if (fabs(m_Parameters.B - totB) > TOL) {
219 
220  sprintf(cc, "**WARNING** ThermalModelCanonical: Inaccurate calculation of total baryon number.\
221 \n\
222 Expected: %d\n\
223 Obtained: %lf\n\
224 \n", m_Parameters.B, totB);
225 
226  printf("%s", cc);
227 
228  m_ValidityLog.append(cc);
229 
231  }
232  }
233 
234 
235  if (m_QCE && m_QMAX != 0) {
236  double totQ = CalculateChargeDensity() * m_Parameters.SVc;
237  if (fabs(m_Parameters.Q - totQ) > TOL) {
238  sprintf(cc, "**WARNING** ThermalModelCanonical: Inaccurate calculation of total electric charge.\
239 \n\
240 Expected: %d\n\
241 Obtained: %lf\n\
242 \n", m_Parameters.Q, totQ);
243 
244  printf("%s", cc);
245 
246  m_ValidityLog.append(cc);
247 
249  }
250  }
251 
252 
253  if (m_SCE && m_SMAX != 0) {
254  double totS = CalculateStrangenessDensity() * m_Parameters.SVc;
255  if (fabs(m_Parameters.S - totS) > TOL) {
256  sprintf(cc, "**WARNING** ThermalModelCanonical: Inaccurate calculation of total strangeness.\
257 \n\
258 Expected: %d\n\
259 Obtained: %lf\n\
260 \n", m_Parameters.S, totS);
261 
262  printf("%s", cc);
263 
264  m_ValidityLog.append(cc);
265 
267  }
268  }
269 
270 
271  if (m_CCE && m_CMAX != 0) {
272  double totC = CalculateCharmDensity() * m_Parameters.SVc;
273  if (fabs(m_Parameters.C - totC) > TOL) {
274  sprintf(cc, "**WARNING** ThermalModelCanonical: Inaccurate calculation of total charm.\
275 \n\
276 Expected: %d\n\
277 Obtained: %lf\n\
278 \n", m_Parameters.C, totC);
279 
280  printf("%s", cc);
281 
282  m_ValidityLog.append(cc);
283 
285  }
286  }
287  }
288 
290  {
291  if (Vc < 0.0)
292  Vc = m_Parameters.SVc;
293 
296  else {
297  // Partial chemical equilibrium canonical ensemble currently works only if there is particle-antiparticle symmetry
298  for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
299  int i2 = m_TPS->PdgToId(-m_TPS->Particle(i).PdgId());
300  if (i2 != -1) {
301  if (fabs(m_Chem[i] - m_Chem[i2]) > 1.e-8) {
302  printf("**ERROR** ThermalModelCanonical::CalculatePartitionFunctions: Partial chemical equilibrium canonical ensemble only supported if particle-antiparticle fugacities are symmetric!\n");
303  exit(1);
304  }
305  }
306  }
307  }
308 
309  bool AllMuZero = true;
310  for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
311  ThermalParticle &tpart = m_TPS->Particle(i);
312  if (IsParticleCanonical(tpart) && m_Chem[i] != 0.0)
313  {
314  AllMuZero = false;
315  break;
316  }
317  }
318 
319  vector<double> Nsx(m_PartialZ.size(), 0.);
320  vector<double> Nsy(m_PartialZ.size(), 0.);
321 
322  for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
323  ThermalParticle &tpart = m_TPS->Particle(i);
324 
325  if (!IsParticleCanonical(tpart)) {
326  int ind = m_QNMap[QuantumNumbers(m_BCE * tpart.BaryonCharge(), m_QCE * tpart.ElectricCharge(), m_SCE * tpart.Strangeness(), m_CCE * tpart.Charm())];
327  if (ind != m_QNMap[QuantumNumbers(0, 0, 0, 0)]) {
328  printf("**ERROR** ThermalModelCanonical: neutral particle cannot have non-zero ce charges\n");
329  exit(1);
330  }
331  if (ind < static_cast<int>(Nsx.size()))
333  }
334  else if (tpart.Statistics() == 0
336  int ind = m_QNMap[QuantumNumbers(m_BCE * tpart.BaryonCharge(), m_QCE * tpart.ElectricCharge(), m_SCE * tpart.Strangeness(), m_CCE * tpart.Charm())];
337  if (ind < static_cast<int>(Nsx.size())) {
340  Nsx[ind] += tdens * cosh(m_Chem[i] / m_Parameters.T);
341  Nsy[ind] += tdens * sinh(m_Chem[i] / m_Parameters.T);
342  }
343  // Currently only works at mu = 0!!
344  else {
346  Nsx[ind] += tdens;
347  }
348  }
349  }
350  else {
351  for (int n = 1; n <= tpart.ClusterExpansionOrder(); ++n) {
352  int ind = m_QNMap[QuantumNumbers(m_BCE*n*tpart.BaryonCharge(), m_QCE*n*tpart.ElectricCharge(), m_SCE*n*tpart.Strangeness(), m_CCE*n*tpart.Charm())];
353  if (ind < static_cast<int>(Nsx.size())) {
355  double tdens = tpart.DensityCluster(n, m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, 0.) / static_cast<double>(n); // TODO: Check
356  Nsx[ind] += tdens * cosh(n * m_Chem[i] / m_Parameters.T);
357  Nsy[ind] += tdens * sinh(n * m_Chem[i] / m_Parameters.T);
358  }
359  // Currently only works at mu = 0!!
360  else {
361  double tdens = tpart.DensityCluster(n, m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, m_Chem[i]) / static_cast<double>(n); // TODO: Check
362  Nsx[ind] += tdens;
363  }
364  }
365  }
366  }
367  }
368 
369  for (int i = 0; i < static_cast<int>(Nsx.size()); ++i) {
370  Nsx[i] *= Vc;
371  Nsy[i] *= Vc;
372  m_PartialZ[i] = 0.;
373  }
374 
376  if (m_Parameters.B == 0 && m_Parameters.Q == 0 && m_Parameters.S == 0 && m_Parameters.C == 0)
377  nmax = 4;
378 
379 
380 
381  int nmaxB = max(4, m_Parameters.B);
382  int nmaxQ = max(4, m_Parameters.Q);
383  int nmaxS = max(4, m_Parameters.S);
384  int nmaxC = max(4, m_Parameters.C);
385 
386  // UPDATE: allow to increase the number of interations externally
388  nmaxB = nmaxQ = nmaxS = nmaxC = nmax;
389 
390 
391 
392 
393 
394  m_MultExp = 0.;
395  m_MultExpBanalyt = 0.;
396  for (size_t i = 0; i < m_PartialZ.size(); ++i) {
397  if (!m_Banalyt || m_QNvec[i].B == 0)
398  m_MultExp += Nsx[i];
399  if (m_Banalyt && (m_QNvec[i].B == 1 || m_QNvec[i].B == -1))
400  m_MultExpBanalyt += Nsx[i];
401  }
402 
403  double dphiB = xMath::Pi() / nmaxB;
404  int maxB = 2 * nmaxB;
405  if (m_BMAX == 0 || m_Banalyt)
406  maxB = 1;
407 
408  for (int iB = 0; iB < maxB; ++iB) {
409 
410  vector<double> xlegB, wlegB;
411 
412  if (m_BMAX != 0 && !m_Banalyt) {
413  double aB = iB * dphiB;
414  if (iB >= nmaxB) aB = xMath::Pi() - (iB + 1) * dphiB;
415  double bB = aB + dphiB;
417  }
418  else {
419  xlegB.resize(1);
420  xlegB[0] = 0.;
421  wlegB.resize(1);
422  wlegB[0] = 1.;
423  }
424 
425 
426  double dphiS = xMath::Pi() / nmaxS;
427  int maxS = 2 * nmaxS;
428  if (m_SMAX == 0)
429  maxS = 1;
430 
431  for (int iS = 0; iS < maxS; ++iS) {
432  vector<double> xlegS, wlegS;
433 
434  if (m_SMAX != 0) {
435  double aS = iS * dphiS;
436  if (iS >= nmaxS) aS = xMath::Pi() - (iS + 1) * dphiS;
437  double bS = aS + dphiS;
439  }
440  else {
441  xlegS.resize(1);
442  xlegS[0] = 0.;
443  wlegS.resize(1);
444  wlegS[0] = 1.;
445  }
446 
447  double dphiQ = xMath::Pi() / nmaxQ;
448  int maxQ = nmaxQ;
449  if (m_QMAX == 0)
450  maxQ = 1;
451 
452  for (int iQ = 0; iQ < maxQ; ++iQ) {
453  vector<double> xlegQ, wlegQ;
454 
455  if (m_QMAX != 0) {
456  double aQ = iQ * dphiQ;
457  double bQ = aQ + dphiQ;
459  }
460  else {
461  xlegQ.resize(1);
462  xlegQ[0] = 0.;
463  wlegQ.resize(1);
464  wlegQ[0] = 1.;
465  }
466 
467  double dphiC = xMath::Pi() / nmaxC;
468  int maxC = 2 * nmaxC;
469  if (m_CMAX == 0)
470  maxC = 1;
471 
472  for (int iC = 0; iC < maxC; ++iC) {
473  vector<double> xlegC, wlegC;
474  if (m_CMAX != 0) {
475  double aC = iC * dphiC;
476  if (iC >= nmaxC) aC = xMath::Pi() - (iC + 1) * dphiC;
477  double bC = aC + dphiC;
479  }
480  else {
481  xlegC.resize(1);
482  xlegC[0] = 0.;
483  wlegC.resize(1);
484  wlegC[0] = 1.;
485  }
486 
487  for (size_t iBt = 0; iBt < xlegB.size(); ++iBt) {
488  for (size_t iSt = 0; iSt < xlegS.size(); ++iSt) {
489  for (size_t iQt = 0; iQt < xlegQ.size(); ++iQt) {
490  for (size_t iCt = 0; iCt < xlegC.size(); ++iCt) {
491  vector<double> cosph(m_PartialZ.size(), 0.), sinph(m_PartialZ.size(), 0.);
492  double wx = 0., wy = 0., mx = 0., my = 0.;
493  for (size_t i = 0; i < m_PartialZ.size(); ++i) {
494  int tB = m_QNvec[i].B;
495  int tQ = m_QNvec[i].Q;
496  int tS = m_QNvec[i].S;
497  int tC = m_QNvec[i].C;
498 
499  if (m_Banalyt) {
500  cosph[i] = cos(tS*xlegS[iSt] + tQ * xlegQ[iQt] + tC * xlegC[iCt]);
501  sinph[i] = sin(tS*xlegS[iSt] + tQ * xlegQ[iQt] + tC * xlegC[iCt]);
502 
503  if (m_QNvec[i].B == 1) {
504  wx += Nsx[i] * cosph[i];
505  wy += Nsx[i] * sinph[i];
506  }
507  else if (m_QNvec[i].B == 0) {
508  mx += Nsx[i] * (cosph[i] - 1.);
509  }
510  }
511  else {
512  cosph[i] = cos(tB*xlegB[iBt] + tS * xlegS[iSt] + tQ * xlegQ[iQt] + tC * xlegC[iCt]);
513  mx += Nsx[i] * (cosph[i] - 1.);
514 
515  if (!AllMuZero) {
516  sinph[i] = sin(tB*xlegB[iBt] + tS * xlegS[iSt] + tQ * xlegQ[iQt] + tC * xlegC[iCt]);
517  my += Nsy[i] * sinph[i];
518  }
519  }
520  }
521 
522  double wmod = 0.;
523  double warg = 0.;
524 
525  if (m_Banalyt) {
526  wmod = sqrt(wx*wx + wy * wy);
527  warg = atan2(wy, wx);
528  }
529 
530  for (size_t iN = 0; iN < m_PartialZ.size(); ++iN) {
531  int tBg = m_Parameters.B - m_QNvec[iN].B;
532  int tQg = m_Parameters.Q - m_QNvec[iN].Q;
533  int tSg = m_Parameters.S - m_QNvec[iN].S;
534  int tCg = m_Parameters.C - m_QNvec[iN].C;
535 
536  if (m_Banalyt) {
537  //m_PartialZ[iN] += wlegB[iBt] * wlegS[iSt] * wlegQ[iQt] * wlegC[iCt] * cos(tBg*xlegB[iBt] + tSg * xlegS[iSt] + tQg * xlegQ[iQt] + tCg * xlegC[iCt] - tBg * warg) * exp(mx) * xMath::BesselI(tBg, 2. * wmod);
538  m_PartialZ[iN] += wlegB[iBt] * wlegS[iSt] * wlegQ[iQt] * wlegC[iCt] *
539  cos(tBg * xlegB[iBt] + tSg * xlegS[iSt] + tQg * xlegQ[iQt] + tCg * xlegC[iCt] - tBg * warg) *
540  exp(mx + 2. * wmod - m_MultExpBanalyt) *
541  xMath::BesselIexp(tBg, 2. * wmod);
542  }
543  else {
544  if (AllMuZero)
545  m_PartialZ[iN] += wlegB[iBt] * wlegS[iSt] * wlegQ[iQt] * wlegC[iCt] * cos(tBg*xlegB[iBt] + tSg * xlegS[iSt] + tQg * xlegQ[iQt] + tCg * xlegC[iCt]) * exp(mx);
546  else
547  m_PartialZ[iN] += wlegB[iBt] * wlegS[iSt] * wlegQ[iQt] * wlegC[iCt] * exp(mx)
548  * (cos(tBg*xlegB[iBt] + tSg * xlegS[iSt] + tQg * xlegQ[iQt] + tCg * xlegC[iCt]) * cos(my)
549  + sin(tBg*xlegB[iBt] + tSg * xlegS[iSt] + tQg * xlegQ[iQt] + tCg * xlegC[iCt]) * sin(my));
550  }
551  }
552  }
553  }
554  }
555  }
556 
557  //int cind = iB * maxS * maxQ * maxC + iS * maxQ * maxC + iQ * maxC + iC;
558  //int tot = maxB * maxS * maxQ * maxC;
559  }
560  }
561  }
562  }
563 
564  for (size_t iN = 0; iN < m_PartialZ.size(); ++iN) {
565  if (m_BMAX != 0 && m_BMAX != 1 && !m_Banalyt) // TODO: cross-check
566  m_PartialZ[iN] /= 2. * xMath::Pi();
567  if (m_QMAX != 0) {
568  m_PartialZ[iN] /= 2. * xMath::Pi();
569  m_PartialZ[iN] *= 2.;
570  }
571  if (m_SMAX != 0)
572  m_PartialZ[iN] /= 2. * xMath::Pi();
573  if (m_CMAX != 0)
574  m_PartialZ[iN] /= 2. * xMath::Pi();
575  }
576 
577 
578  m_Corr.resize(m_PartialZ.size());
579  for (size_t iN = 0; iN < m_PartialZ.size(); ++iN) {
580  m_Corr[iN] = m_PartialZ[iN] / m_PartialZ[m_QNMap[QuantumNumbers(0, 0, 0, 0)]];
581  }
582  }
583 
585  {
586  ThermalParticle &tpart = m_TPS->Particle(part);
587  double ret1 = 0., ret2 = 0., ret3 = 0.;
588 
589  if (!IsParticleCanonical(tpart)) {
590  return tpart.ScaledVariance(m_Parameters, m_UseWidth, m_Chem[part]);
591  }
592  else if (tpart.Statistics() == 0
594  {
595  int ind = m_QNMap[QuantumNumbers(m_BCE*tpart.BaryonCharge(), m_QCE*tpart.ElectricCharge(), m_SCE*tpart.Strangeness(), m_CCE*tpart.Charm())];
596  int ind2 = m_QNMap[QuantumNumbers(m_BCE * 2 * tpart.BaryonCharge(), m_QCE * 2 * tpart.ElectricCharge(), m_SCE * 2 * tpart.Strangeness(), m_CCE * 2 * tpart.Charm())];
597 
598  ret1 = 1.;
599  if (ind < static_cast<int>(m_Corr.size()) && ind2 < static_cast<int>(m_Corr.size()))
601 
602  if (ind < static_cast<int>(m_Corr.size()))
604  }
605  else {
606  double ret1num = 0., ret1zn = 0.;
607  for (int n = 1; n <= tpart.ClusterExpansionOrder(); ++n) {
608  int ind = m_QNMap[QuantumNumbers(m_BCE*n*tpart.BaryonCharge(), m_QCE*n*tpart.ElectricCharge(), m_SCE*n*tpart.Strangeness(), m_CCE*n*tpart.Charm())];
609 
610  double densityClusterN = tpart.DensityCluster(n, m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, m_Chem[part]);
611 
612  if (ind < static_cast<int>(m_Corr.size())) {
613  ret1num += m_Corr[ind] * n * densityClusterN;
614  ret1zn += m_Corr[ind] * densityClusterN;
615  }
616 
617  for (int n2 = 1; n2 <= tpart.ClusterExpansionOrder(); ++n2) {
618  if (m_QNMap.count(QuantumNumbers(m_BCE*(n + n2)*tpart.BaryonCharge(), m_QCE*(n + n2)*tpart.ElectricCharge(), m_SCE*(n + n2)*tpart.Strangeness(), m_CCE*(n + n2)*tpart.Charm())) != 0) {
619  int ind2 = m_QNMap[QuantumNumbers(m_BCE*(n + n2)*tpart.BaryonCharge(), m_QCE*(n + n2)*tpart.ElectricCharge(), m_SCE*(n + n2)*tpart.Strangeness(), m_CCE*(n + n2)*tpart.Charm())];
620  if (ind < static_cast<int>(m_Corr.size()) && ind2 < static_cast<int>(m_Corr.size()))
621  ret2 += densityClusterN * m_Corr[ind2] * m_Parameters.SVc * tpart.DensityCluster(n2, m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, m_Chem[part]);
622  }
623  }
624  }
625 
626  if (ret1zn == 0.0)
627  return 1.;
628 
629  ret1 = ret1num / ret1zn;
630  ret2 = ret2 / ret1zn;
631  ret3 = -ret1zn * m_Parameters.SVc;
632  }
633  return ret1 + ret2 + ret3;
634  }
635 
637  int NN = m_densities.size();
638 
639  vector<double> yld(NN, 0);
640  vector<double> ret1num(NN, 0);
641  vector< vector<double> > ret2num(NN, vector<double>(NN, 0.));
642 
643  for (int i = 0; i < NN; ++i)
644  yld[i] = m_densities[i] * m_Parameters.SVc;
645 
646  for (int i = 0; i < NN; ++i) {
647  ThermalParticle &tpart = m_TPS->Particle(i);
648  if (!IsParticleCanonical(tpart)) {
649  ret1num[i] = tpart.ScaledVariance(m_Parameters, m_UseWidth, m_Chem[i]) * yld[i];
650  }
651  else if (tpart.Statistics() == 0
653  {
654  ret1num[i] = yld[i];
655  }
656  else {
657  for (int n = 1; n <= tpart.ClusterExpansionOrder(); ++n) {
658  int ind = m_QNMap[QuantumNumbers(m_BCE*n*tpart.BaryonCharge(), m_QCE*n*tpart.ElectricCharge(), m_SCE*n*tpart.Strangeness(), m_CCE*n*tpart.Charm())];
659 
660  double densityClusterN = tpart.DensityCluster(n, m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, m_Chem[i]);
661 
662  if (ind < static_cast<int>(m_Corr.size()))
663  ret1num[i] += m_Corr[ind] * n * densityClusterN * m_Parameters.SVc;
664  }
665  }
666  }
667 
668  for (int i = 0; i < NN; ++i) {
669  for (int j = 0; j < NN; ++j) {
670  ThermalParticle &tpart1 = m_TPS->Particle(i);
671  ThermalParticle &tpart2 = m_TPS->Particle(j);
672 
673  int n1max = tpart1.ClusterExpansionOrder();
674  int n2max = tpart2.ClusterExpansionOrder();
675 
676  if (tpart1.Statistics() == 0 || tpart1.CalculationType() != IdealGasFunctions::ClusterExpansion)
677  n1max = 1;
678  if (tpart2.Statistics() == 0 || tpart2.CalculationType() != IdealGasFunctions::ClusterExpansion)
679  n2max = 1;
680 
681  if (!IsParticleCanonical(tpart1) || !IsParticleCanonical(tpart2)) {
682  ret2num[i][j] = yld[i] * yld[j];
683  }
684  else {
685  for (int n1 = 1; n1 <= n1max; ++n1) {
686  for (int n2 = 1; n2 <= n2max; ++n2) {
687  int ind = m_QNMap[QuantumNumbers(
688  m_BCE*(n1*tpart1.BaryonCharge() + n2 * tpart2.BaryonCharge()),
689  m_QCE*(n1*tpart1.ElectricCharge() + n2 * tpart2.ElectricCharge()),
690  m_SCE*(n1*tpart1.Strangeness() + n2 * tpart2.Strangeness()),
691  m_CCE*(n1*tpart1.Charm() + n2 * tpart2.Charm()))];
692 
693  double densityClusterN1 = tpart1.DensityCluster(n1, m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, m_Chem[i]);
694  double densityClusterN2 = tpart2.DensityCluster(n2, m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, m_Chem[j]);
695 
696  if (ind < static_cast<int>(m_Corr.size()))
697  ret2num[i][j] += m_Corr[ind] * densityClusterN1 * densityClusterN2 * m_Parameters.SVc * m_Parameters.SVc;
698  }
699  }
700  }
701  }
702  }
703 
704 
705  m_PrimCorrel.resize(NN);
706  for (int i = 0; i < NN; ++i)
707  m_PrimCorrel[i].resize(NN);
709 
710  for (int i = 0; i < NN; ++i) {
711  for (int j = 0; j < NN; ++j) {
712  m_PrimCorrel[i][j] = 0.;
713  if (i == j)
714  m_PrimCorrel[i][j] += ret1num[i] / yld[i];
715  m_PrimCorrel[i][j] += ret2num[i][j] / yld[i];
716  m_PrimCorrel[i][j] += -yld[j];
717  m_PrimCorrel[i][j] *= yld[i] / m_Parameters.SVc / m_Parameters.T;
718  if (yld[i] == 0.0)
719  m_PrimCorrel[i][j] = 0.;
720  }
721  }
722 
723  for (int i = 0; i < NN; ++i) {
724  m_wprim[i] = m_PrimCorrel[i][i];
725  if (m_densities[i] > 0.) m_wprim[i] *= m_Parameters.T / m_densities[i];
726  else m_wprim[i] = 1.;
727  }
728 
729  }
730 
737 
739 
740  for (size_t i = 0; i < m_wprim.size(); ++i) {
741  m_skewprim[i] = 1.;
742  m_kurtprim[i] = 1.;
743  m_skewtot[i] = 1.;
744  m_kurttot[i] = 1.;
745  }
746  }
747 
750  double ret = 0.;
751 
752  for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
753  ThermalParticle &tpart = m_TPS->Particle(i);
754  {
755  if (!IsParticleCanonical(tpart)) {
757  }
758  else if (tpart.Statistics() == 0
760  int ind = m_QNMap[QuantumNumbers(tpart.BaryonCharge(), tpart.ElectricCharge(), tpart.Strangeness(), tpart.Charm())];
761 
762  if (ind < static_cast<int>(m_Corr.size()))
764  }
765  else {
766  for (int n = 1; n <= tpart.ClusterExpansionOrder(); ++n) {
767  int ind = m_QNMap[QuantumNumbers(n*tpart.BaryonCharge(), n*tpart.ElectricCharge(), n*tpart.Strangeness(), n*tpart.Charm())];
768  if (ind < static_cast<int>(m_Corr.size()))
770  }
771  }
772  }
773  }
774 
775  return ret;
776  }
777 
780  double ret = 0.;
781 
782  for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
783  ThermalParticle &tpart = m_TPS->Particle(i);
784  {
785  if (!IsParticleCanonical(tpart)) {
787  }
788  else if (tpart.Statistics() == 0
790  int ind = m_QNMap[QuantumNumbers(tpart.BaryonCharge(), tpart.ElectricCharge(), tpart.Strangeness(), tpart.Charm())];
791 
792  if (ind < static_cast<int>(m_Corr.size()))
794  }
795  else {
796  for (int n = 1; n <= tpart.ClusterExpansionOrder(); ++n) {
797  int ind = m_QNMap[QuantumNumbers(n*tpart.BaryonCharge(), n*tpart.ElectricCharge(), n*tpart.Strangeness(), n*tpart.Charm())];
798 
799  if (ind < static_cast<int>(m_Corr.size()))
801  }
802  }
803  }
804  }
805 
806  return ret;
807  }
808 
810  {
812 
813  if (m_BCE)
815  else
817 
818  if (m_QCE)
820  else
822 
823  if (m_SCE)
825  else
827 
828  if (m_CCE)
830  else
832 
833  return ret;
834  }
835 
837  {
839  }
840 
842  {
843  return !(
844  (part.BaryonCharge() == 0 || m_BCE == 0)
845  && (part.ElectricCharge() == 0 || m_QCE == 0)
846  && (part.Strangeness() == 0 || m_SCE == 0)
847  && (part.Charm() == 0 || m_CCE == 0)
848  );
849  }
850 
852  {
853  if (charge == ConservedCharge::BaryonCharge)
854  return (m_BCE != 0);
855  else if (charge == ConservedCharge::ElectricCharge)
856  return (m_QCE != 0);
857  else if (charge == ConservedCharge::StrangenessCharge)
858  return (m_SCE != 0);
859  else if (charge == ConservedCharge::CharmCharge)
860  return (m_CCE != 0);
861  return 0;
862  }
863 
864  void ThermalModelCanonical::PrepareModelGCE()
865  {
866  CleanModelGCE();
867 
871 
872  if (m_BCE)
873  m_Parameters.muB = 0.0;
874 
875  if (!m_BCE && m_SCE)
877 
878  if (!m_BCE && m_QCE)
879  m_Parameters.muQ = -m_Parameters.muB / 30.;
880 
881  m_Parameters.muC = 0.;
882 
885  static_cast<bool>(m_BCE),
886  static_cast<bool>(m_QCE),
887  static_cast<bool>(m_SCE),
888  static_cast<bool>(m_CCE));
889 
894 
895 
896  // Possible alternative below
897  //double tdens = 0.;
898  //for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
899  // ThermalParticle &part = m_TPS->Particle(i);
900  // if (part.BaryonCharge() == 1)
901  // tdens += part.Density(m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, 0.);
902  //}
903  //m_Parameters.muB = m_Parameters.T * asinh(m_Parameters.B / m_Parameters.SVc / 2. / tdens);
904  //m_Parameters.muS = m_Parameters.muB / 3.;
905  //m_Parameters.muQ = -m_Parameters.muB / 30.;
906  }
907 
908  void ThermalModelCanonical::CleanModelGCE()
909  {
910  if (m_modelgce != NULL) {
911  delete m_modelgce;
912  m_modelgce = NULL;
913  }
914  }
915 
916 } // namespace thermalfist
917 
918 
virtual double ParticleScaledVariance(int part)
Scaled variance of primordial particle number fluctuations for species i.
Abstract base class for an HRG model implementation.
std::vector< QuantumNumbers > m_QNvec
A set of QuantumNumbers combinations for which it is necessary to compute the canonical partition fun...
virtual void CalculateTwoParticleFluctuationsDecays()
Computes particle number correlations and fluctuations for all final-state particles which are marked...
std::vector< double > m_Chem
double DensityCluster(int n, const ThermalModelParameters &params, IdealGasFunctions::Quantity type=IdealGasFunctions::ParticleDensity, bool useWidth=0, double mu=0.) const
virtual void ValidateCalculation()
Checks whether issues have occured during the calculation of particle densities in the CalculateDensi...
std::vector< double > m_kurttot
int Charm() const
Particle&#39;s charm.
int ClusterExpansionOrder() const
Number of terms in the cluster expansion method.
std::vector< double > m_wprim
double Density(const ThermalModelParameters &params, IdealGasFunctions::Quantity type=IdealGasFunctions::ParticleDensity, bool useWidth=0, double mu=0.) const
Computes a specified ideal gas thermodynamic function.
const ThermalParticle & Particle(int id) const
ThermalParticle object corresponding to particle species with a provided 0-based index.
std::vector< double > m_skewprim
virtual void FixParameters()
Method which actually implements ConstrainChemicalPotentials() (for backward compatibility).
virtual void CalculatePrimordialDensities()
Calculates the primordial densities of all species.
double Pi()
Pi constant.
Definition: xMath.h:24
void SetUseWidth(bool useWidth)
Sets whether finite resonance widths are used. Deprecated.
int PdgToId(long long pdgid)
Transforms PDG ID to a 0-based particle id number.
long long PdgId() const
Particle&#39;s Particle Data Group (PDG) ID number.
Class containing the particle list.
virtual void FixParameters()
Method which actually implements ConstrainChemicalPotentials() (for backward compatibility).
ThermalModelParameters m_Parameters
Structure containing all thermal parameters of the model.
virtual double CalculateStrangenessDensity()
int ComponentsNumber() const
Number of different particle species in the list.
virtual ~ThermalModelCanonical(void)
Destroy the ThermalModelCanonical object.
virtual void CalculateSusceptibilityMatrix()
Calculates the conserved charges susceptibility matrix.
double BesselIexp(int n, double x)
Definition: xMath.cpp:795
Contains some extra mathematical functions used in the code.
ThermalParticleSystem * m_TPS
double ScaledVariance(const ThermalModelParameters &params, bool useWidth=0, double mu=0.) const
Computes the scaled variance of particle number fluctuations in the ideal gas. Computes the scaled va...
virtual void FillChemicalPotentials()
Sets the chemical potentials of all particles.
virtual void FixParametersNoReset()
Method which actually implements ConstrainChemicalPotentialsNoReset() (for backward compatibility)...
int BaryonCharge() const
Particle&#39;s baryon number.
virtual void CalculateQuantumNumbersRange(bool computeFluctuations=false)
Calculates the range of quantum numbers values for which it is necessary to compute the canonical par...
Class containing all information about a particle specie.
virtual void CalculateProxySusceptibilityMatrix()
Calculates the susceptibility matrix of conserved charges proxies.
virtual void FixParametersNoReset()
Method which actually implements ConstrainChemicalPotentialsNoReset() (for backward compatibility)...
virtual void CalculateFluctuations()
Computes the fluctuation observables.
std::vector< double > m_kurtprim
const std::vector< ThermalParticle > & Particles() const
Returns the vector of all particle species.
std::vector< std::vector< double > > m_TotalCorrel
ThermalModelInteraction m_InteractionModel
virtual void ValidateCalculation()
Checks whether issues have occured during the calculation of particle densities in the CalculateDensi...
virtual bool SolveChemicalPotentials(double totB=0., double totQ=0., double totS=0., double totC=0., double muBinit=0., double muQinit=0., double muSinit=0., double muCinit=0., bool ConstrMuB=true, bool ConstrMuQ=true, bool ConstrMuS=true, bool ConstrMuC=true)
The procedure which calculates the chemical potentials which reproduce the specified total baryon...
void UseStatistics(bool enable)
Use quantum statistics.
void GetCoefsIntegrateLegendre10(double a, double b, std::vector< double > *x, std::vector< double > *w)
Name
Set of all conserved charges considered.
std::vector< double > m_PartialZ
The computed canonical partition function.
virtual double CalculatePressure()
Implementation of the equation of state functions.
virtual double GetGCEDensity(int i) const
Density of particle species i in the grand-canonical ensemble.
virtual void CalculatePartitionFunctions(double Vc=-1.)
Calculates all necessary canonical partition functions.
IdealGasFunctions::QStatsCalculationType CalculationType() const
Method to evaluate quantum statistics.
virtual void CalculateDensities()
Calculates the primordial and total (after decays) densities of all species.
Struct containing a set of quantum numbers: Baryon number, electric charge, strangeness, and charm.
virtual void CalculateTwoParticleCorrelations()
Computes the fluctuations and correlations of the primordial particle numbers.
std::vector< double > m_densities
std::vector< double > m_Corr
A vector of chemical factors.
virtual void ChangeTPS(ThermalParticleSystem *TPS)
Change the particle list.
std::vector< std::vector< double > > m_PrimCorrel
bool UsePartialChemicalEquilibrium()
Whether partial chemical equilibrium with additional chemical potentials is used. ...
ThermalModelEnsemble m_Ensemble
virtual bool IsConservedChargeCanonical(ConservedCharge::Name charge) const
Whether the given conserved charge is treated canonically.
std::vector< double > m_skewtot
void SetCalculationType(IdealGasFunctions::QStatsCalculationType type)
Sets the CalculationType() method to evaluate quantum statistics.
virtual void CalculateParticleChargeCorrelationMatrix()
Calculates the matrix of correlators between primordial (and also final) particle numbers and conserv...
Class implementing the Ideal HRG model.
int ElectricCharge() const
Particle&#39;s electric charge.
int Strangeness() const
Particle&#39;s strangeness.
virtual bool IsParticleCanonical(const ThermalParticle &part)
Determines whether the specified ThermalParticle is treat canonically or grand-canonically in the pre...
const ThermalModelParameters & Parameters() const
void ChangeTPS(ThermalParticleSystem *TPS)
Change the particle list.
The main namespace where all classes and functions of the Thermal-FIST library reside.
virtual void SetChemicalPotentials(const std::vector< double > &chem=std::vector< double >(0))
Sets the chemical potentials of all particles.
int m_IntegrationIterationsMultiplier
A multiplier to increase the number of iterations during the numerical integration used to calculate ...
std::map< QuantumNumbers, int > m_QNMap
Maps QuantumNumbers combinations to a 1-dimensional index.
int Statistics() const
Particle&#39;s statistics.