Thermal-FIST  1.3
Package for hadron resonance gas model applications
ThermalParticleSystem.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 <algorithm>
12 #include <queue>
13 #include <iostream>
14 #include <iomanip>
15 #include <sstream>
16 #include <set>
17 #include <cmath>
18 #include <cstdlib>
19 
20 #include "HRGBase/Utility.h"
21 
22 using namespace std;
23 
24 namespace thermalfist {
25 
26  namespace {
28  bool cmpParticleMass(const ThermalParticle &a, const ThermalParticle &b) {
29  return (a.Mass() < b.Mass());
30  }
31 
34  bool cmpParticleMassAndPdg(const ThermalParticle& a, const ThermalParticle& b) {
35  if (a.Mass() == b.Mass()) {
36  if (abs(a.PdgId()) != abs(b.PdgId()))
37  return abs(a.PdgId()) < abs(b.PdgId());
38  return (a.PdgId() > b.PdgId());
39  }
40  return (a.Mass() < b.Mass());
41  }
42 
44  bool cmpParticlePDG(const ThermalParticle &a, const ThermalParticle &b) {
45  if (abs(a.Charm()) != abs(b.Charm())) return (abs(a.Charm()) < abs(b.Charm()));
46  if (abs(a.AbsoluteCharm()) != abs(b.AbsoluteCharm())) return (abs(a.AbsoluteCharm()) < abs(b.AbsoluteCharm()));
47  if (abs(a.BaryonCharge()) != abs(b.BaryonCharge())) return (abs(a.BaryonCharge()) < abs(b.BaryonCharge()));
48  if (abs(a.Strangeness()) != abs(b.Strangeness())) return (abs(a.Strangeness()) < abs(b.Strangeness()));
49  if (a.Mass() == b.Mass()) {
50  if (abs(a.PdgId()) != abs(b.PdgId()))
51  return abs(a.PdgId()) < abs(b.PdgId());
52  return (a.PdgId() > b.PdgId());
53  }
54  return (a.Mass() < b.Mass());
55  }
56  }
57 
58  const std::string ThermalParticleSystem::flag_no_antiparticles = "no_antiparticles";
59  const std::string ThermalParticleSystem::flag_nostrangeness = "no_strangeness";
60  const std::string ThermalParticleSystem::flag_nocharm = "no_charm";
61  const std::string ThermalParticleSystem::flag_nonuclei = "no_nuclei";
62  const std::string ThermalParticleSystem::flag_noexcitednuclei = "no_excitednuclei";
63 
64 
65  ThermalParticleSystem::ThermalParticleSystem(const std::vector<std::string>& ListFiles, const std::vector<std::string>& DecayFiles, const std::set<std::string>& flags, double mcut)
66  {
67  Initialize(ListFiles, DecayFiles, flags, mcut);
68  }
69 
70  ThermalParticleSystem::~ThermalParticleSystem(void)
71  {
72  }
73 
74  ThermalParticle::ParticleDecaysVector ThermalParticleSystem::GetDecaysFromAntiParticle(const ThermalParticle::ParticleDecaysVector& Decays) {
76  for (unsigned int i = 0; i < ret.size(); ++i) {
77  for (unsigned int j = 0; j < ret[i].mDaughters.size(); ++j) {
78  if (m_PDGtoID.count(-ret[i].mDaughters[j]) > 0) ret[i].mDaughters[j] = -ret[i].mDaughters[j];
79  }
80  }
81  return ret;
82  }
83 
84  void ThermalParticleSystem::ProcessDecays()
85  {
86  FillResonanceDecays();
87  FillResonanceDecaysByFeeddown();
88  }
89 
90  void ThermalParticleSystem::FillDecayProperties()
91  {
92  for (size_t i = 0; i < m_Particles.size(); ++i) {
93  if (m_Particles[i].Decays().size() != 0) {
94  double tsumb = 0.;
95 
96  for (size_t j = 0; j < m_Particles[i].Decays().size(); ++j) {
97 
98  m_Particles[i].Decays()[j].mPole = m_Particles[i].Mass();
99 
100  std::string tname = "";
101 
102  double M0 = 0.;
103  double tS = 0.;
104  for (size_t k = 0; k < m_Particles[i].Decays()[j].mDaughters.size(); ++k) {
105  int tid = PdgToId(m_Particles[i].Decays()[j].mDaughters[k]);
106  if (tid != -1) {
107  M0 += m_Particles[tid].Mass();
108  tS += max(0., (m_Particles[tid].Degeneracy() - 1.) / 2.);
109  if (k != 0)
110  tname += " - ";
111  tname += m_Particles[tid].Name();
112  }
113  }
114  m_Particles[i].Decays()[j].mM0 = M0;
115  m_Particles[i].Decays()[j].mL = abs(max(0., (m_Particles[i].Degeneracy() - 1.) / 2.) - tS);
116 
117  tsumb += m_Particles[i].Decays()[j].mBratio;
118  m_Particles[i].Decays()[j].mBratioAverage = m_Particles[i].Decays()[j].mBratio;
119 
120  if (tname.size() > 0)
121  m_Particles[i].Decays()[j].mChannelName = tname;
122  }
123  }
124  m_Particles[i].CalculateAndSetDynamicalThreshold();
125  m_Particles[i].FillCoefficientsDynamical();
126  }
127  }
128 
129  void ThermalParticleSystem::FillDecayThresholds()
130  {
131  for (size_t i = 0; i < m_Particles.size(); ++i) {
132  if (m_Particles[i].Decays().size() != 0) {
133  for (size_t j = 0; j < m_Particles[i].Decays().size(); ++j) {
134  double M0 = 0.;
135  for (size_t k = 0; k < m_Particles[i].Decays()[j].mDaughters.size(); ++k) {
136  if (PdgToId(m_Particles[i].Decays()[j].mDaughters[k]) != -1)
137  M0 += m_Particles[PdgToId(m_Particles[i].Decays()[j].mDaughters[k])].Mass();
138  }
139  m_Particles[i].Decays()[j].mM0 = M0;
140  }
141  m_Particles[i].FillCoefficients();
142  }
143  }
144  }
145 
146  void ThermalParticleSystem::FillResonanceDecays() {
147  m_DecayContributionsByFeeddown[Feeddown::StabilityFlag].resize(m_Particles.size());
148  m_DecayCumulants.resize(m_Particles.size());
149  m_DecayProbabilities.resize(m_Particles.size());
150  for (size_t i = 0; i < m_Particles.size(); ++i) {
151  m_DecayContributionsByFeeddown[Feeddown::StabilityFlag][i].resize(0);
152  m_DecayProbabilities[i].resize(0);
153  m_DecayCumulants[i].resize(0);
154  }
155  for (int i = static_cast<int>(m_Particles.size()) - 1; i >= 0; i--)
156  if (!m_Particles[i].IsStable()) {
157  GoResonance(i, i, 1.);
158  }
159 
160  for (size_t i = 0; i < m_Particles.size(); ++i) {
161  for (size_t j = 0; j < m_DecayContributionsByFeeddown[Feeddown::StabilityFlag][i].size(); ++j) {
162  SingleDecayContribution &DecayContrib = m_DecayContributionsByFeeddown[Feeddown::StabilityFlag][i][j];
163  vector<double> tmp = GoResonanceDecayProbs(DecayContrib.second, i, true);
164  if (tmp.size() > 1) m_DecayProbabilities[i].push_back(make_pair(tmp, DecayContrib.second));
165  }
166  for (size_t j = 0; j < m_DecayProbabilities[i].size(); ++j) {
167  double tmp = 0., tmp2 = 0., tmp3 = 0., tmp4 = 0.;
168  for (int jj = 0; jj < static_cast<int>(m_DecayProbabilities[i][j].first.size()); ++jj) {
169  tmp += m_DecayProbabilities[i][j].first[jj] * jj;
170  tmp2 += m_DecayProbabilities[i][j].first[jj] * jj * jj;
171  tmp3 += m_DecayProbabilities[i][j].first[jj] * jj * jj * jj;
172  tmp4 += m_DecayProbabilities[i][j].first[jj] * jj * jj * jj * jj;
173  }
174  double n2 = 0., n3 = 0., n4 = 0.;
175  n2 = tmp2 - tmp * tmp;
176  n3 = tmp3 - 3. * tmp2 * tmp + 2. * tmp * tmp * tmp;
177  n4 = tmp4 - 4. * tmp3 * tmp + 6. * tmp2 * tmp * tmp - 3. * tmp * tmp * tmp * tmp - 3. * n2 * n2;
178  vector<double> moments(0);
179  moments.push_back(tmp);
180  moments.push_back(n2);
181  moments.push_back(n3);
182  moments.push_back(n4);
183  m_DecayCumulants[i].push_back(make_pair(moments, m_DecayProbabilities[i][j].second));
184  }
185  }
186 
187  m_DecayDistributionsMap.resize(m_Particles.size());
188  m_ResonanceFinalStatesDistributions.resize(m_Particles.size());
189  for (size_t i = 0; i < m_Particles.size(); ++i) {
190  m_ResonanceFinalStatesDistributions[i].resize(0);
191  m_DecayDistributionsMap[i].resize(0);
192  }
193  for (size_t i = 0; i < m_Particles.size(); ++i) {
194  m_ResonanceFinalStatesDistributions[i] = GoResonanceDecayDistributions(i, true);
195  }
196  // Clear m_DecayDistributionsMap and memory it occupies
197  std::vector< std::vector< std::pair<double, std::vector<int> > > >().swap(m_DecayDistributionsMap);
198 
199  for (size_t i = 0; i < m_Particles.size(); ++i) {
200  vector<int> nchtyp(0);
201  nchtyp.push_back(0);
202  nchtyp.push_back(1);
203  nchtyp.push_back(-1);
204 
205  m_Particles[i].Nch().resize(0);
206  m_Particles[i].DeltaNch().resize(0);
207 
208  for (int nti = 0; nti < 3; nti++) {
209  vector<double> prob = GoResonanceDecayProbsCharge(i, nchtyp[nti], true);
210  double tmp = 0., tmp2 = 0., tmp3 = 0., tmp4 = 0.;
211  for (int jj = 0; jj < static_cast<int>(prob.size()); ++jj) {
212  tmp += prob[jj] * jj;
213  tmp2 += prob[jj] * jj * jj;
214  tmp3 += prob[jj] * jj * jj * jj;
215  tmp4 += prob[jj] * jj * jj * jj * jj;
216  }
217  double n2 = 0., n3 = 0., n4 = 0.;
218  n2 = tmp2 - tmp * tmp;
219  n3 = tmp3 - 3. * tmp2 * tmp + 2. * tmp * tmp * tmp;
220  n4 = tmp4 - 4. * tmp3 * tmp + 6. * tmp2 * tmp * tmp - 3. * tmp * tmp * tmp * tmp - 3. * n2 * n2;
221  m_Particles[i].Nch().push_back(tmp);
222  m_Particles[i].DeltaNch().push_back(n2);
223  }
224 
225  }
226  }
227 
228 
229  void ThermalParticleSystem::GoResonance(int ind, int startind, double BR) {
230  DecayContributionsToParticle& DecayContrib = m_DecayContributionsByFeeddown[Feeddown::StabilityFlag][ind];
231  if (ind != startind && DecayContrib.size() > 0 && DecayContrib[DecayContrib.size() - 1].second == startind)
232  {
233  DecayContrib[DecayContrib.size() - 1].first += BR;
234  }
235  else if (ind != startind)
236  DecayContrib.push_back(make_pair(BR, startind));
237 
238  if (!m_Particles[ind].IsStable()) {
239  for (size_t i = 0; i < m_Particles[ind].Decays().size(); ++i) {
240  const ParticleDecayChannel& decaychannel = m_Particles[ind].Decays()[i];
241  double tbr = decaychannel.mBratio;
242 
243  if (m_ResonanceWidthIntegrationType == ThermalParticle::eBW && ind == startind)
244  tbr = decaychannel.mBratioAverage;
245 
246  for (size_t j = 0; j < decaychannel.mDaughters.size(); ++j) {
247  if (m_PDGtoID.count(decaychannel.mDaughters[j]) != 0)
248  GoResonance(m_PDGtoID[decaychannel.mDaughters[j]], startind, BR*tbr);
249  }
250  }
251  }
252  }
253 
254  std::vector<double> ThermalParticleSystem::GoResonanceDecayProbs(int ind, int goalind, bool firstdecay) {
255  std::vector<double> ret(1, 0.);
256  if (m_Particles[ind].IsStable()) {
257  if (ind == goalind) ret.push_back(1.);
258  else ret[0] = 1.;
259  return ret;
260  }
261  else if (ind == goalind) {
262  ret.push_back(1.);
263  return ret;
264  }
265  else {
266  ret[0] = 0.;
267  vector<double> tret;
268  for (size_t i = 0; i < m_Particles[ind].Decays().size(); ++i) {
269  double tbr = m_Particles[ind].Decays()[i].mBratio;
270  if (m_ResonanceWidthIntegrationType == ThermalParticle::eBW && firstdecay)
271  tbr = m_Particles[ind].Decays()[i].mBratioAverage;
272 
273  tret.resize(1);
274  tret[0] = 1.;
275  for (size_t j = 0; j < m_Particles[ind].Decays()[i].mDaughters.size(); ++j) {
276  if (m_PDGtoID.count(m_Particles[ind].Decays()[i].mDaughters[j]) != 0) {
277  vector<double> tmp = GoResonanceDecayProbs(m_PDGtoID[m_Particles[ind].Decays()[i].mDaughters[j]], goalind);
278  vector<double> tmp2(tret.size() + tmp.size() - 1, 0.);
279  for (size_t i1 = 0; i1 < tret.size(); ++i1)
280  for (size_t i2 = 0; i2 < tmp.size(); ++i2)
281  tmp2[i1 + i2] += tret[i1] * tmp[i2];
282  tret = tmp2;
283  }
284  }
285  if (ret.size() < tret.size()) ret.resize(tret.size(), 0.);
286  for (size_t j = 0; j < tret.size(); ++j)
287  ret[j] += tbr * tret[j];
288  }
289  double totprob = 0.;
290  for (size_t i = 0; i < ret.size(); ++i)
291  totprob += ret[i];
292  if (totprob > 1.) {
293  for (size_t i = 0; i < ret.size(); ++i)
294  ret[i] *= 1. / totprob;
295  }
296  else {
297  ret[0] += 1. - totprob;
298  }
299  return ret;
300  }
301  //return ret;
302  }
303 
304  std::vector<double> ThermalParticleSystem::GoResonanceDecayProbsCharge(int ind, int nch, bool firstdecay)
305  {
306  bool fl = false;
307  int tQ = m_Particles[ind].ElectricCharge();
308  if (nch == 0 && tQ != 0)
309  fl = true;
310  if (nch == 1 && tQ > 0)
311  fl = true;
312  if (nch == -1 && tQ < 0)
313  fl = true;
314 
315  std::vector<double> ret(1, 0.);
316  if (m_Particles[ind].IsStable()) {
317  if (fl) ret.push_back(1.);
318  else ret[0] = 1.;
319  return ret;
320  }
321  else {
322  ret[0] = 0.;
323  vector<double> tret;
324  for (size_t i = 0; i < m_Particles[ind].Decays().size(); ++i) {
325  double tbr = m_Particles[ind].Decays()[i].mBratio;
326  if (m_ResonanceWidthIntegrationType == ThermalParticle::eBW && firstdecay)
327  tbr = m_Particles[ind].Decays()[i].mBratioAverage;
328 
329  tret.resize(1);
330  tret[0] = 1.;
331  for (size_t j = 0; j < m_Particles[ind].Decays()[i].mDaughters.size(); ++j) {
332  if (m_PDGtoID.count(m_Particles[ind].Decays()[i].mDaughters[j]) != 0) {
333  vector<double> tmp = GoResonanceDecayProbsCharge(m_PDGtoID[m_Particles[ind].Decays()[i].mDaughters[j]], nch);
334  vector<double> tmp2(tret.size() + tmp.size() - 1, 0.);
335  for (size_t i1 = 0; i1 < tret.size(); ++i1)
336  for (size_t i2 = 0; i2 < tmp.size(); ++i2)
337  tmp2[i1 + i2] += tret[i1] * tmp[i2];
338  tret = tmp2;
339  }
340  }
341  if (ret.size() < tret.size())
342  ret.resize(tret.size(), 0.);
343  for (size_t j = 0; j < tret.size(); ++j)
344  ret[j] += tbr * tret[j];
345  }
346  double totprob = 0.;
347  for (size_t i = 0; i < ret.size(); ++i)
348  totprob += ret[i];
349  if (totprob > 1.) {
350  for (size_t i = 0; i < ret.size(); ++i)
351  ret[i] *= 1. / totprob;
352  }
353  else {
354  ret[0] += 1. - totprob;
355  }
356  return ret;
357  }
358  //return ret;
359  }
360 
361  ThermalParticleSystem::ResonanceFinalStatesDistribution ThermalParticleSystem::GoResonanceDecayDistributions(int ind, bool firstdecay)
362  {
363  if (!firstdecay && m_DecayDistributionsMap[ind].size() != 0)
364  return m_DecayDistributionsMap[ind];
365 
366 
367  std::vector< std::pair<double, std::vector<int> > > retorig(1);
368  retorig[0].first = 1.;
369  retorig[0].second = std::vector<int>(m_Particles.size(), 0);
370  retorig[0].second[ind] = 1;
371 
372  std::vector< std::pair<double, std::vector<int> > > ret(0);
373 
374  ThermalParticle &tpart = m_Particles[ind];
375 
376  if (tpart.IsStable()) {
377  m_ResonanceFinalStatesDistributions[ind] = retorig;
378  return retorig;
379  }
380 
381  for (size_t i = 0; i < tpart.Decays().size(); ++i) {
382  double tbr = tpart.Decays()[i].mBratio;
383  if (m_ResonanceWidthIntegrationType == ThermalParticle::eBW && firstdecay)
384  tbr = m_Particles[ind].Decays()[i].mBratioAverage;
385 
386  std::vector< std::pair<double, std::vector<int> > > tret = retorig;
387 
388  for (size_t j = 0; j < tpart.Decays()[i].mDaughters.size(); ++j) {
389  if (m_PDGtoID.count(tpart.Decays()[i].mDaughters[j]) != 0) {
390 
391  std::vector< std::pair<double, std::vector<int> > > tmp = GoResonanceDecayDistributions(m_PDGtoID[tpart.Decays()[i].mDaughters[j]]);
392  std::vector< std::pair<double, std::vector<int> > > tmp2(tret.size() * tmp.size());
393  for (int i1 = 0; i1 < static_cast<int>(tret.size()); ++i1) {
394  for (int i2 = 0; i2 < static_cast<int>(tmp.size()); ++i2) {
395  tmp2[i1*tmp.size() + i2].first = tret[i1].first * tmp[i2].first;
396  tmp2[i1*tmp.size() + i2].second.resize(m_Particles.size());
397  for (size_t jj = 0; jj < tmp2[i1*tmp.size() + i2].second.size(); ++jj)
398  tmp2[i1*tmp.size() + i2].second[jj] = tret[i1].second[jj] + tmp[i2].second[jj];
399  }
400  }
401  tret = tmp2;
402 
403  // Restrict maximum number of channels to 1500, otherwise memory is an issue, relevant for the THERMUS-3.0 table
404  if (tret.size() > 1500) {
405  printf("**WARNING** %s (%lld) Decay Distributions: Too large array, cutting the number of channels to 1500!\n",
406  m_Particles[ind].Name().c_str(),
407  m_Particles[ind].PdgId());
409  }
410  }
411  }
412 
413  for (size_t j = 0; j < tret.size(); ++j) {
414  tret[j].first *= tbr;
415  ret.push_back(tret[j]);
416  }
417  }
418 
419  // Restrict maximum number of channels to 1500, otherwise memory is an issue, relevant for the THERMUS-3.0 table
420  if (ret.size() > 1500) {
421  printf("**WARNING** %s (%lld) Decay Distributions: Too large array, cutting the number of channels to 1500!\n",
422  m_Particles[ind].Name().c_str(),
423  m_Particles[ind].PdgId());
425  }
426 
427  double totprob = 0.;
428  for (size_t i = 0; i < ret.size(); ++i)
429  totprob += ret[i].first;
430  if (totprob > 1.) {
431  for (size_t i = 0; i < ret.size(); ++i)
432  ret[i].first *= 1. / totprob;
433  }
434  else if (totprob < 1.) {
435  double emptyprob = 1. - totprob;
436  ret.push_back(std::make_pair(emptyprob, retorig[0].second));
437  }
438 
439  if (!firstdecay)
440  m_DecayDistributionsMap[ind] = ret;
441 
442  // Debugging
443 
444  //if (tpart.BaryonCharge() == 1) {
445  // printf("Checking baryon number conservation in decays for %d\n", tpart.PdgId());
446  // double tBav = 0.;
447  // for (int i = 0; i < ret.size(); ++i) {
448  // double tbr = ret[i].first;
449  // for (int j = 0; j < ret[i].second.size(); ++j)
450  // if (m_Particles[j].IsStable())
451  // tBav += tbr * ret[i].second[j] * m_Particles[j].BaryonCharge();
452  // }
453  // printf("<B> = %lf\n", tBav);
454  // //printf("Decay distributions for %d\n", tpart.PdgId());
455  // //for (int i = 0; i < ret.size(); ++i) {
456  // // printf("%lf\n", ret[i].first);
457  // // for (int j = 0; j < ret[i].second.size(); ++j)
458  // // if (ret[i].second[j] > 0)
459  // // printf("%d: %d\n", m_Particles[j].PdgId(), ret[i].second[j]);
460  // //}
461  //}
462 
463  return ret;
464  }
465 
466  bool ThermalParticleSystem::AcceptParticle(const ThermalParticle& part, const std::set<std::string>& flags, double mcut) const
467  {
468  if (mcut >= 0. && part.Mass() > mcut)
469  return false;
470  if (flags.count(ThermalParticleSystem::flag_nostrangeness) > 0 && part.AbsoluteStrangeness() != 0)
471  return false;
472  if (flags.count(ThermalParticleSystem::flag_nocharm) > 0 && part.AbsoluteCharm() != 0)
473  return false;
474  if (flags.count(ThermalParticleSystem::flag_nonuclei) > 0 && abs(part.BaryonCharge() > 1))
475  return false;
476  if (flags.count(ThermalParticleSystem::flag_noexcitednuclei) > 0 && abs(part.BaryonCharge() > 1) && !part.IsStable())
477  return false;
478  return true;
479  }
480 
481  void ThermalParticleSystem::LoadList(const std::vector<std::string>& ListFiles, const std::vector<std::string>& DecayFiles, const std::set<std::string>& flags, double mcut)
482  {
483  m_NumberOfParticles = 0;
484  m_Particles.resize(0);
485  m_PDGtoID.clear();
486 
487  m_NumBaryons = m_NumCharged = m_NumStrange = m_NumCharmed = 0;
488 
489  for(int i = 0; i < ListFiles.size(); ++i)
490  AddParticlesToListFromFile(ListFiles[i], flags, mcut);
491 
492  FinalizeList();
493 
494  std::vector<std::string> tDecayFiles = DecayFiles;
495  if (tDecayFiles.size() == 1 && tDecayFiles[0] == "")
496  tDecayFiles.clear();
497 
498  if (tDecayFiles.size() == 0 && ListFiles.size() > 0) {
499  for (size_t ilist = 0; ilist < ListFiles.size(); ++ilist) {
500  string decayprefix = "";
501  string decayprefixfile = "";
502 
503  for (int i = ListFiles[ilist].size() - 1; i >= 0; --i) {
504  if (ListFiles[ilist][i] == '\\' || ListFiles[ilist][i] == '/')
505  {
506  decayprefix = ListFiles[ilist].substr(0, i + 1);
507  break;
508  }
509  decayprefixfile += ListFiles[ilist][i];
510  }
511 
512  reverse(decayprefixfile.begin(), decayprefixfile.end());
513 
514 
515  string DecayFile = "";
516  if (decayprefixfile.substr(0, 4) == "list") {
517  DecayFile = decayprefix + "decays" + decayprefixfile.substr(4);
518  }
519  else {
520  DecayFile = decayprefix + "decays.dat";
521  }
522 
523  if (ilist == 0)
524  tDecayFiles.push_back(decayprefix + "decays.dat");
525 
526  tDecayFiles.push_back(DecayFile);
527  }
528  }
529 
530  LoadDecays(tDecayFiles, flags);
531 
532  SetResonanceWidthShape(m_ResonanceWidthShape);
533  SetResonanceWidthIntegrationType(m_ResonanceWidthIntegrationType);
534  SetCalculationType(m_QStatsCalculationType);
535 
536  CheckDecayChannelsAreSpecified();
537  }
538 
539  void ThermalParticleSystem::LoadList(const std::string& InputFile, const std::string& DecayFile, bool GenAntiP, double mcut) {
540 
541  std::set<std::string> flags;
542  if (!GenAntiP)
543  flags.insert(ThermalParticleSystem::flag_no_antiparticles);
544 
545  std::vector<std::string> DecayFiles(0);
546  if (DecayFile != "")
547  DecayFiles.push_back(DecayFile);
548 
549  LoadList(std::vector<std::string>(1, InputFile), DecayFiles, flags, mcut);
550  }
551 
552  void ThermalParticleSystem::AddParticlesToListFromFile(const std::string& InputFile, const std::set<std::string>& flags, double mcut)
553  {
554  ifstream fin;
555  fin.open(InputFile.c_str());
556  if (fin.is_open()) {
557 
558  char tmpc[2000];
559  fin.getline(tmpc, 2000);
560  string tmp = string(tmpc);
561  vector<string> elems = CuteHRGHelper::split(tmp, '#');
562 
563  int flnew = 0;
564  if (elems.size() < 1 || CuteHRGHelper::split(elems[0], ';').size() < 4)
565  flnew = 1;
566  else
567  flnew = 0;
568 
569  fin.clear();
570  fin.seekg(0, ios::beg);
571 
572  if (flnew == 1)
573  LoadTable_NewFormat(fin, flags, mcut);
574  else
575  LoadTable_OldFormat(fin, flags, mcut);
576 
577  fin.close();
578 
579  }
580  }
581 
582  void ThermalParticleSystem::LoadTable_OldFormat(std::ifstream & fin, const std::set<std::string>& flags, double mcut)
583  {
584  bool GenerateAntiParticles = (flags.count(ThermalParticleSystem::flag_no_antiparticles) == 0);
585  if (fin.is_open()) {
586  string tmp;
587  char tmpc[500];
588  fin.getline(tmpc, 500);
589  tmp = string(tmpc);
590  while (1) {
591  vector<string> fields = CuteHRGHelper::split(tmp, ';');
592  if (fields.size() < 14) break;
593  int stable, spin, stat, str, bary, chg, charm;
594  long long pdgid;
595  double mass, width, threshold, abss, absc, radius = 0.5;
596  string name, decayname = "";
597  stable = atoi(fields[0].c_str());
598  name = fields[1];
599  //pdgid = atoi(fields[2].c_str());
600  pdgid = stringToLongLong(fields[2]);
601  spin = atoi(fields[3].c_str());
602  stat = atoi(fields[4].c_str());
603  mass = atof(fields[5].c_str());
604  str = atoi(fields[6].c_str());
605  bary = atoi(fields[7].c_str());
606  chg = atoi(fields[8].c_str());
607  charm = atoi(fields[9].c_str());
608  abss = atof(fields[10].c_str());
609  absc = atof(fields[11].c_str());
610  width = atof(fields[12].c_str());
611  threshold = atof(fields[13].c_str());
612  if (fields.size() >= 15) radius = atof(fields[14].c_str());
613  if (fields.size() == 16) decayname = fields[15];
614 
615  ThermalParticle part_candidate = ThermalParticle(static_cast<bool>(stable), name, pdgid, static_cast<double>(spin), stat, mass, str, bary, chg, abss, width, threshold, charm, absc);
616 
617  //if (mcut >= 0. && mass > mcut) {
618  if (!AcceptParticle(part_candidate, flags, mcut) || m_PDGtoID.count(pdgid) != 0) {
619  fin.getline(tmpc, 500);
620  tmp = string(tmpc);
621  continue;
622  }
623 
624  if (bary != 0) m_NumBaryons++;
625  if (chg != 0) m_NumCharged++;
626  if (str != 0) m_NumStrange++;
627  if (charm != 0) m_NumCharmed++;
628 
629  m_Particles.push_back(part_candidate);
630  m_PDGtoID[pdgid] = m_Particles.size() - 1;
631  m_NumberOfParticles++;
632 
633  if (GenerateAntiParticles && !(bary == 0 && chg == 0 && str == 0 && charm == 0) && (m_PDGtoID.count(-pdgid) == 0)) {
634 
635  if (bary != 0) m_NumBaryons++;
636  if (chg != 0) m_NumCharged++;
637  if (str != 0) m_NumStrange++;
638  if (charm != 0) m_NumCharmed++;
639 
640  if (bary == 0 && name[name.size() - 1] == '+')
641  name[name.size() - 1] = '-';
642  else if (bary == 0 && name[name.size() - 1] == '-')
643  name[name.size() - 1] = '+';
644  else
645  name = "anti-" + name;
646  m_Particles.push_back(ThermalParticle(static_cast<bool>(stable), name, -pdgid, static_cast<double>(spin), stat, mass, -str, -bary, -chg, abss, width, threshold, -charm, absc));
647  m_Particles[m_Particles.size() - 1].SetAntiParticle(true);
648  m_PDGtoID[-pdgid] = m_Particles.size() - 1;
649  }
650 
651  fin.getline(tmpc, 500);
652  tmp = string(tmpc);
653  }
654  }
655  }
656 
657  void ThermalParticleSystem::LoadTable_NewFormat(std::ifstream & fin, const std::set<std::string>& flags, double mcut)
658  {
659  bool GenerateAntiParticles = (flags.count(ThermalParticleSystem::flag_no_antiparticles) == 0);
660  if (fin.is_open()) {
661  char cc[2000];
662  while (!fin.eof()) {
663  fin.getline(cc, 2000);
664  string tmp = string(cc);
665  vector<string> elems = CuteHRGHelper::split(tmp, '#');
666  if (elems.size() < 1 || elems[0].size() == 0)
667  continue;
668 
669  istringstream iss(elems[0]);
670 
671  int stable, stat, str, bary, chg, charm;
672  long long pdgid;
673  double mass, degeneracy, width, threshold, abss, absc;
674  string name;
675 
676  if (iss >> pdgid
677  >> name
678  >> stable
679  >> mass
680  >> degeneracy
681  >> stat
682  >> bary
683  >> chg
684  >> str
685  >> charm
686  >> abss
687  >> absc
688  >> width
689  >> threshold) {
690 
691  ThermalParticle part_candidate = ThermalParticle((bool)stable, name, pdgid, degeneracy, stat, mass, str, bary, chg, abss, width, threshold, charm, absc);
692 
693  //if (mcut >= 0. && mass > mcut)
694  if (!AcceptParticle(part_candidate, flags, mcut) || m_PDGtoID.count(pdgid) != 0)
695  continue;
696 
697  if (bary != 0) m_NumBaryons++;
698  if (chg != 0) m_NumCharged++;
699  if (str != 0) m_NumStrange++;
700  if (charm != 0) m_NumCharmed++;
701 
702  m_Particles.push_back(part_candidate);
703  m_PDGtoID[pdgid] = m_Particles.size() - 1;
704  m_NumberOfParticles++;
705 
706  if (GenerateAntiParticles && !(bary == 0 && chg == 0 && str == 0 && charm == 0) && (m_PDGtoID.count(-pdgid) == 0)) {
707 
708  if (bary != 0) m_NumBaryons++;
709  if (chg != 0) m_NumCharged++;
710  if (str != 0) m_NumStrange++;
711  if (charm != 0) m_NumCharmed++;
712 
713  if (bary == 0 && name[name.size() - 1] == '+')
714  name[name.size() - 1] = '-';
715  else if (bary == 0 && name[name.size() - 1] == '-')
716  name[name.size() - 1] = '+';
717  else
718  name = "anti-" + name;
719  m_Particles.push_back(ThermalParticle((bool)stable, name, -pdgid, degeneracy, stat, mass, -str, -bary, -chg, abss, width, threshold, -charm, absc));
720  m_Particles[m_Particles.size() - 1].SetAntiParticle(true);
721  m_PDGtoID[pdgid] = m_Particles.size() - 1;
722  }
723  }
724  }
725  }
726  }
727 
728  void ThermalParticleSystem::SetTableFromVector(const std::vector<ThermalParticle>& part_in, bool GenerateAntiParticles)
729  {
730  m_Particles.resize(0);
731 
732  for (size_t i = 0; i < part_in.size(); ++i) {
733  const ThermalParticle &part = part_in[i];
734  if (!GenerateAntiParticles) {
735  m_Particles.push_back(part);
736  }
737  else if (part.PdgId() > 0) {
738  m_Particles.push_back(part);
739 
740  if (!part.IsNeutral()) {
741  m_Particles.push_back(part.GenerateAntiParticle());
742  }
743  }
744  }
745 
746  FinalizeList();
747 
748  if (GenerateAntiParticles) {
749  for (size_t i = 0; i < m_Particles.size(); ++i) {
750  if (m_Particles[i].IsAntiParticle() && PdgToId(-m_Particles[i].PdgId()) != -1) {
751  m_Particles[i].SetDecays(GetDecaysFromAntiParticle(m_Particles[PdgToId(-m_Particles[i].PdgId())].Decays()));
752  }
753  }
754  }
755 
756  FillDecayProperties();
757  FillDecayThresholds();
758  ProcessDecays();
759  }
760 
761  void ThermalParticleSystem::WriteTableToFile(const std::string& OutputFile, bool WriteAntiParticles)
762  {
763  std::ofstream fout(OutputFile.c_str());
764  if (fout.is_open()) {
765  fout << "#"
766  << std::setw(14) << "pdgid"
767  << std::setw(20) << "name"
768  << std::setw(15) << "stable"
769  << std::setw(15) << "mass[GeV]"
770  << std::setw(15) << "degeneracy"
771  << std::setw(15) << "statistics"
772  << std::setw(15) << "B"
773  << std::setw(15) << "Q"
774  << std::setw(15) << "S"
775  << std::setw(15) << "C"
776  << std::setw(15) << "|S|"
777  << std::setw(15) << "|C|"
778  << std::setw(15) << "width[GeV]"
779  << std::setw(15) << "threshold[GeV]"
780  << std::endl;
781 
782  for (size_t i = 0; i < m_Particles.size(); ++i) {
783  const ThermalParticle& part = m_Particles[i];
784  if (part.PdgId() < 0 && !WriteAntiParticles)
785  continue;
786 
787  fout << std::setw(15) << part.PdgId()
788  << std::setw(20) << part.Name()
789  << std::setw(15) << static_cast<int>(part.IsStable())
790  << std::setw(15) << part.Mass()
791  << std::setw(15) << part.Degeneracy()
792  << std::setw(15) << part.Statistics()
793  << std::setw(15) << part.BaryonCharge()
794  << std::setw(15) << part.ElectricCharge()
795  << std::setw(15) << part.Strangeness()
796  << std::setw(15) << part.Charm()
797  << std::setw(15) << part.AbsoluteStrangeness()
798  << std::setw(15) << part.AbsoluteCharm()
799  << std::setw(15) << part.ResonanceWidth()
800  << std::setw(15) << part.DecayThresholdMass()
801  << std::endl;
802  }
803  fout.close();
804  }
805  }
806 
807  void ThermalParticleSystem::LoadDecays(const std::vector<std::string>& DecayFiles, const std::set<std::string>& flags)
808  {
809  for (size_t i = 0; i < m_Particles.size(); ++i)
810  m_Particles[i].ClearDecays();
811 
812  for (size_t i = 0; i < DecayFiles.size(); ++i) {
813  ifstream fin(DecayFiles[i].c_str());
814 
815  if (fin.is_open()) {
816 
817  char tmpc[2000];
818  fin.getline(tmpc, 2000);
819  string tmp = string(tmpc);
820  vector<string> elems = CuteHRGHelper::split(tmp, '#');
821 
822  int flnew = 0;
823  if (tmp.size() == 0 || elems.size() >= 2)
824  flnew = 1;
825  else
826  flnew = 0;
827 
828  fin.clear();
829  fin.seekg(0, ios::beg);
830 
831  if (flnew == 1)
832  ReadDecays_NewFormat(fin);
833  else
834  ReadDecays_OldFormat(fin);
835 
836  fin.close();
837 
838  }
839 
840  }
841 
842  if (flags.count(ThermalParticleSystem::flag_no_antiparticles) == 0) {
843  for (size_t i = 0; i < m_Particles.size(); ++i) {
844  if (m_Particles[i].PdgId() < 0)
845  m_Particles[i].SetDecays(GetDecaysFromAntiParticle(m_Particles[m_PDGtoID[-m_Particles[i].PdgId()]].Decays()));
846  }
847  }
848 
849  for (size_t i = 0; i < m_Particles.size(); ++i)
850  m_Particles[i].SetDecaysOriginal(m_Particles[i].Decays());
851 
852  FillDecayProperties();
853  FillDecayThresholds();
854  ProcessDecays();
855  }
856 
857  void ThermalParticleSystem::LoadDecays(const std::string& DecaysFile, bool GenerateAntiParticles)
858  {
859  std::set<std::string> flags;
860  if (!GenerateAntiParticles)
861  flags.insert(ThermalParticleSystem::flag_no_antiparticles);
862 
863  LoadDecays(vector<string>(1, DecaysFile), flags);
864  }
865 
866  void ThermalParticleSystem::ReadDecays_NewFormat(std::ifstream & fin)
867  {
868  vector< ThermalParticle::ParticleDecaysVector > decays(0);
869  map<long long, int> decaymap;
870  decaymap.clear();
871 
872 
873  if (fin.is_open()) {
874  char cc[2000];
875  int index = 0;
876  while (!fin.eof()) {
877  fin.getline(cc, 2000);
878  string tmp = string(cc);
879  vector<string> elems = CuteHRGHelper::split(tmp, '#');
880  if (elems.size() < 1 || elems[0].size() == 0)
881  continue;
882 
883  int tdecaysnumber = 0;
884  long long tpdgid = 0;
886 
887  istringstream iss(elems[0]);
888  if (!(iss >> tpdgid)) continue;
889 
890  {
891  bool fl = false;
892  while (!fl) {
893  if (fin.eof()) break;
894  fin.getline(cc, 500);
895  tmp = string(cc);
896  elems = CuteHRGHelper::split(tmp, '#');
897  if (elems.size() < 1 || elems[0].size() == 0)
898  continue;
899 
900  istringstream isstnum(elems[0]);
901  if (!(isstnum >> tdecaysnumber)) {
902  tdecaysnumber = 0;
903  continue;
904  }
905  fl = true;
906  }
907  }
908 
909  for (int i = 0; i < tdecaysnumber; ++i) {
910  bool fl = false;
911  while (!fl) {
912  if (fin.eof()) break;
913  fin.getline(cc, 500);
914  tmp = string(cc);
915  elems = CuteHRGHelper::split(tmp, '#');
916  if (elems.size() < 1 || elems[0].size() == 0)
917  continue;
918 
919  ParticleDecayChannel tdecay;
920  istringstream issdec(elems[0]);
921  if (!(issdec >> tdecay.mBratio)) continue;
922  long long tmpid;
923  while (issdec >> tmpid) {
924  tdecay.mDaughters.push_back(tmpid);
925  }
926  tdecays.push_back(tdecay);
927  fl = true;
928  }
929  }
930 
931  if (static_cast<int>(tdecays.size()) == tdecaysnumber && static_cast<int>(tdecays.size()) != 0) {
932  decays.push_back(tdecays);
933  decaymap[tpdgid] = index;
934  index++;
935  }
936  }
937 
938  for (size_t i = 0; i < m_Particles.size(); ++i) {
939  if (decaymap.count(m_Particles[i].PdgId()) != 0)
940  m_Particles[i].SetDecays(decays[decaymap[m_Particles[i].PdgId()]]);
941  }
942  }
943  }
944 
945  void ThermalParticleSystem::Initialize(const std::vector<std::string>& ListFiles, const std::vector<std::string>& DecayFiles, const std::set<std::string>& flags, double mcut)
946  {
947  if (!Disclaimer::DisclaimerPrinted)
948  Disclaimer::DisclaimerPrinted = Disclaimer::PrintDisclaimer();
949 
950  m_NumberOfParticles = 0;
951  m_Particles.resize(0);
952  m_PDGtoID.clear();
953 
954  m_SortMode = ThermalParticleSystem::SortByMass;
955 
956  m_DecayContributionsByFeeddown.resize(Feeddown::NumberOfTypes);
957 
958  SetResonanceWidthShape(ThermalParticle::RelativisticBreitWigner);
959  SetResonanceWidthIntegrationType(ThermalParticle::ZeroWidth);
960  SetCalculationType(IdealGasFunctions::Quadratures);
961 
962  LoadList(ListFiles, DecayFiles, flags, mcut);
963  }
964 
965  void ThermalParticleSystem::Initialize(const std::string& InputFile, const std::string& DecayFile, bool GenAntiP, double mcut)
966  {
967  std::set<std::string> flags;
968  if (!GenAntiP)
969  flags.insert(ThermalParticleSystem::flag_no_antiparticles);
970  Initialize(vector<string>(1, InputFile), vector<string>(1, DecayFile), flags, mcut);
971  }
972 
973  void ThermalParticleSystem::WriteDecaysToFile(const std::string& OutputFile, bool WriteAntiParticles)
974  {
975  std::ofstream fout(OutputFile.c_str());
976  if (fout.is_open()) {
977  fout << "# the list of decays" << std::endl;
978  fout << "# each entry consists of the following:" << std::endl;
979  fout << "# a line with the pdgid of decaying particle" << std::endl;
980  fout << "# a line with the number of decay channels" << std::endl;
981  fout << "# for each channel a line containing whitespace-separated values of the channel branching ratio and pdg ids of the daughter products" << std::endl;
982  fout << "# everything after the # symbol is treated as a comment and ignored" << std::endl;
983  fout << "# decays of antiparticles are not listed but generated from the listed decays of particles" << std::endl;
984  fout << std::endl;
985 
986  for (unsigned int i = 0; i < m_Particles.size(); ++i) {
987  if ((m_Particles[i].PdgId()>0 || WriteAntiParticles) && m_Particles[i].Decays().size()>0) {
988  fout << std::left << std::setw(36) << m_Particles[i].PdgId();
989  fout << " # " << m_Particles[i].Name() << std::endl;
990 
991  fout << std::left << std::setw(36) << m_Particles[i].Decays().size();
992  fout << " # " << m_Particles[i].Decays().size() << " decay channel";
993  if (m_Particles[i].Decays().size() % 10 != 1 || m_Particles[i].Decays().size() % 100 == 11) fout << "s";
994  fout << std::endl;
995 
996  for (unsigned int j = 0; j < m_Particles[i].Decays().size(); ++j) {
997  fout << std::left << std::setw(15) << m_Particles[i].Decays()[j].mBratio << " ";
998  std::ostringstream oss;
999  for (unsigned int k = 0; k < m_Particles[i].Decays()[j].mDaughters.size(); ++k) {
1000  oss << m_Particles[i].Decays()[j].mDaughters[k];
1001  if (k != m_Particles[i].Decays()[j].mDaughters.size() - 1)
1002  oss << " ";
1003  }
1004  fout << std::left << std::setw(20) << oss.str();
1005  fout << " # " << m_Particles[i].Name() << " -> ";
1006  for (unsigned int k = 0; k < m_Particles[i].Decays()[j].mDaughters.size(); ++k) {
1007  if (m_PDGtoID.count(m_Particles[i].Decays()[j].mDaughters[k]) == 0) {
1008  //if (m_Particles[i].Decays()[j].mDaughters[k] == 22) fout << "?gamma?";
1009  long long tpdg = m_Particles[i].Decays()[j].mDaughters[k];
1010  if (ExtraParticles::PdgToId(tpdg) != -1)
1011  fout << ExtraParticles::ParticleByPdg(tpdg).Name();
1012  else fout << "???";
1013  }
1014  else
1015  fout << m_Particles[m_PDGtoID[m_Particles[i].Decays()[j].mDaughters[k]]].Name();
1016  if (k != m_Particles[i].Decays()[j].mDaughters.size() - 1)
1017  fout << " + ";
1018  }
1019  fout << std::endl;
1020  }
1021  fout << std::endl;
1022  }
1023  }
1024 
1025  fout.close();
1026  }
1027  }
1028 
1029  void ThermalParticleSystem::ReadDecays_OldFormat(std::ifstream & fin)
1030  {
1031  vector< ThermalParticle::ParticleDecaysVector > decays(0);
1032  vector<long long> pdgids(0);
1033  map<long long, int> decaymap;
1034  decaymap.clear();
1035 
1036  if (fin.is_open()) {
1037  int decaypartnumber = 0;
1038  fin >> decaypartnumber;
1039  decays.reserve(decaypartnumber);
1040 
1041  for (int i = 0; i < decaypartnumber; ++i) {
1042  int decaysnumber, daughters;
1043  long long pdgid, tmpid;
1044  double bratio;
1045  fin >> pdgid >> decaysnumber;
1046  decaymap[pdgid] = i;
1047  decays.push_back(ThermalParticle::ParticleDecaysVector(0));
1048  pdgids.push_back(pdgid);
1049  for (int j = 0; j < decaysnumber; ++j) {
1050  ParticleDecayChannel decay;
1051  fin >> bratio;
1052  decay.mBratio = bratio / 100.;
1053  fin >> daughters;
1054  decay.mDaughters.reserve(daughters);
1055  for (int k = 0; k < daughters; ++k) {
1056  fin >> tmpid;
1057  decay.mDaughters.push_back(tmpid);
1058  }
1059  decays[i].push_back(decay);
1060  }
1061  }
1062  }
1063 
1064  for (size_t i = 0; i < m_Particles.size(); ++i) {
1065  if (decaymap.count(m_Particles[i].PdgId()) != 0)
1066  m_Particles[i].SetDecays(decays[decaymap[m_Particles[i].PdgId()]]);
1067  }
1068 
1069  }
1070 
1071  std::string ThermalParticleSystem::GetNameFromPDG(long long pdgid) {
1072  if (m_PDGtoID.count(pdgid) != 0)
1073  return m_Particles[m_PDGtoID[pdgid]].Name();
1074  if (pdgid == 1) return string("Npart");
1075  if (pdgid == 310) return string("K0S");
1076  if (pdgid == 130) return string("K0L");
1077  if (pdgid % 10 == 0) {
1078  long long tpdgid = pdgid / 10;
1079  if (PdgToId(tpdgid) != -1 && PdgToId(-tpdgid) != -1)
1080  return m_Particles[PdgToId(tpdgid)].Name() + "+" + m_Particles[PdgToId(-tpdgid)].Name();
1081  }
1082  if (pdgid == 22122112) return string("p+n");
1083 
1084  return ExtraParticles::NameByPdg(pdgid);
1085 
1086  //return string("???");
1087  }
1088 
1089  void ThermalParticleSystem::NormalizeBranchingRatios() {
1090  for (size_t i = 0; i < m_Particles.size(); ++i) m_Particles[i].NormalizeBranchingRatios();
1091  ProcessDecays();
1092  }
1093 
1094 
1095  void ThermalParticleSystem::RestoreBranchingRatios() {
1096  for (size_t i = 0; i < m_Particles.size(); ++i) m_Particles[i].RestoreBranchingRatios();
1097  ProcessDecays();
1098  }
1099 
1100  void ThermalParticleSystem::SetCalculationType(IdealGasFunctions::QStatsCalculationType type)
1101  {
1102  m_QStatsCalculationType = type;
1103  for (size_t i = 0; i < m_Particles.size(); ++i)
1104  m_Particles[i].SetCalculationType(type);
1105  }
1106 
1107  void ThermalParticleSystem::SetClusterExpansionOrder(int order)
1108  {
1109  for (size_t i = 0; i < m_Particles.size(); ++i)
1110  m_Particles[i].SetClusterExpansionOrder(order);
1111  }
1112 
1113  void ThermalParticleSystem::SetResonanceWidthShape(ThermalParticle::ResonanceWidthShape shape)
1114  {
1115  m_ResonanceWidthShape = shape;
1116  for (size_t i = 0; i < m_Particles.size(); ++i)
1117  m_Particles[i].SetResonanceWidthShape(shape);
1118  }
1119 
1120  void ThermalParticleSystem::SetResonanceWidthIntegrationType(ThermalParticle::ResonanceWidthIntegration type)
1121  {
1122  bool dodecays = (type != m_ResonanceWidthIntegrationType);
1123 
1124  m_ResonanceWidthIntegrationType = type;
1125 
1126  for (size_t i = 0; i < m_Particles.size(); ++i) {
1127  if (!m_Particles[i].ZeroWidthEnforced())
1128  m_Particles[i].SetResonanceWidthIntegrationType(type);
1129  }
1130 
1131  if (dodecays)
1132  ProcessDecays();
1133  }
1134 
1136  {
1137  if (id < 0 || id >= static_cast<int>(m_Particles.size())) {
1138  printf("**ERROR** ThermalParticleSystem::Particle(int id): id is out of bounds!");
1139  exit(1);
1140  }
1141  return m_Particles[id];
1142  }
1143 
1145  {
1146  if (id < 0 || id >= static_cast<int>(m_Particles.size())) {
1147  printf("**ERROR** ThermalParticleSystem::Particle(int id): id is out of bounds!\n");
1148  exit(1);
1149  }
1150  return m_Particles[id];
1151  }
1152 
1153  ThermalParticle & ThermalParticleSystem::ParticleByPDG(long long pdgid)
1154  {
1155  if (m_PDGtoID.count(pdgid) == 0) {
1156  printf("**ERROR** ThermalParticleSystem::ParticleByPDG(long long pdgid): pdgid %lld is unknown\n", pdgid);
1157  exit(1);
1158  }
1159  return m_Particles[m_PDGtoID[pdgid]];
1160  }
1161 
1162  void ThermalParticleSystem::FillPdgMap()
1163  {
1164  m_NumBaryons = m_NumCharged = m_NumStrange = m_NumCharmed = 0;
1165  m_NumberOfParticles = 0;
1166  m_PDGtoID.clear();
1167  for (size_t i = 0; i < m_Particles.size(); ++i) {
1168  m_PDGtoID[m_Particles[i].PdgId()] = i;
1169  if (m_Particles[i].BaryonCharge() != 0) m_NumBaryons++;
1170  if (m_Particles[i].ElectricCharge() != 0) m_NumCharged++;
1171  if (m_Particles[i].Strangeness() != 0) m_NumStrange++;
1172  if (m_Particles[i].Charm() != 0) m_NumCharmed++;
1173  if (m_Particles[i].PdgId() > 0) m_NumberOfParticles++;
1174  }
1175 
1176  for (size_t i = 0; i < m_DecayContributionsByFeeddown.size(); ++i)
1177  m_DecayContributionsByFeeddown[i].resize(m_Particles.size());
1178  }
1179 
1180  void ThermalParticleSystem::FinalizeList()
1181  {
1182  if (SortMode() == ThermalParticleSystem::SortByMass)
1183  sort(m_Particles.begin(), m_Particles.end(), cmpParticleMass);
1184  else if (SortMode() == ThermalParticleSystem::SortByMassAndPDG)
1185  sort(m_Particles.begin(), m_Particles.end(), cmpParticleMassAndPdg);
1186  else
1187  sort(m_Particles.begin(), m_Particles.end(), cmpParticlePDG);
1188  FillPdgMap();
1189  for (size_t i = 0; i < m_Particles.size(); ++i) {
1190  if (m_Particles[i].DecayType() == ParticleDecayType::Default)
1191  m_Particles[i].SetDecayType( DecayTypeByParticleType(m_Particles[i]) );
1192  }
1193  }
1194 
1195  void ThermalParticleSystem::AddParticle(const ThermalParticle & part)
1196  {
1197  m_Particles.push_back(part);
1198  FillPdgMap();
1199  }
1200 
1201  void ThermalParticleSystem::RemoveParticleAt(int ind)
1202  {
1203  if (ind >= 0 && ind < static_cast<int>(m_Particles.size())) {
1204  m_Particles.erase(m_Particles.begin() + ind);
1205  FillPdgMap();
1206  }
1207  }
1208 
1209  bool ThermalParticleSystem::CheckDecayChargesConservation(int ind) const
1210  {
1211  std::vector<int> check = CheckDecayChargesConservationVector(ind);
1212  for (int i = 0; i < check.size(); ++i)
1213  if (check[i] != 1)
1214  return false;
1215  return true;
1216  }
1217 
1218  bool ThermalParticleSystem::CheckDecayChannelsAreSpecified() const
1219  {
1220  bool ret = true;
1221  int cnt = 0;
1222  for (int i = 0; i < Particles().size(); ++i) {
1223  const ThermalParticle& part = Particles()[i];
1224  if (!part.IsStable() && part.Decays().size() == 0 && cnt < 10) {
1225  printf("**WARNING** %s (%lld): Particle marked unstable but no decay channels found!\n",
1226  part.Name().c_str(),
1227  part.PdgId());
1228  ret = false;
1229  cnt++;
1230  if (cnt == 10) {
1231  printf("**WARNING** Further warnings are discarded...\n");
1232  }
1233  }
1234  }
1235  return ret;
1236  }
1237 
1238  std::vector<int> ThermalParticleSystem::CheckDecayChargesConservationVector(int ind) const
1239  {
1240  const ThermalParticle& part = Particles()[ind];
1241  int goalB = part.BaryonCharge();
1242  int goalQ = part.ElectricCharge();
1243  int goalS = part.Strangeness();
1244  int goalC = part.Charm();
1245 
1246  std::map<long long, int> tPDGtoID = m_PDGtoID;
1247 
1248  std::vector<int> ret(4, 1);
1249 
1250  for (size_t i = 0; i < part.Decays().size(); ++i) {
1251  int decB = 0, decQ = 0, decS = 0, decC = 0;
1252  for (size_t j = 0; j < part.Decays()[i].mDaughters.size(); ++j) {
1253  long long tpdg = part.Decays()[i].mDaughters[j];
1254  if (tPDGtoID.count(tpdg) != 0) {
1255  int tid = tPDGtoID[tpdg];
1256  decB += Particles()[tid].BaryonCharge();
1257  decQ += Particles()[tid].ElectricCharge();
1258  decS += Particles()[tid].Strangeness();
1259  decC += Particles()[tid].Charm();
1260  }
1261  else if (ExtraParticles::PdgToId(tpdg) != -1) {
1262  int tid = ExtraParticles::PdgToId(tpdg);
1263  decB += ExtraParticles::Particle(tid).BaryonCharge();
1265  decS += ExtraParticles::Particle(tid).Strangeness();
1266  decC += ExtraParticles::Particle(tid).Charm();
1267  }
1268  }
1269 
1270  if (goalB != decB)
1271  ret[0] = 0;
1272  if (goalQ != decQ)
1273  ret[1] = 0;
1274  if (goalS != decS)
1275  ret[2] = 0;
1276  if (goalC != decC)
1277  ret[3] = 0;
1278  }
1279 
1280  return ret;
1281  }
1282 
1283  bool ThermalParticleSystem::operator==(const ThermalParticleSystem & rhs) const
1284  {
1285  bool ret = true;
1286  ret &= m_PDGtoID == rhs.m_PDGtoID;
1287  ret &= m_NumBaryons == rhs.m_NumBaryons;
1288  ret &= m_NumCharged == rhs.m_NumCharged;
1289  ret &= m_NumStrange == rhs.m_NumStrange;
1290  ret &= m_NumCharmed == rhs.m_NumCharmed;
1291  ret &= m_NumberOfParticles == rhs.m_NumberOfParticles;
1292  ret &= m_ResonanceWidthIntegrationType == rhs.m_ResonanceWidthIntegrationType;
1293  ret &= m_DecayDistributionsMap == rhs.m_DecayDistributionsMap;
1294 
1295  ret &= m_Particles == rhs.m_Particles;
1296 
1297  return ret;
1298  }
1299 
1300  ParticleDecayType::DecayType ThermalParticleSystem::DecayTypeByParticleType(const ThermalParticle &part)
1301  {
1302  // Check if it's a known stable (wrt to any time scale of relevance) particle
1303  set<long long> stablePDG;
1304  stablePDG.insert(2212); stablePDG.insert(-2212); // proton
1305  stablePDG.insert(2112); stablePDG.insert(-2112); // neutron
1306  stablePDG.insert(1000010020); stablePDG.insert(-1000010020); // deuteron
1307  stablePDG.insert(1000020030); stablePDG.insert(-1000020030); // He3
1308  stablePDG.insert(1000010030); stablePDG.insert(-1000010030); // triton
1309  stablePDG.insert(1000020040); stablePDG.insert(-1000020040); // He4
1310 
1311  if (stablePDG.count(part.PdgId()) > 0) {
1312  return ParticleDecayType::Stable;
1313  }
1314 
1315  // Check if it's a known weakly decaying particle
1316  set<long long> weakPDG;
1317  weakPDG.insert(310); // K0S
1318  weakPDG.insert(130); // K0L
1319  weakPDG.insert(211); weakPDG.insert(-211); // pi+-
1320  weakPDG.insert(321); weakPDG.insert(-321); // K+-
1321  weakPDG.insert(3122); weakPDG.insert(-3122); // Lambda
1322  weakPDG.insert(3222); weakPDG.insert(-3222); // Sigma+
1323  weakPDG.insert(3112); weakPDG.insert(-3112); // Sigma-
1324  weakPDG.insert(3322); weakPDG.insert(-3322); // Ksi0
1325  weakPDG.insert(3312); weakPDG.insert(-3312); // Ksi-
1326  weakPDG.insert(3334); weakPDG.insert(-3334); // Omega
1327  weakPDG.insert(411); weakPDG.insert(-411); // D+-
1328  weakPDG.insert(421); weakPDG.insert(-421); // D0
1329  weakPDG.insert(431); weakPDG.insert(-431); // Ds
1330  weakPDG.insert(4232); weakPDG.insert(-4232); // Ksic+
1331  weakPDG.insert(4132); weakPDG.insert(-4132); // Ksic0
1332  weakPDG.insert(4422); weakPDG.insert(-4422); // Ksicc++
1333  weakPDG.insert(4412); weakPDG.insert(-4412); // Ksicc+
1334  weakPDG.insert(4332); weakPDG.insert(-4332); // Omegac
1335 
1336  if (weakPDG.count(part.PdgId()) > 0) {
1337  return ParticleDecayType::Weak;
1338  }
1339 
1340  // Check if it's a known electromagnetically decaying particle
1341  // Note: we treat eta decay as "electromagnetic" although some of them are in fact isospin-invariance breaking strong decays
1342  set<long long> emPDG;
1343  emPDG.insert(111); // pi0
1344  emPDG.insert(221); // eta
1345  emPDG.insert(331); // eta'
1346  emPDG.insert(3212); emPDG.insert(-3212); // Sigma0
1347 
1348  if (emPDG.count(part.PdgId()) > 0) {
1349  return ParticleDecayType::Electromagnetic;
1350  }
1351 
1352  if (!part.IsStable()) // if particle not marked as stable assume it at least decays strongly
1353  {
1354  return ParticleDecayType::Strong;
1355  }
1356  else {
1357  // if contains strangeness (or charm), it is not stable under weak decays
1358  if (part.AbsoluteStrangeness() != 0 || part.AbsoluteCharm() != 0)
1359  return ParticleDecayType::Weak;
1360 
1361  return ParticleDecayType::Stable;
1362  }
1363 
1364 
1365  return ParticleDecayType::Default;
1366  }
1367 
1368  void ThermalParticleSystem::FillResonanceDecaysByFeeddown() {
1369  m_DecayContributionsByFeeddown[Feeddown::Weak].resize(m_Particles.size());
1370  m_DecayContributionsByFeeddown[Feeddown::Electromagnetic].resize(m_Particles.size());
1371  m_DecayContributionsByFeeddown[Feeddown::Strong].resize(m_Particles.size());
1372  for (size_t i = 0; i < m_Particles.size(); ++i) {
1373  m_DecayContributionsByFeeddown[Feeddown::Weak][i].resize(0);
1374  m_DecayContributionsByFeeddown[Feeddown::Electromagnetic][i].resize(0);
1375  m_DecayContributionsByFeeddown[Feeddown::Strong][i].resize(0);
1376  }
1377  for (int i = static_cast<int>(m_Particles.size()) - 1; i >= 0; i--)
1378  if (m_Particles[i].DecayType() != ParticleDecayType::Stable && m_Particles[i].DecayType() != ParticleDecayType::Default) {
1379  GoResonanceByFeeddown(i, i, 1., Feeddown::Type(static_cast<int>(m_Particles[i].DecayType())));
1380  }
1381  }
1382 
1383  void ThermalParticleSystem::GoResonanceByFeeddown(int ind, int startind, double BR, Feeddown::Type feeddown) {
1384  for (int feed_index = static_cast<int>(Feeddown::Weak); feed_index <= static_cast<int>(Feeddown::Strong); ++feed_index) {
1385  if (static_cast<int>(feeddown) < feed_index) continue;
1386  //std::vector< std::pair<double, int> >& decayContributions = m_Particles[ind].DecayContributionsByFeeddown()[feed_index];
1387  DecayContributionsToParticle& decayContributions = m_DecayContributionsByFeeddown[feed_index][ind];
1388  if (ind != startind && decayContributions.size() > 0 && decayContributions[decayContributions.size() - 1].second == startind)
1389  {
1390  decayContributions[decayContributions.size() - 1].first += BR;
1391  }
1392  else if (ind != startind) {
1393  decayContributions.push_back(make_pair(BR, startind));
1394  }
1395  }
1396 
1397 
1398  if (m_Particles[ind].DecayType() != ParticleDecayType::Stable && m_Particles[ind].DecayType() != ParticleDecayType::Default) {
1399  for (size_t i = 0; i < m_Particles[ind].Decays().size(); ++i) {
1400  const ParticleDecayChannel& decaychannel = m_Particles[ind].Decays()[i];
1401  double tbr = decaychannel.mBratio;
1402 
1403  if (m_ResonanceWidthIntegrationType == ThermalParticle::eBW && ind == startind)
1404  tbr = decaychannel.mBratioAverage;
1405 
1406  for (size_t j = 0; j < decaychannel.mDaughters.size(); ++j) {
1407  if (m_PDGtoID.count(decaychannel.mDaughters[j]) != 0)
1408  GoResonanceByFeeddown(m_PDGtoID[decaychannel.mDaughters[j]], startind, BR*tbr, Feeddown::Type(static_cast<int>(m_Particles[ind].DecayType())));
1409  }
1410  }
1411  }
1412  }
1413 
1414 
1415  namespace CuteHRGHelper {
1416  std::vector<std::string>& split(const std::string& s, char delim, std::vector<std::string>& elems) {
1417  std::stringstream ss(s);
1418  std::string item;
1419  while (std::getline(ss, item, delim)) {
1420  elems.push_back(item);
1421  }
1422  return elems;
1423  }
1424 
1425  std::vector<std::string> split(const std::string& s, char delim) {
1426  std::vector<std::string> elems;
1427  split(s, delim, elems);
1428  return elems;
1429  }
1430 
1431  void cutDecayDistributionsVector(std::vector< std::pair<double, std::vector<int> > >& vect, int maxsize)
1432  {
1433  if (static_cast<int>(vect.size()) > maxsize) {
1434  std::sort(vect.begin(), vect.end());
1435  std::reverse(vect.begin(), vect.end());
1436  vect.resize(1500);
1437  }
1438  }
1439  }
1440 
1441  namespace ExtraParticles {
1442  static std::vector<ThermalParticle> Particles;
1443  static std::map<long long, int> PdgIdMap;
1444  static bool isInitialized = Init();
1445  const ThermalParticle& Particle(int id)
1446  {
1447  if (id < 0 || id >= Particles.size()) {
1448  printf("**ERROR** ExtraParticles::Particle(int id): id is out of bounds!");
1449  exit(1);
1450  }
1451  return Particles[id];
1452  }
1453  const ThermalParticle& ParticleByPdg(long long pdgid)
1454  {
1455  int tid = PdgToId(pdgid);
1456  if (tid == -1) {
1457  printf("**ERROR** ExtraParticles::ParticleByPdg(long long pdgid): pdgid %lld is unknown\n", pdgid);
1458  exit(1);
1459  }
1460  return Particle(tid);
1461  }
1462  int PdgToId(long long pdgid)
1463  {
1464  return (PdgIdMap.count(pdgid) > 0) ? PdgIdMap[pdgid] : -1;
1465  }
1466  bool Init()
1467  {
1468  Particles.clear();
1469  PdgIdMap.clear();
1470 
1471  int tsz = 0;
1472  // photons
1473  Particles.push_back(ThermalParticle(true, "gamma", 22, 2., 1, 0.));
1474  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1475  tsz++;
1476 
1477  // electrons
1478  Particles.push_back(ThermalParticle(true, "e-", 11, 2., 1, 5.109989461E-04, 0, 0, -1));
1479  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1480  tsz++;
1481  Particles.push_back(ThermalParticle(true, "e+", -11, 2., 1, 5.109989461E-04, 0, 0, 1));
1482  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1483  tsz++;
1484 
1485  // muons
1486  Particles.push_back(ThermalParticle(true, "mu-", 13, 2., 1, 1.056583745E-01, 0, 0, -1));
1487  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1488  tsz++;
1489  Particles.push_back(ThermalParticle(true, "mu+", -13, 2., 1, 1.056583745E-01, 0, 0, 1));
1490  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1491  tsz++;
1492 
1493  // tauons
1494  Particles.push_back(ThermalParticle(true, "tau-", 15, 2., 1, 1.77686E+00, 0, 0, -1));
1495  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1496  tsz++;
1497  Particles.push_back(ThermalParticle(true, "tau+", -15, 2., 1, 1.77686E+00, 0, 0, 1));
1498  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1499  tsz++;
1500 
1501  // nu(e)
1502  Particles.push_back(ThermalParticle(true, "nu(e)", 12, 1., 1, 0.));
1503  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1504  tsz++;
1505  Particles.push_back(ThermalParticle(true, "anti-nu(e)", -12, 1., 1, 0.));
1506  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1507  tsz++;
1508 
1509  // nu(mu)
1510  Particles.push_back(ThermalParticle(true, "nu(mu)", 14, 1., 1, 0.));
1511  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1512  tsz++;
1513  Particles.push_back(ThermalParticle(true, "anti-nu(mu)", -14, 1., 1, 0.));
1514  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1515  tsz++;
1516 
1517  // nu(tau)
1518  Particles.push_back(ThermalParticle(true, "nu(tau)", 16, 1., 1, 0.));
1519  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1520  tsz++;
1521  Particles.push_back(ThermalParticle(true, "anti-nu(tau)", -16, 1., 1, 0.));
1522  PdgIdMap[Particles[tsz].PdgId()] = tsz;
1523  tsz++;
1524 
1525  return true;
1526  }
1527  std::string NameByPdg(long long pdg)
1528  {
1529  int tid = PdgToId(pdg);
1530  if (tid != -1)
1531  return Particle(tid).Name();
1532  return string("???");
1533  }
1534  } // namespace ExtraParticles
1535 
1536 } // namespace thermalfist
long long stringToLongLong(const std::string &str)
Structure containing information about a single decay channel of a particle.
Definition: ParticleDecay.h:73
std::string NameByPdg(long long pdg)
double AbsoluteStrangeness() const
Absolute strange quark content |s|.
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
DecayType
Type of particle&#39;s decay.
Definition: ParticleDecay.h:60
int Charm() const
Particle&#39;s charm.
std::vector< ParticleDecayChannel > ParticleDecaysVector
Vector of all decay channels of a particle.
Contains some helper functions.
long long PdgId() const
Particle&#39;s Particle Data Group (PDG) ID number.
Class containing the particle list.
double ResonanceWidth() const
Particle&#39;s width at the pole mass (GeV)
void cutDecayDistributionsVector(std::vector< std::pair< double, std::vector< int > > > &vect, int maxsize=1000)
std::vector< std::pair< double, std::vector< int > > > ResonanceFinalStatesDistribution
const ThermalParticle & ParticleByPdg(long long pdg)
int BaryonCharge() const
Particle&#39;s baryon number.
ResonanceWidthIntegration
Treatment of finite resonance widths.
Class containing all information about a particle specie.
ResonanceWidthShape
Relativistic vs non-relativistic Breit-Wigner shape.
std::vector< SingleDecayContribution > DecayContributionsToParticle
A vector of SingleDecayContribution where each element corresponds to a certain resonance species...
const std::string & Name() const
Particle&#39;s name.
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].
ThermalParticle GenerateAntiParticle() const
Generates the anti-particle to the current particle specie.
bool IsStable() const
Return particle stability flag.
double DecayThresholdMass() const
The decays threshold mass.
int ElectricCharge() const
Particle&#39;s electric charge.
int Strangeness() const
Particle&#39;s strangeness.
const ThermalParticle & Particle(int id)
double Degeneracy() const
Particle&#39;s internal degeneracy factor.
QStatsCalculationType
Identifies whether quantum statistics are to be computed using the cluster expansion or numerical int...
const ParticleDecaysVector & Decays() const
A vector of particle&#39;s decays.
double AbsoluteCharm() const
Absolute charm quark content |s|.
The main namespace where all classes and functions of the Thermal-FIST library reside.
std::pair< double, int > SingleDecayContribution
int Statistics() const
Particle&#39;s statistics.