Thermal-FIST  1.3
Package for hadron resonance gas model applications
ThermalParticle.cpp
Go to the documentation of this file.
1 /*
2  * Thermal-FIST package
3  *
4  * Copyright (c) 2014-2019 Volodymyr Vovchenko
5  *
6  * GNU General Public License (GPLv3 or later)
7  */
9 
10 #include <fstream>
11 #include <iostream>
12 #include <sstream>
13 #include <cmath>
14 #include <cstdlib>
15 #include <algorithm>
16 
17 #include "HRGBase/Utility.h"
18 #include "HRGBase/xMath.h"
21 
22 using namespace std;
23 
24 namespace thermalfist {
25 
26  ThermalParticle::ThermalParticle(bool Stable, std::string Name, long long PDGID, double Deg, int Stat, double Mass,
27  int Strange, int Baryon, int Charge, double AbsS, double Width, double Threshold, int Charm, double AbsC, int Quark) :
28  m_Stable(Stable), m_AntiParticle(false), m_Name(Name), m_PDGID(PDGID), m_Degeneracy(Deg), m_Statistics(Stat), m_StatisticsOrig(Stat), m_Mass(Mass),
29  m_Strangeness(Strange), m_Baryon(Baryon), m_ElectricCharge(Charge), m_Charm(Charm), m_ArbitraryCharge(Baryon), m_AbsS(AbsS), m_AbsC(AbsC), m_Width(Width), m_Threshold(Threshold), m_Quark(Quark), m_Weight(1.)
30  {
33 
35 
37  if (m_Mass < 1.000) SetClusterExpansionOrder(5);
38  if (m_Mass < 0.200) SetClusterExpansionOrder(10);
39 
41  //SetResonanceWidthIntegrationType(BWTwoGamma);
43 
44  m_DecayType = ParticleDecayType::Default;
45 
47 
49 
50  }
51 
52 
54  {
55  }
56 
58  {
59  //if (PdgId() == 223) // omega(782)
60  // return true;
61  return ((ResonanceWidth() / Mass()) < 0.01);
62  }
63 
65  {
66  m_Width = width;
67  if (m_Width != 0.0) {
70  }
71  }
72 
74  {
75  m_Threshold = threshold;
76  if (m_Threshold < 0.0) {
77  printf("**WARNING** Trying to set negative decay threshold for %s, setting to zero instead", m_Name.c_str());
78  }
79  if (m_Width != 0.0) FillCoefficients();
80  }
81 
83  {
84  m_ThresholdDynamical = threshold;
85  if (m_ThresholdDynamical < 0.0) {
86  printf("**WARNING** Trying to set negative dynamical decay threshold for %s, setting to zero instead", m_Name.c_str());
87  }
88  }
89 
91  {
92  double Thr = m_Mass + m_Width;
93  for (size_t i = 0; i < m_Decays.size(); ++i) {
94  Thr = min(Thr, m_Decays[i].mM0);
95  }
96  m_ThresholdDynamical = Thr;
97  }
98 
100  {
101  if (shape != m_ResonanceWidthShape) {
102  m_ResonanceWidthShape = shape;
104  }
105  }
106 
108  {
109  m_ResonanceWidthIntegrationType = type;
111  if (type == ThermalParticle::eBW || type == ThermalParticle::eBWconstBR)
113  }
114 
115  double ThermalParticle::MassDistribution(double m) const
116  {
117  return MassDistribution(m, m_Width);
118  }
119 
120  double ThermalParticle::MassDistribution(double m, double width) const
121  {
122  if (width < 0.) width = m_Width;
123 
124  // Zero if outside the interval
125  //if (m_ResonanceWidthIntegrationType == BWTwoGamma) {
126  // double a = max(m_Threshold, m_Mass - 2.*m_Width);
127  // double b = m_Mass + 2.*m_Width;
128  // if (m < a || m > b)
129  // return 0.;
130  //}
131 
132  if (m_ResonanceWidthShape == RelativisticBreitWigner)
133  return m_Mass * width * m / ((m * m - m_Mass * m_Mass)*(m * m - m_Mass * m_Mass) + m_Mass * m_Mass*width*width);
134  else
135  return width / ((m - m_Mass)*(m - m_Mass) + width * width / 4.);
136  }
137 
138  void ThermalParticle::ReadDecays(string filename) {
139  m_Decays.resize(0);
140  ifstream fin(filename.c_str());
141  if (fin.is_open()) {
142  char cc[400];
143  double tmpbr;
144  while (fin >> tmpbr) {
145  ParticleDecayChannel decay;
146  decay.mBratio = tmpbr / 100.;
147  fin.getline(cc, 350);
148  stringstream ss;
149  ss << cc;
150  int tmpid;
151  while (ss >> tmpid) {
152  decay.mDaughters.push_back(tmpid);
153  }
154  m_Decays.push_back(decay);
155  }
156  }
157  }
158 
159  void ThermalParticle::CalculateThermalBranchingRatios(const ThermalModelParameters & params, bool useWidth, double mu)
160  {
161  if (!useWidth || m_Width == 0.0 || m_Width / m_Mass < 1.e-2 || m_ResonanceWidthIntegrationType != eBW) {
162  for (size_t j = 0; j < m_Decays.size(); ++j) {
163  m_Decays[j].mBratioAverage = m_Decays[j].mBratio;
164  }
165  }
166  else {
167  if (!(params.gammaq == 1.)) mu += log(params.gammaq) * GetAbsQ() * params.T;
168  if (!(params.gammaS == 1. || m_AbsS == 0.)) mu += log(params.gammaS) * m_AbsS * params.T;
169  if (!(params.gammaC == 1. || m_AbsC == 0.)) mu += log(params.gammaC) * m_AbsC * params.T;
170 
171  for (size_t j = 0; j < m_Decays.size(); ++j) {
172  m_Decays[j].mBratioAverage = 0.;
173  }
174 
175  double ret1 = 0., ret2 = 0., tmp = 0.;
176  for (size_t i = 0; i < m_xalldyn.size(); i++) {
177  tmp = m_walldyn[i];
178  double dens = IdealGasFunctions::IdealGasQuantity(IdealGasFunctions::ParticleDensity, m_QuantumStatisticsCalculationType, m_Statistics, params.T, mu, m_xalldyn[i], m_Degeneracy, m_ClusterExpansionOrder);
179  ret1 += tmp * dens;
180  ret2 += tmp;
181 
182  for (size_t j = 0; j < m_Decays.size(); ++j) {
183  const_cast<double&>(m_Decays[j].mBratioAverage) += tmp * dens * m_Decays[j].mBratioVsM[i];
184  }
185  }
186 
187  for (size_t j = 0; j < m_Decays.size(); ++j) {
188  if (ret1 != 0.0)
189  m_Decays[j].mBratioAverage /= ret1;
190  else
191  m_Decays[j].mBratioAverage = m_Decays[j].mBratio;
192  }
193  }
194  }
195 
196  std::vector<double> ThermalParticle::BranchingRatioWeights(const std::vector<double>& ms) const
197  {
198  std::vector<double> ret = ms;
199 
200  std::vector<double> mthr, br;
201  double tsum = 0.;
202  for (size_t i = 0; i < m_Decays.size(); ++i) {
203  mthr.push_back(m_Decays[i].mM0);
204  br.push_back(m_Decays[i].mBratio);
205  tsum += m_Decays[i].mBratio;
206  }
207  if (tsum < 1.) {
208  mthr.push_back(0.);
209  br.push_back(1. - tsum);
210  }
211  else if (tsum > 1.) {
212  for (size_t i = 0; i < br.size(); ++i)
213  br[i] *= 1. / tsum;
214  }
215 
216  for (size_t i = 0; i < ms.size(); ++i) {
217  double tw = 0.;
218  for (size_t j = 0; j < br.size(); ++j) {
219  if (mthr[j] <= ms[i])
220  tw += br[j];
221  }
222  ret[i] = tw;
223  }
224  return ret;
225  }
226 
227  ThermalParticle ThermalParticle::GenerateAntiParticle(/*ThermalParticleSystem *TPS*/) const
228  {
229  string name = Name();
230  if (BaryonCharge() == 0 && name[name.size() - 1] == '+')
231  name[name.size() - 1] = '-';
232  else if (BaryonCharge() == 0 && name[name.size() - 1] == '-')
233  name[name.size() - 1] = '+';
234  else
235  name = "anti-" + name;
236 
237  ThermalParticle ret = *this;
238  ret.SetName(name);
239  ret.SetPdgId(-PdgId());
243  ret.SetCharm(-Charm());
245  ret.SetAntiParticle(true);
246  // Decays are to be done separately from ThermalParticleSystem instance
247  // The code below is deprecated
248  /*if (TPS != NULL) {
249  ret.SetDecays(TPS->GetDecaysFromAntiParticle(Decays()));
250  ret.SetDecaysOriginal(ret.Decays());
251  }*/
252  return ret;
253  }
254 
256  {
257  bool ret = true;
258 
259  /*ret &= m_xlag32 == rhs.m_xlag32;
260  ret &= m_wlag32 == rhs.m_wlag32;
261  ret &= m_xleg == rhs.m_xleg;
262  ret &= m_wleg == rhs.m_wleg;
263  ret &= m_xleg32 == rhs.m_xleg32;
264  ret &= m_wleg32 == rhs.m_wleg32;*/
265 
266  ret &= m_Stable == rhs.m_Stable;
267  ret &= m_AntiParticle == rhs.m_AntiParticle;
268  ret &= m_Name == rhs.m_Name;
269  ret &= m_PDGID == rhs.m_PDGID;
270  ret &= m_Degeneracy == rhs.m_Degeneracy;
271  ret &= m_Statistics == rhs.m_Statistics;
272  ret &= m_StatisticsOrig == rhs.m_StatisticsOrig;
273  ret &= m_Mass == rhs.m_Mass;
274  ret &= m_QuantumStatisticsCalculationType == rhs.m_QuantumStatisticsCalculationType;
275  ret &= m_ClusterExpansionOrder == rhs.m_ClusterExpansionOrder;
276  ret &= m_Baryon == rhs.m_Baryon;
277  ret &= m_ElectricCharge == rhs.m_ElectricCharge;
278  ret &= m_Strangeness == rhs.m_Strangeness;
279  ret &= m_Charm == rhs.m_Charm;
280  ret &= m_Quark == rhs.m_Quark;
281  ret &= m_ArbitraryCharge == rhs.m_ArbitraryCharge;
282  ret &= m_AbsQuark == rhs.m_AbsQuark;
283  ret &= m_AbsS == rhs.m_AbsS;
284  ret &= m_AbsC == rhs.m_AbsC;
285  ret &= m_Width == rhs.m_Width;
286  ret &= m_Threshold == rhs.m_Threshold;
287  ret &= m_ThresholdDynamical == rhs.m_ThresholdDynamical;
288  ret &= m_ResonanceWidthShape == rhs.m_ResonanceWidthShape;
289  ret &= m_ResonanceWidthIntegrationType == rhs.m_ResonanceWidthIntegrationType;
290  ret &= m_Weight == rhs.m_Weight;
291  ret &= m_DecayType == rhs.m_DecayType;
292  ret &= m_Decays == rhs.m_Decays;
293  ret &= m_DecaysOrig == rhs.m_DecaysOrig;
294 
295  return ret;
296  }
297 
299  double sum = 0.;
300  for (size_t i = 0; i < m_Decays.size(); ++i) {
301  sum += m_Decays[i].mBratio;
302  }
303  for (size_t i = 0; i < m_Decays.size(); ++i) {
304  m_Decays[i].mBratio *= 1. / sum;
305  }
307  }
308 
310  {
311  //m_Decays = m_DecaysOrig;
312  for (size_t i = 0; i < m_Decays.size(); ++i) {
313  m_Decays[i].mBratio = m_DecaysOrig[i].mBratio;
314  }
316  }
317 
319  double a, b;
320  if (m_ResonanceWidthIntegrationType != BWTwoGamma && m_Threshold >= 0.) {
321  a = m_Threshold;
322  b = m_Mass + 2.*m_Width;
324  m_brweight = BranchingRatioWeights(m_xleg);
325  }
326  else {
327  a = max(m_Threshold, m_Mass - 2.*m_Width);
328  b = m_Mass + 2.*m_Width;
330  m_brweight = BranchingRatioWeights(m_xleg);
331  }
332 
333  // Old version
334  //if (m_Width / m_Mass<1e-1) { NumericalIntegration::GetCoefsIntegrateLegendre10(a, b, &m_xleg, &m_wleg); }
335  //else { NumericalIntegration::GetCoefsIntegrateLegendre32(a, b, &m_xleg, &m_wleg); }
336 
337  // New version
338  NumericalIntegration::GetCoefsIntegrateLegendre32(0., 1., &m_xleg32, &m_wleg32);
340  }
341 
342  // Mass-dependent widths
344  if (m_Width == 0.0) return;
345 
346  double a, b;
347 
348  if (m_Decays.size() == 0)
349  m_Threshold = m_ThresholdDynamical = m_Mass - 2.*m_Width + 1.e-6;
350 
351  //a = max(m_Threshold, m_ThresholdDynamical);
352  a = m_ThresholdDynamical;
353 
354  b = m_Mass + 2.*m_Width;
355  if (a >= m_Mass - 2.*m_Width) {
356  m_xlegpdyn.resize(0);
357  if (a >= m_Mass + 2.*m_Width)
358  m_xlegdyn.resize(0);
359  else
360  NumericalIntegration::GetCoefsIntegrateLegendre32(a, b, &m_xlegdyn, &m_wlegdyn);
361  }
362  else {
363  NumericalIntegration::GetCoefsIntegrateLegendre32(a, m_Mass - 2.*m_Width, &m_xlegpdyn, &m_wlegpdyn);
364  NumericalIntegration::GetCoefsIntegrateLegendre32(m_Mass - 2.*m_Width, b, &m_xlegdyn, &m_wlegdyn);
365  }
367 
368  m_vallegpdyn = m_xlegpdyn;
369  m_vallegdyn = m_xlegdyn;
370  m_vallagdyn = m_xlagdyn;
371 
372 
373  double tsumb = 0.;
374  double tC = 0.;
375  vector<double> tCP(m_Decays.size(), 0.);
376 
377  for (size_t i = 0; i < m_Decays.size(); ++i) {
378  tsumb += m_Decays[i].mBratio;
379  m_Decays[i].mBratioVsM.resize(0);
380  }
381 
382  for (size_t j = 0; j < m_xlegpdyn.size(); ++j) {
383  double twid = 0.;
384 
385  for (size_t i = 0; i < m_Decays.size(); ++i) {
386  twid += m_Decays[i].ModifiedWidth(m_xlegpdyn[j]) * m_Width;
387  }
388 
389  if (tsumb < 1.)
390  twid += (1. - tsumb) * m_Width;
391 
392  if (twid == 0.0) {
393  m_vallegpdyn[j] = 0.;
394  for (size_t i = 0; i < m_Decays.size(); ++i)
395  m_Decays[i].mBratioVsM.push_back(m_Decays[i].mBratio);
396  continue;
397  }
398 
399  for (size_t i = 0; i < m_Decays.size(); ++i) {
400  double ttwid = m_Decays[i].ModifiedWidth(m_xlegpdyn[j]) * m_Width;
401  m_Decays[i].mBratioVsM.push_back(ttwid / twid);
402  tCP[i] += m_wlegpdyn[j] * ttwid / twid * MassDistribution(m_xlegpdyn[j], twid);
403  }
404 
405  tC += m_wlegpdyn[j] * MassDistribution(m_xlegpdyn[j], twid);
406  m_vallegpdyn[j] = MassDistribution(m_xlegpdyn[j], twid);
407  }
408 
409  for (size_t j = 0; j < m_xlegdyn.size(); ++j) {
410  double twid = 0.;
411 
412  for (size_t i = 0; i < m_Decays.size(); ++i) {
413  twid += m_Decays[i].ModifiedWidth(m_xlegdyn[j]) * m_Width;
414  }
415 
416  if (tsumb < 1.)
417  twid += (1. - tsumb) * m_Width;
418 
419  if (twid == 0.0) {
420  m_vallegdyn[j] = 0.;
421  for (size_t i = 0; i < m_Decays.size(); ++i)
422  m_Decays[i].mBratioVsM.push_back(m_Decays[i].mBratio);
423  continue;
424  }
425 
426  for (size_t i = 0; i < m_Decays.size(); ++i) {
427  double ttwid = m_Decays[i].ModifiedWidth(m_xlegdyn[j]) * m_Width;
428  m_Decays[i].mBratioVsM.push_back(ttwid / twid);
429  tCP[i] += m_wlegdyn[j] * ttwid / twid * MassDistribution(m_xlegdyn[j], twid);
430  }
431 
432  tC += m_wlegdyn[j] * MassDistribution(m_xlegdyn[j], twid);
433  m_vallegdyn[j] = MassDistribution(m_xlegdyn[j], twid);
434  }
435 
436  for (size_t j = 0; j < m_xlagdyn.size(); ++j) {
437  double twid = 0.;
438  double tx = m_Mass + 2.*m_Width + m_xlagdyn[j] * m_Width;
439 
440  for (size_t i = 0; i < m_Decays.size(); ++i) {
441  twid += m_Decays[i].ModifiedWidth(tx) * m_Width;
442  }
443 
444  if (tsumb < 1.)
445  twid += (1. - tsumb) * m_Width;
446 
447  if (twid == 0.0) {
448  m_vallagdyn[j] = 0.;
449  for (size_t i = 0; i < m_Decays.size(); ++i)
450  m_Decays[i].mBratioVsM.push_back(m_Decays[i].mBratio);
451  continue;
452  }
453 
454  for (size_t i = 0; i < m_Decays.size(); ++i) {
455  double ttwid = m_Decays[i].ModifiedWidth(tx) * m_Width;
456  m_Decays[i].mBratioVsM.push_back(ttwid / twid);
457  tCP[i] += m_wlagdyn[j] * m_Width * ttwid / twid * MassDistribution(tx, twid);
458  }
459 
460  tC += m_wlagdyn[j] * m_Width * MassDistribution(tx, twid);
461  m_vallagdyn[j] = m_Width * MassDistribution(tx, twid);
462  }
463 
464  m_xalldyn.resize(0);
465  m_walldyn.resize(0);
466 
467  for (size_t j = 0; j < m_xlegpdyn.size(); ++j) {
468  m_xalldyn.push_back(m_xlegpdyn[j]);
469  m_walldyn.push_back(m_wlegpdyn[j] * m_vallegpdyn[j] / tC);
470  }
471 
472  for (size_t j = 0; j < m_xlegdyn.size(); ++j) {
473  m_xalldyn.push_back(m_xlegdyn[j]);
474  m_walldyn.push_back(m_wlegdyn[j] * m_vallegdyn[j] / tC);
475  }
476 
477  for (size_t j = 0; j < m_xlagdyn.size(); ++j) {
478  m_xalldyn.push_back(m_Mass + 2.*m_Width + m_xlagdyn[j] * m_Width);
479  m_walldyn.push_back(m_wlagdyn[j] * m_vallagdyn[j] / tC);
480  }
481 
482  m_densalldyn.resize(m_xalldyn.size());
483 
484  double tsum = 0.;
485  for (size_t j = 0; j < m_walldyn.size(); ++j) {
486  tsum += m_walldyn[j];
487  }
488 
489 
490  // // Output to file for debugging
491  // {
492  // char cc[300];
493  // sprintf(cc, "%d_width.dat", PdgId());
494  // FILE *f = fopen(cc, "w");
495 
496  // for (int j = 0; j < m_xlegpdyn.size(); ++j)
497  // fprintf(f, "%15lf%15E\n", m_xlegpdyn[j], m_vallegpdyn[j] / tC);
498 
499  // for (int j = 0; j < m_xlegdyn.size(); ++j)
500  // fprintf(f, "%15lf%15E\n", m_xlegdyn[j], m_vallegdyn[j] / tC);
501 
502  // for (int j = 0; j < m_xlagdyn.size(); ++j)
503  // fprintf(f, "%15lf%15E\n", m_Mass + 2.*m_Width + m_xlagdyn[j] * m_Width, m_vallagdyn[j] / m_Width / tC);
504 
505  // fclose(f);
506  // }
507 
508  }
509 
510  double ThermalParticle::TotalWidtheBW(double M) const
511  {
512  //if (m_ResonanceWidthIntegrationType != eBW)
513  // return m_Width;
514 
515  double tsumb = 0.0;
516  for (size_t i = 0; i < m_Decays.size(); ++i) {
517  tsumb += m_Decays[i].mBratio;
518  }
519 
520  double twid = 0.0;
521  for (size_t i = 0; i < m_Decays.size(); ++i) {
522  twid += m_Decays[i].ModifiedWidth(M) * m_Width;
523  }
524 
525  if (tsumb < 1.)
526  twid += (1. - tsumb) * m_Width;
527 
528  return twid;
529  }
530 
531  std::vector<double> ThermalParticle::BranchingRatiosM(double M, bool eBW) const
532  {
533  std::vector<double> ret(m_Decays.size(), 0.);
534 
535  if (!eBW || m_Width / m_Mass < 0.01) {
536  for (size_t i = 0; i < m_Decays.size(); ++i)
537  ret[i] = m_Decays[i].mBratio;
538 
539  return ret;
540  }
541 
542  double totwid = TotalWidtheBW(M);
543 
544  for (size_t i = 0; i < m_Decays.size(); ++i) {
545  double partialwid = m_Decays[i].ModifiedWidth(M) * m_Width;
546  ret[i] = partialwid / totwid;
547  }
548 
549  return ret;
550  }
551 
552  double ThermalParticle::ThermalMassDistribution(double M, double T, double Mu, double width)
553  {
554  return IdealGasFunctions::IdealGasQuantity(IdealGasFunctions::ParticleDensity, m_QuantumStatisticsCalculationType, m_Statistics, T, Mu, M, m_Degeneracy, m_ClusterExpansionOrder) * MassDistribution(M, width);
555  }
556 
557  double ThermalParticle::ThermalMassDistribution(double M, double T, double Mu)
558  {
559  return ThermalMassDistribution(M, T, Mu, TotalWidtheBW(M));
560  }
561 
562  void ThermalParticle::UseStatistics(bool enable) {
563  if (!enable) m_Statistics = 0;
564  else m_Statistics = m_StatisticsOrig;
565  }
566 
567  void ThermalParticle::SetMass(double mass)
568  {
569  m_Mass = mass;
570  if (m_Width != 0.0) {
573  }
574  }
575 
577  {
579  return BaryonCharge();
581  return ElectricCharge();
583  return Strangeness();
584  if (chg == ConservedCharge::CharmCharge)
585  return Charm();
586  return 0;
587  }
588 
590  return (m_Baryon == 0 && m_ElectricCharge == 0 && m_Strangeness == 0 && m_Charm == 0);
591  }
592 
593 
594  double ThermalParticle::Density(const ThermalModelParameters &params, IdealGasFunctions::Quantity type, bool useWidth, double mu) const {
595  if (!(params.gammaq == 1.)) mu += log(params.gammaq) * m_AbsQuark * params.T;
596  if (!(params.gammaS == 1. || m_AbsS == 0.)) mu += log(params.gammaS) * m_AbsS * params.T;
597  if (!(params.gammaC == 1. || m_AbsC == 0.)) mu += log(params.gammaC) * m_AbsC * params.T;
598 
599  //if (!useWidth || m_Mass == 0.0 || m_Width / m_Mass < 1.e-2 || m_ResonanceWidthIntegrationType == ZeroWidth) {
600  if (!useWidth || m_Mass == 0.0 || ZeroWidthEnforced() || m_ResonanceWidthIntegrationType == ZeroWidth) {
601  return IdealGasFunctions::IdealGasQuantity(type, m_QuantumStatisticsCalculationType, m_Statistics, params.T, mu, m_Mass, m_Degeneracy, m_ClusterExpansionOrder);
602  }
603 
604  int ind = m_xleg.size();
605  const vector<double> &x = m_xleg, &w = m_wleg;
606  double ret1 = 0., ret2 = 0., tmp = 0.;
607 
608  // Integration from m0 or M-2*Gamma to M+2*Gamma
609  if (m_ResonanceWidthIntegrationType != eBW && m_ResonanceWidthIntegrationType != eBWconstBR) {
610  for (int i = 0; i < ind; i++) {
611 
612  tmp = w[i] * MassDistribution(x[i]);
613 
614  if (m_ResonanceWidthIntegrationType == FullIntervalWeighted)
615  tmp *= m_brweight[i];
616 
617  double dens = IdealGasFunctions::IdealGasQuantity(type, m_QuantumStatisticsCalculationType, m_Statistics, params.T, mu, x[i], m_Degeneracy, m_ClusterExpansionOrder);
618 
619  ret1 += tmp * dens;
620  ret2 += tmp;
621  }
622  }
623 
624  // Integration from M+2*Gamma to infinity
625  if (m_ResonanceWidthIntegrationType == FullInterval || m_ResonanceWidthIntegrationType == FullIntervalWeighted) {
626  int ind2 = m_xlag32.size();
627  for (int i = 0; i < ind2; ++i) {
628  double tmass = m_Mass + 2.*m_Width + m_xlag32[i] * m_Width;
629  tmp = m_wlag32[i] * m_Width * MassDistribution(tmass);
630  double dens = IdealGasFunctions::IdealGasQuantity(type, m_QuantumStatisticsCalculationType, m_Statistics, params.T, mu, tmass, m_Degeneracy, m_ClusterExpansionOrder);
631 
632  ret1 += tmp * dens;
633  ret2 += tmp;
634  }
635  }
636 
637  if (m_ResonanceWidthIntegrationType == eBW || m_ResonanceWidthIntegrationType == eBWconstBR) {
638  for (size_t i = 0; i < m_xalldyn.size(); i++) {
639  tmp = m_walldyn[i];
640  double dens = IdealGasFunctions::IdealGasQuantity(type, m_QuantumStatisticsCalculationType, m_Statistics, params.T, mu, m_xalldyn[i], m_Degeneracy, m_ClusterExpansionOrder);
641  ret1 += tmp * dens;
642  ret2 += tmp;
643  }
644  }
645 
646  return ret1 / ret2;
647  }
648 
649  double ThermalParticle::DensityCluster(int n, const ThermalModelParameters & params, IdealGasFunctions::Quantity type, bool useWidth, double mu) const
650  {
651  double mn = 1.;
652  if ((abs(BaryonCharge()) & 1) && !(n & 1))
653  mn = -1.;
654 
655  if (!(params.gammaq == 1.)) mu += log(params.gammaq) * m_AbsQuark /*GetAbsQ()*/ * params.T;
656  if (!(params.gammaS == 1. || m_AbsS == 0.)) mu += log(params.gammaS) * m_AbsS * params.T;
657  if (!(params.gammaC == 1. || m_AbsC == 0.)) mu += log(params.gammaC) * m_AbsC * params.T;
658 
659  //if (!useWidth || m_Width / m_Mass < 1.e-2 || m_ResonanceWidthIntegrationType == ZeroWidth) {
660  if (!useWidth || ZeroWidthEnforced() || m_ResonanceWidthIntegrationType == ZeroWidth) {
661  return mn * IdealGasFunctions::IdealGasQuantity(type, m_QuantumStatisticsCalculationType, 0, params.T / static_cast<double>(n), mu, m_Mass, m_Degeneracy);
662  }
663 
664  int ind = m_xleg.size();
665  const vector<double> &x = m_xleg, &w = m_wleg;
666  double ret1 = 0., ret2 = 0., tmp = 0.;
667 
668  // Integration from m0 or M-2*Gamma to M+2*Gamma
669  if (m_ResonanceWidthIntegrationType != eBW && m_ResonanceWidthIntegrationType != eBWconstBR) {
670  for (int i = 0; i < ind; i++) {
671  tmp = w[i] * MassDistribution(x[i]);
672 
673  if (m_ResonanceWidthIntegrationType == FullIntervalWeighted)
674  tmp *= m_brweight[i];
675 
676  double dens = IdealGasFunctions::IdealGasQuantity(type, m_QuantumStatisticsCalculationType, 0, params.T / static_cast<double>(n), mu, x[i], m_Degeneracy);
677 
678  ret1 += tmp * dens;
679  ret2 += tmp;
680  }
681  }
682 
683  // Integration from M+2*Gamma to infinity
684  if (m_ResonanceWidthIntegrationType == FullInterval || m_ResonanceWidthIntegrationType == FullIntervalWeighted) {
685  int ind2 = m_xlag32.size();
686  for (int i = 0; i < ind2; ++i) {
687  double tmass = m_Mass + 2.*m_Width + m_xlag32[i] * m_Width;
688  tmp = m_wlag32[i] * m_Width * MassDistribution(tmass);
689  double dens = IdealGasFunctions::IdealGasQuantity(type, m_QuantumStatisticsCalculationType, 0, params.T / static_cast<double>(n), mu, tmass, m_Degeneracy);
690 
691  ret1 += tmp * dens;
692  ret2 += tmp;
693  }
694  }
695 
696  if (m_ResonanceWidthIntegrationType == eBW || m_ResonanceWidthIntegrationType == eBWconstBR) {
697  for (size_t i = 0; i < m_xalldyn.size(); i++) {
698  tmp = m_walldyn[i];
699  double dens = IdealGasFunctions::IdealGasQuantity(type, m_QuantumStatisticsCalculationType, 0, params.T / static_cast<double>(n), mu, m_xalldyn[i], m_Degeneracy);
700  ret1 += tmp * dens;
701  ret2 += tmp;
702  }
703  }
704 
705  return mn * ret1 / ret2;
706  }
707 
708 
709  double ThermalParticle::ScaledVariance(const ThermalModelParameters &params, bool useWidth, double mu) const {
710  if (m_Degeneracy == 0.0) return 1.;
711  if (m_Statistics == 0) return 1.;
712  double dens = Density(params, IdealGasFunctions::ParticleDensity, useWidth, mu);
713  if (dens == 0.) return 1.;
714  double ret = chi(2, params, useWidth, mu) / chi(1, params, useWidth, mu);
715  if (ret != ret) ret = 1.;
716  return ret;
717  }
718 
719  double ThermalParticle::Skewness(const ThermalModelParameters &params, bool useWidth, double mu) const
720  {
721  if (m_Degeneracy == 0) return 1.;
722  if (m_Statistics == 0) return 1.;
723  double dens = Density(params, IdealGasFunctions::ParticleDensity, useWidth, mu);
724  if (dens == 0.) return 1.;
725  double ret = chi(3, params, useWidth, mu) / chi(2, params, useWidth, mu);
726  if (ret != ret) ret = 1.;
727  return ret;
728  }
729 
730  double ThermalParticle::Kurtosis(const ThermalModelParameters &params, bool useWidth, double mu) const
731  {
732  if (m_Degeneracy == 0) return 1.;
733  if (m_Statistics == 0) return 1.;
734  double dens = Density(params, IdealGasFunctions::ParticleDensity, useWidth, mu);
735  if (dens == 0.) return 1.;
736  double ret = chi(4, params, useWidth, mu) / chi(2, params, useWidth, mu);
737  if (ret != ret) ret = 1.;
738  return ret;
739  }
740 
741  double ThermalParticle::FD(double k, double T, double mu, double m) const {
742  double arg = (sqrt(k*k + m * m) - mu) / T;
743  return 1. / (exp(arg) + 1.);
744  }
745 
746  double ThermalParticle::GetAbsQ() const {
747  if (m_Baryon == 0) return 2. - m_AbsC - m_AbsS;
748  else return abs(m_Baryon) * 3. - m_AbsC - m_AbsS;
749  }
750 
751  double ThermalParticle::GetCharge(int index) const {
752  if (index == 0) return (double)m_Baryon;
753  if (index == 1) return (double)m_ElectricCharge;
754  if (index == 2) return (double)m_Strangeness;
755  if (index == 3) return (double)m_Charm;
756  return 0.;
757  }
758 
759  double ThermalParticle::GetAbsCharge(int index) const {
760  if (index == 0) return fabs((double)m_Baryon);
761  if (index == 1) return fabs((double)m_ElectricCharge);
762  if (index == 2) return m_AbsS;
763  if (index == 3) return m_AbsC;
764  return 0.;
765  }
766 
767  double ThermalParticle::chi(int index, const ThermalModelParameters &params, bool useWidth, double mu) const {
768  if (index == 0) return Density(params, IdealGasFunctions::Pressure, useWidth, mu) / pow(params.T, 4) / pow(xMath::GeVtoifm(), 3);
769  if (index == 1) return Density(params, IdealGasFunctions::ParticleDensity, useWidth, mu) / pow(params.T, 3) / pow(xMath::GeVtoifm(), 3);
770  if (index == 2) return Density(params, IdealGasFunctions::chi2, useWidth, mu);
771  if (index == 3) return Density(params, IdealGasFunctions::chi3, useWidth, mu);
772  if (index == 4) return Density(params, IdealGasFunctions::chi4, useWidth, mu);
773  return 1.;
774  }
775 
776 } // namespace thermalfist
void RestoreBranchingRatios()
Restores all branching ratios to the original values.
Structure containing information about a single decay channel of a particle.
Definition: ParticleDecay.h:73
void SetAbsoluteQuark(double abschg)
Set absolute light quark content |u,d|.
static bool PrintDisclaimer()
Definition: Utility.cpp:47
double GeVtoifm()
A constant to transform GeV into fm .
Definition: xMath.h:27
double DensityCluster(int n, const ThermalModelParameters &params, IdealGasFunctions::Quantity type=IdealGasFunctions::ParticleDensity, bool useWidth=0, double mu=0.) const
void SetMass(double mass)
Set particle&#39;s mass [GeV].
int Charm() const
Particle&#39;s charm.
void GetCoefsIntegrateLaguerre32(std::vector< double > *x, std::vector< double > *w)
void NormalizeBranchingRatios()
Normalizes all branching ratios such that they sum up to 100%.
double Density(const ThermalModelParameters &params, IdealGasFunctions::Quantity type=IdealGasFunctions::ParticleDensity, bool useWidth=0, double mu=0.) const
Computes a specified ideal gas thermodynamic function.
std::vector< double > BranchingRatiosM(double M, bool eBW=true) const
(Energy-dependent) branching ratios
void SetPdgId(long long PdgId)
Set particle&#39;s particle&#39;s Particle Data Group (PDG) ID number.
Contains some helper functions.
void SetElectricCharge(int chg)
Set particle&#39;s electric charge.
static bool DisclaimerPrinted
Definition: Utility.h:27
void SetBaryonCharge(int chg)
Set particle&#39;s baryon number.
Energy-independent Breit-Wigner in +-2 interval.
long long PdgId() const
Particle&#39;s Particle Data Group (PDG) ID number.
Energy-dependent Breit-Wigner scheme (eBW)
double ResonanceWidth() const
Particle&#39;s width at the pole mass (GeV)
double IdealGasQuantity(Quantity quantity, QStatsCalculationType calctype, int statistics, double T, double mu, double m, double deg, int order=1)
Calculation of a generic ideal gas function.
Structure containing all thermal parameters of the model.
double GetCharge(int index) const
Get the quantum number numbered by the index.
void SetResonanceWidthShape(ResonanceWidthShape shape)
Set the resonance width profile to use.
double MassDistribution(double m) const
void FillCoefficientsDynamical()
Fills coefficients for mass integration in the eBW scheme.
Contains some extra mathematical functions used in the code.
void SetAntiParticle(bool antpar=true)
Set manually whether particle is an antiparticle.
double Skewness(const ThermalModelParameters &params, bool useWidth=0, double mu=0.) const
Computes the normalized skewness of particle number fluctuations in the ideal gas.
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...
double Kurtosis(const ThermalModelParameters &params, bool useWidth=0, double mu=0.) const
Computes the normalized excess kurtosis of particle number fluctuations in the ideal gas...
int BaryonCharge() const
Particle&#39;s baryon number.
void SetName(const std::string &name)
Set particle&#39;s name.
ResonanceWidthIntegration
Treatment of finite resonance widths.
std::vector< double > BranchingRatioWeights(const std::vector< double > &ms) const
Class containing all information about a particle specie.
ResonanceWidthShape
Relativistic vs non-relativistic Breit-Wigner shape.
double TotalWidtheBW(double M) const
Total width (eBW scheme) at a given mass.
const std::string & Name() const
Particle&#39;s name.
void SetCharm(int chg)
Set particle&#39;s charm.
void GetCoefsIntegrateLegendre32(double a, double b, std::vector< double > *x, std::vector< double > *w)
Energy-independent Breit-Wigner in full energy interval.
void SetClusterExpansionOrder(int order)
Set ClusterExpansionOrder()
Quantity
Identifies the thermodynamic function.
bool operator==(const ThermalParticle &rhs) const
double ThermalMassDistribution(double M, double T, double Mu, double width)
Mass distribution of a resonance in a thermal environment.
void UseStatistics(bool enable)
Use quantum statistics.
void GetCoefsIntegrateLegendre10(double a, double b, std::vector< double > *x, std::vector< double > *w)
void CalculateThermalBranchingRatios(const ThermalModelParameters &params, bool useWidth=0, double mu=0.)
Computes average decay branching ratios by integrating over the thermal mass distribution.
Name
Set of all conserved charges considered.
void ReadDecays(std::string filename="")
Read decays from a file and assign them to the particle.
bool IsNeutral() const
Whether particle is neutral one.
std::vector< long long > mDaughters
Definition: ParticleDecay.h:75
double Mass() const
Particle&#39;s mass [GeV].
double FD(double k, double T, double mu, double m) const
Fermi-Dirac distribution function.
ThermalParticle GenerateAntiParticle() const
Generates the anti-particle to the current particle specie.
bool ZeroWidthEnforced() const
Whether zero-width approximation is enforced for this particle species.
void SetResonanceWidthIntegrationType(ResonanceWidthIntegration type)
Set the ResonanceWidthIntegration scheme used to treat finite resonance widths.
Energy-independent Breit-Wigner in full energy interval with weighted branching ratios.
void SetCalculationType(IdealGasFunctions::QStatsCalculationType type)
Sets the CalculationType() method to evaluate quantum statistics.
Energy-dependent Breit-Wigner scheme (eBW) with constant branching ratios when evaluating feeddown...
int ElectricCharge() const
Particle&#39;s electric charge.
void FillCoefficients()
Fills coefficients for mass integration in the energy independent BW scheme.
int Strangeness() const
Particle&#39;s strangeness.
double GetAbsCharge(int index) const
Get the absolute value of a quantum number.
int ConservedCharge(ConservedCharge::Name chg) const
One of the four QCD conserved charges.
void SetStrangenessCharge(int chg)
Set particle&#39;s strangeness.
double ArbitraryCharge() const
Arbitrary (auxiliary) charge assigned to particle.
void SetDecayThresholdMass(double threshold)
Set the decays threshold mass.
The main namespace where all classes and functions of the Thermal-FIST library reside.
void SetDecayThresholdMassDynamical(double threshold)
Set the threshold mass manually for use in the eBW scheme.
void SetArbitraryCharge(double arbchg)
Assigns arbitrary (auxiliary) charge to particle.
void SetResonanceWidth(double width)
Sets the particle&#39;s width at the pole mass.
double chi(int index, const ThermalModelParameters &params, bool useWidth=0, double mu=0.) const
Computes the ideal gas generalized susceptibility .