Thermal-FIST  1.3
Package for hadron resonance gas model applications
EventGeneratorBase.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 <functional>
11 #include <algorithm>
12 
13 
14 #include "HRGBase/xMath.h"
21 #include "HRGVDW/ThermalModelVDW.h"
23 
24 namespace thermalfist {
25 
27  double EventGeneratorBase::m_LastWeight = 1., EventGeneratorBase::m_LastLogWeight = 0., EventGeneratorBase::m_LastNormWeight = 1.;
28 
29 
31  {
33  }
34 
36  {
37  for (size_t i = 0; i < m_MomentumGens.size(); ++i) {
38  if (m_MomentumGens[i] != NULL)
39  delete m_MomentumGens[i];
40  }
41  m_MomentumGens.resize(0);
42 
43  for (size_t i = 0; i < m_BWGens.size(); ++i) {
44  if (m_BWGens[i] != NULL)
45  delete m_BWGens[i];
46  }
47  m_BWGens.resize(0);
48  }
49 
50  //void EventGeneratorBase::SetConfiguration(const ThermalModelParameters& params, EventGeneratorConfiguration::Ensemble ensemble, EventGeneratorConfiguration::ModelType modeltype, ThermalParticleSystem *TPS, ThermalModelBase *THMEVVDW)
52  const EventGeneratorConfiguration& config)
53  {
54  m_Config = config;
55 
56  if (TPS == NULL)
57  return;
58 
59 
62  }
66  }
68  if (m_Config.CanonicalB)
70  if (m_Config.CanonicalS)
72  if (m_Config.CanonicalQ)
74  if (m_Config.CanonicalC)
76  }
77 
80  }
83  }
86  }
89  }
90 
92  //m_THM->SetStatistics(false);
93 
94  m_THM->ConstrainMuB(false);
95  m_THM->ConstrainMuQ(false);
96  m_THM->ConstrainMuS(false);
97  m_THM->ConstrainMuC(false);
98 
99  if (!m_Config.fUsePCE)
101  else
103 
105  for (size_t i = 0; i < m_THM->Densities().size(); ++i) {
106  for (size_t j = 0; j < m_THM->Densities().size(); ++j) {
107  if (m_Config.bij.size() == m_THM->Densities().size()
108  && m_Config.bij[i].size() == m_THM->Densities().size())
109  m_THM->SetVirial(i, j, m_Config.bij[i][j]);
110 
111  if (m_Config.aij.size() == m_THM->Densities().size()
112  && m_Config.aij[i].size() == m_THM->Densities().size())
113  m_THM->SetAttraction(i, j, m_Config.aij[i][j]);
114  }
115  }
116  }
117 
119  // The following procedure currently not used,
120  // but can be considered if SolveChemicalPotentials routine fails
121  // Note to take into account PCE possiblity if this option is considered
122  // TODO: Properly for mixed-canonical ensembles and charm
123  if (0 && !(m_Config.B == 0 && m_Config.Q == 0 && m_Config.S == 0) && !m_Config.fUsePCE) {
124  if (m_Config.S == 0 && !(m_Config.Q == 0 || m_Config.B == 0)) {
125  double QBrat = (double)(m_Config.Q) / m_Config.B;
126 
127  double left = 0.000, right = 0.900, center;
128 
130  m_THM->SetQoverB(QBrat);
131  m_THM->FixParameters();
133  double valleft = m_THM->CalculateBaryonDensity() * m_THM->Volume() - m_Config.B;
134 
136  m_THM->SetQoverB(QBrat);
137  m_THM->FixParameters();
139  double valright = m_THM->CalculateBaryonDensity() * m_THM->Volume() - m_Config.B;
140 
141  double valcenter;
142 
143  while ((right - left) > 0.00001) {
144  center = (left + right) / 2.;
146  m_THM->SetQoverB(QBrat);
147  m_THM->FixParameters();
149  valcenter = m_THM->CalculateBaryonDensity() * m_THM->Volume() - m_Config.B;
150 
151  if (valleft*valcenter > 0.) {
152  left = center;
153  valleft = valcenter;
154  }
155  else {
156  right = center;
157  valright = valcenter;
158  }
159  }
160 
162  m_THM->SetQoverB(QBrat);
163  m_THM->FixParameters();
164 
168 
170  }
171  }
172 
173  if (!m_Config.fUsePCE)
174  {
178  if (m_THM->Parameters().muB != m_THM->Parameters().muB ||
179  m_THM->Parameters().muQ != m_THM->Parameters().muQ ||
180  m_THM->Parameters().muS != m_THM->Parameters().muS ||
181  m_THM->Parameters().muC != m_THM->Parameters().muC ||
182  !solve_chems)
183  {
184  printf("**WARNING** Could not constrain chemical potentials. Setting all for exactly conserved charges to zero...\n");
185  if (m_Config.CanonicalB)
187  else
189 
190  if (m_Config.CanonicalQ)
192  else
194 
195  if (m_Config.CanonicalS)
197  else
199 
200  if (m_Config.CanonicalC)
202  else
204 
206  }
211 
212  std::cout << "Chemical potentials constrained!\n"
213  << "muB = " << m_Config.CFOParameters.muB
214  << " muQ = " << m_Config.CFOParameters.muQ
215  << " muS = " << m_Config.CFOParameters.muS
216  << " muC = " << m_Config.CFOParameters.muC << "\n";
217 
218  std::cout << "B = " << m_THM->CalculateBaryonDensity() * m_THM->Parameters().V
219  << " Q = " << m_THM->CalculateChargeDensity() * m_THM->Parameters().V
220  << " S = " << m_THM->CalculateStrangenessDensity() * m_THM->Parameters().V
221  << " C = " << m_THM->CalculateCharmDensity() * m_THM->Parameters().V
222  << "\n";
223  }
224  }
225 
227  m_THM->ConstrainMuS(true);
228  m_THM->ConstrainMuC(true);
233  }
234 
236  m_THM->ConstrainMuC(true);
240  }
241 
244 
247 
248  //m_acc.resize(m_THM->ComponentsNumber());
249  }
250 
251  //void EventGeneratorBase::ReadAcceptance(std::string accfolder)
252  //{
253  // //m_acc.resize(m_THM->TPS()->Particles().size());
254  // for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
255  // std::string filename = accfolder + "pty_acc_" + to_string_fix(m_THM->TPS()->Particles()[i].PdgId()) + ".txt";
256  // Acceptance::ReadAcceptanceFunction(m_acc[i], filename);
257  // }
258  //}
259 
261  if (!m_THM->IsGCECalculated())
263 
264  m_Baryons.resize(0);
265  m_AntiBaryons.resize(0);
266  m_StrangeMesons.resize(0);
267  m_AntiStrangeMesons.resize(0);
268  m_ChargeMesons.resize(0);
269  m_AntiChargeMesons.resize(0);
270  m_CharmMesons.resize(0);
271  m_AntiCharmMesons.resize(0);
272  m_CharmAll.resize(0);
273  m_AntiCharmAll.resize(0);
274  m_MeanB = 0.;
275  m_MeanAB = 0.;
276  m_MeanSM = 0.;
277  m_MeanASM = 0.;
278  m_MeanCM = 0.;
279  m_MeanACM = 0.;
280  m_MeanCHRMM = 0.;
281  m_MeanACHRMM = 0.;
282  m_MeanCHRM = 0.;
283  m_MeanACHRM = 0.;
284 
285  std::vector<double> yields = m_THM->Densities();
286  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i)
287  yields[i] *= m_THM->Volume();
288 
289  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
290  if (m_THM->TPS()->Particles()[i].BaryonCharge() == 1) {
291  m_Baryons.push_back(std::make_pair(yields[i], i));
292  m_MeanB += yields[i];
293  }
294  else if (m_THM->TPS()->Particles()[i].BaryonCharge() == -1) {
295  m_AntiBaryons.push_back(std::make_pair(yields[i], i));
296  m_MeanAB += yields[i];
297  }
298  else if (m_THM->TPS()->Particles()[i].BaryonCharge() == 0 && m_THM->TPS()->Particles()[i].Strangeness() == 1) {
299  m_StrangeMesons.push_back(std::make_pair(yields[i], i));
300  m_MeanSM += yields[i];
301  }
302  else if (m_THM->TPS()->Particles()[i].BaryonCharge() == 0 && m_THM->TPS()->Particles()[i].Strangeness() == -1) {
303  m_AntiStrangeMesons.push_back(std::make_pair(yields[i], i));
304  m_MeanASM += yields[i];
305  }
306  else if (m_THM->TPS()->Particles()[i].BaryonCharge() == 0 && m_THM->TPS()->Particles()[i].Strangeness() == 0 && m_THM->TPS()->Particles()[i].ElectricCharge() == 1) {
307  m_ChargeMesons.push_back(std::make_pair(yields[i], i));
308  m_MeanCM += yields[i];
309  }
310  else if (m_THM->TPS()->Particles()[i].BaryonCharge() == 0 && m_THM->TPS()->Particles()[i].Strangeness() == 0 && m_THM->TPS()->Particles()[i].ElectricCharge() == -1) {
311  m_AntiChargeMesons.push_back(std::make_pair(yields[i], i));
312  m_MeanACM += yields[i];
313  }
314  else if (m_THM->TPS()->Particles()[i].BaryonCharge() == 0 && m_THM->TPS()->Particles()[i].Strangeness() == 0 && m_THM->TPS()->Particles()[i].ElectricCharge() == 0 && m_THM->TPS()->Particles()[i].Charm() == 1) {
315  m_CharmMesons.push_back(std::make_pair(yields[i], i));
316  m_MeanCHRMM += yields[i];
317  }
318  else if (m_THM->TPS()->Particles()[i].BaryonCharge() == 0 && m_THM->TPS()->Particles()[i].Strangeness() == 0 && m_THM->TPS()->Particles()[i].ElectricCharge() == 0 && m_THM->TPS()->Particles()[i].Charm() == -1) {
319  m_AntiCharmMesons.push_back(std::make_pair(yields[i], i));
320  m_MeanACHRMM += yields[i];
321  }
322 
323  if (m_THM->TPS()->Particles()[i].Charm() == 1) {
324  m_CharmAll.push_back(std::make_pair(yields[i], i));
325  m_MeanCHRM += yields[i];
326  }
327  else if (m_THM->TPS()->Particles()[i].Charm() == -1) {
328  m_AntiCharmAll.push_back(std::make_pair(yields[i], i));
329  m_MeanACHRM += yields[i];
330  }
331  }
332 
333  // sort in descending order and convert to prefix sums
334  std::sort(m_Baryons.begin(), m_Baryons.end(), std::greater< std::pair<double, int> >());
335  std::sort(m_AntiBaryons.begin(), m_AntiBaryons.end(), std::greater< std::pair<double, int> >());
336  std::sort(m_StrangeMesons.begin(), m_StrangeMesons.end(), std::greater< std::pair<double, int> >());
337  std::sort(m_AntiStrangeMesons.begin(), m_AntiStrangeMesons.end(), std::greater< std::pair<double, int> >());
338  std::sort(m_ChargeMesons.begin(), m_ChargeMesons.end(), std::greater< std::pair<double, int> >());
339  std::sort(m_AntiChargeMesons.begin(), m_AntiChargeMesons.end(), std::greater< std::pair<double, int> >());
340  std::sort(m_CharmMesons.begin(), m_CharmMesons.end(), std::greater< std::pair<double, int> >());
341  std::sort(m_AntiCharmMesons.begin(), m_AntiCharmMesons.end(), std::greater< std::pair<double, int> >());
342  std::sort(m_CharmAll.begin(), m_CharmAll.end(), std::greater< std::pair<double, int> >());
343  std::sort(m_AntiCharmAll.begin(), m_AntiCharmAll.end(), std::greater< std::pair<double, int> >());
344 
345  for (int i = 1; i < static_cast<int>(m_Baryons.size()); ++i) m_Baryons[i].first += m_Baryons[i - 1].first;
346  for (int i = 1; i < static_cast<int>(m_AntiBaryons.size()); ++i) m_AntiBaryons[i].first += m_AntiBaryons[i - 1].first;
347  for (int i = 1; i < static_cast<int>(m_StrangeMesons.size()); ++i) m_StrangeMesons[i].first += m_StrangeMesons[i - 1].first;
348  for (int i = 1; i < static_cast<int>(m_AntiStrangeMesons.size()); ++i) m_AntiStrangeMesons[i].first += m_AntiStrangeMesons[i - 1].first;
349  for (int i = 1; i < static_cast<int>(m_ChargeMesons.size()); ++i) m_ChargeMesons[i].first += m_ChargeMesons[i - 1].first;
350  for (int i = 1; i < static_cast<int>(m_AntiChargeMesons.size()); ++i) m_AntiChargeMesons[i].first += m_AntiChargeMesons[i - 1].first;
351  for (int i = 1; i < static_cast<int>(m_CharmMesons.size()); ++i) m_CharmMesons[i].first += m_CharmMesons[i - 1].first;
352  for (int i = 1; i < static_cast<int>(m_AntiCharmMesons.size()); ++i) m_AntiCharmMesons[i].first += m_AntiCharmMesons[i - 1].first;
353  for (int i = 1; i < static_cast<int>(m_CharmAll.size()); ++i) m_CharmAll[i].first += m_CharmAll[i - 1].first;
354  for (int i = 1; i < static_cast<int>(m_AntiCharmAll.size()); ++i) m_AntiCharmAll[i].first += m_AntiCharmAll[i - 1].first;
355  }
356 
357  std::vector<int> EventGeneratorBase::GenerateTotals() const {
358  if (!m_THM->IsGCECalculated())
360  std::vector<int> totals(m_THM->TPS()->Particles().size());
361 
362  m_LastWeight = 1.;
363  m_LastNormWeight = 1.;
364 
365  while (true) {
366  // First generate a configuration which satisfies conservation laws
368  totals = GenerateTotalsCCE();
370  totals = GenerateTotalsSCE();
372  totals = GenerateTotalsCE();
373  else
374  totals = GenerateTotalsGCE();
375 
376  // Then take into account EV/vdW interactions using importance sampling
377  std::vector<double> *densitiesid = NULL;
378  std::vector<double> tmpdens;
379  const std::vector<double>& densities = m_THM->Densities();
381  tmpdens = m_DensitiesIdeal;
382  densitiesid = &tmpdens;
383  }
384 
386  ThermalModelEVDiagonal *model = static_cast<ThermalModelEVDiagonal*>(m_THM);
387  double V = m_THM->Volume();
388  double VVN = m_THM->Volume();
389 
390  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i)
391  VVN -= model->ExcludedVolume(i) * totals[i];
392 
393  if (VVN < 0.) continue;
394  double weight = 1.;
395  double logweight = 0.;
396 
397  double normweight = 1.;
398  double weightev = 1.;
399  double VVNev = m_THM->Volume();
400  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i)
401  VVNev -= model->ExcludedVolume(i) * densities[i] * m_THM->Volume();
402 
403  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
404  weight *= pow(VVN / m_THM->Volume() * densitiesid->operator[](i) / densities[i], totals[i]);
405  if (densitiesid->operator[](i) > 0. && densities[i] > 0.)
406  logweight += totals[i] * log(VVN / m_THM->Volume() * densitiesid->operator[](i) / densities[i]);
407 
408  weightev *= pow(VVNev / V * densitiesid->operator[](i) / densities[i], densities[i] * V);
409 
410  if (densitiesid->operator[](i) > 0. && densities[i] > 0.)
411  //normweight *= pow(VVN / V, totals[i]) / pow(VVNev / V, densities[i] * V) * pow(densitiesid->operator[](i) / densities[i], totals[i] - (densities[i] * V));
412  normweight *= pow(VVN / VVNev, totals[i]) * pow(VVNev / V, totals[i] - densities[i] * V) * pow(densitiesid->operator[](i) / densities[i], totals[i] - (densities[i] * V));
413  }
414 
415  m_LastWeight = weight;
416  m_LastLogWeight = logweight;
417  m_LastNormWeight = normweight;
418 
419  //std::cout << "Norm weight = " << normweight << " " << weight / weightev << " " << std::scientific << normweight - 1. << std::fixed << "\n";
420  }
421 
422 
425  double V = m_THM->Volume();
426 
427  double weight = 1.;
428  double logweight = 0.;
429  double normweight = 1.;
430  double weightev = 1.;
431  bool fl = 1;
432  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
433  double VVN = m_THM->Volume();
434 
435  for (size_t j = 0; j < m_THM->TPS()->Particles().size(); ++j)
436  VVN -= model->VirialCoefficient(j, i) * totals[j];
437 
438  if (VVN < 0.) { fl = false; break; }
439 
440  double VVNev = m_THM->Volume();
441  for (size_t j = 0; j < m_THM->TPS()->Particles().size(); ++j)
442  VVNev -= model->VirialCoefficient(j, i) * densities[j] * V;
443 
444  weight *= pow(VVN / m_THM->Volume() * densitiesid->operator[](i) / densities[i], totals[i]);
445  if (densitiesid->operator[](i) > 0. && densities[i] > 0.)
446  logweight += totals[i] * log(VVN / m_THM->Volume() * densitiesid->operator[](i) / densities[i]);
447 
448  weightev *= pow(VVNev / m_THM->Volume() * densitiesid->operator[](i) / densities[i], densities[i] * V);
449  if (densitiesid->operator[](i) > 0. && densities[i] > 0.)
450  normweight *= pow(VVN / VVNev, totals[i]) * pow(VVNev / V, totals[i] - densities[i] * V) * pow(densitiesid->operator[](i) / densities[i], totals[i] - (densities[i] * V));
451  }
452  if (!fl) continue;
453  m_LastWeight = weight;
454  m_LastLogWeight = logweight;
455  m_LastNormWeight = normweight;
456 
457  //std::cout << "Norm weight = " << normweight << " " << weight / weightev << " " << std::scientific << normweight - 1. << std::fixed << "\n";
458  }
459 
461  ThermalModelVDW *model = static_cast<ThermalModelVDW*>(m_THM);
462  double V = m_THM->Volume();
463 
464  double weight = 1.;
465  double logweight = 0.;
466  double normweight = 1.;
467  double weightvdw = 1.;
468  bool fl = 1;
469  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
470  double VVN = m_THM->Volume();
471 
472  for (size_t j = 0; j < m_THM->TPS()->Particles().size(); ++j)
473  VVN -= model->VirialCoefficient(j, i) * totals[j];
474 
475  if (VVN < 0.) { fl = false; break; }
476 
477  double VVNev = m_THM->Volume();
478  for (size_t j = 0; j < m_THM->TPS()->Particles().size(); ++j)
479  VVNev -= model->VirialCoefficient(j, i) * densities[j] * V;
480 
481  weight *= pow(VVN / m_THM->Volume() * densitiesid->operator[](i) / densities[i], totals[i]);
482  if (densitiesid->operator[](i) > 0. && densities[i] > 0.)
483  logweight += totals[i] * log(VVN / m_THM->Volume() * densitiesid->operator[](i) / densities[i]);
484 
485  for (size_t j = 0; j < m_THM->TPS()->Particles().size(); ++j) {
486  double aij = model->AttractionCoefficient(i, j);
487  weight *= exp(aij * totals[j] / m_THM->Parameters().T / m_THM->Volume() * totals[i]);
488  logweight += totals[i] * aij * totals[j] / m_THM->Parameters().T / m_THM->Volume();
489  }
490 
491  weightvdw *= pow(VVNev / m_THM->Volume() * densitiesid->operator[](i) / densities[i], densities[i] * V);
492  if (densitiesid->operator[](i) > 0. && densities[i] > 0.)
493  normweight *= pow(VVN / VVNev, totals[i]) * pow(VVNev / V, totals[i] - densities[i] * V) * pow(densitiesid->operator[](i) / densities[i], totals[i] - (densities[i] * V));
494 
495  for (size_t j = 0; j < m_THM->TPS()->Particles().size(); ++j) {
496  double aij = model->AttractionCoefficient(i, j);
497  weightvdw *= exp(aij * densities[j] / m_THM->Parameters().T * densities[i] * V);
498  normweight *= exp(aij * totals[j] / m_THM->Parameters().T / m_THM->Volume() * totals[i] - aij * densities[j] / m_THM->Parameters().T * densities[i] * V);
499  }
500 
501  }
502  if (!fl) continue;
503  m_LastWeight = weight;
504  m_LastLogWeight = logweight;
505  m_LastNormWeight = normweight;
506 
507  //if (normweight > 1.)
508  // std::cout << std::scientific << normweight - 1. << std::fixed << "\n";
509 
510  //std::cout << "Norm weight = " << normweight << " " << weight / weightvdw << " " << std::scientific << normweight - 1. << std::fixed << "\n";
511  }
512 
513  break;
514  }
515 
516  fCEAccepted++;
517 
518  return totals;
519  }
520 
521  std::vector<int> EventGeneratorBase::GenerateTotalsGCE() const
522  {
523  fCETotal++;
524 
526  std::vector<int> totals(m_THM->TPS()->Particles().size(), 0);
527 
528  const std::vector<double>& densities = m_THM->Densities();
529  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
530  double mean = densities[i] * m_THM->Volume();
531  int total = RandomGenerators::RandomPoisson(mean);
532  totals[i] = total;
533  }
534 
535  return totals;
536  }
537 
538  std::vector<int> EventGeneratorBase::GenerateTotalsSCE() const
539  {
540  if (!m_THM->IsGCECalculated())
542 
543  std::vector<int> totals(m_THM->TPS()->Particles().size(), 0);
544 
545  // Generate SCE configuration depending on whether Vc > V, Vc = V, or Vc < V
546  while (true) {
547  const std::vector<double>& densities = m_THM->Densities();
548 
549  // If Vc = V then just generate yields from a single ensemble
550  if (m_THM->Volume() == m_THM->CanonicalVolume()) {
552  }
553  // If Vc > V then generate yields from a single ensemble with volume Vc
554  // particle from this ensemble is within a smaller volume V
555  // with probability V/Vc
556  else if (m_THM->Volume() < m_THM->CanonicalVolume()) {
557  std::vector<int> totalsaux = GenerateTotalsSCESubVolume(m_THM->CanonicalVolume());
558  double prob = m_THM->Volume() / m_THM->CanonicalVolume();
559  for (size_t i = 0; i < totalsaux.size(); ++i) {
560  for (int j = 0; j < totalsaux[i]; ++j) {
561  if (RandomGenerators::randgenMT.rand() < prob)
562  totals[i]++;
563  }
564  }
565  }
566  // If V > Vc then generate yields from (int)(V/Vc) SCE ensembles
567  // plus special treatment of one more ensemble if (V mod Vc) != 0
568  else {
569  // Number of normal SCE sub-ensembles
570  int multiples = static_cast<int>(m_THM->Volume() / m_THM->CanonicalVolume());
571 
572  for (int iter = 0; iter < multiples; ++iter) {
573  std::vector<int> totalsaux = GenerateTotalsSCESubVolume(m_THM->CanonicalVolume());
574  for (size_t i = 0; i < totalsaux.size(); ++i)
575  totals[i] += totalsaux[i];
576  }
577 
578  // For (V mod Vc) != 0 there is one more subvolume Vsub < Vc
579  double fraction = (m_THM->Volume() - multiples * m_THM->CanonicalVolume()) / m_THM->CanonicalVolume();
580 
581  if (fraction > 0.0) {
582 
583  bool successflag = false;
584 
585  while (!successflag) {
586 
587  std::vector<int> totalsaux = GenerateTotalsSCESubVolume(m_THM->CanonicalVolume());
588  std::vector<int> totalsaux2(m_THM->TPS()->Particles().size(), 0);
589  int netS = 0;
590  for (size_t i = 0; i < totalsaux.size(); ++i) {
591  if (m_THM->TPS()->Particles()[i].Strangeness() > 0) {
592  for (int j = 0; j < totalsaux[i]; ++j) {
593  if (RandomGenerators::randgenMT.rand() < fraction) {
594  totalsaux2[i]++;
595  netS += m_THM->TPS()->Particles()[i].Strangeness();
596  }
597  }
598  }
599  }
600 
601  // Check if possible to match S+ with S-
602  // If S = 1 then must be at least one S = -1 hadron
603  if (netS == 1) {
604  bool fl = false;
605  for (size_t i = 0; i < totalsaux.size(); ++i) {
606  if (m_THM->TPS()->Particles()[i].Strangeness() < 0 && totalsaux[i] > 0) {
607  fl = true;
608  break;
609  }
610  }
611  if (!fl) {
612  printf("**WARNING** SCE Event generator: Cannot match S- with S+ = 1, discarding subconfiguration...\n");
613  continue;
614  }
615  }
616 
617  int repeatmax = 10000;
618  int repeat = 0;
619  while (true) {
620  int netS2 = netS;
621  for (size_t i = 0; i < totalsaux.size(); ++i) {
622  if (m_THM->TPS()->Particles()[i].Strangeness() < 0) {
623  totalsaux2[i] = 0;
624  for (int j = 0; j < totalsaux[i]; ++j) {
625  if (RandomGenerators::randgenMT.rand() < fraction) {
626  totalsaux2[i]++;
627  netS2 += m_THM->TPS()->Particles()[i].Strangeness();
628  }
629  }
630  }
631  }
632  if (netS2 == 0) {
633  for (size_t i = 0; i < totalsaux2.size(); ++i)
634  totals[i] += totalsaux2[i];
635  successflag = true;
636  break;
637  }
638  repeat++;
639  if (repeat >= repeatmax) {
640  printf("**WARNING** SCE event generator: Cannot match S- with S+, too many tries, discarding configuration...\n");
641  break;
642  }
643  }
644  }
645  }
646  }
647 
648  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
649  if (m_THM->TPS()->Particles()[i].Strangeness() == 0) {
650  double mean = densities[i] * m_THM->Volume();
651  int total = RandomGenerators::RandomPoisson(mean);
652  totals[i] = total;
653  }
654  }
655 
656  return totals;
657  }
658 
659  return totals;
660  }
661 
662  std::vector<int> EventGeneratorBase::GenerateTotalsSCESubVolume(double VolumeSC) const
663  {
665  std::vector<int> totals(m_THM->TPS()->Particles().size(), 0);
666 
667  std::vector< std::pair<double, int> > fStrangeMesonsc = m_StrangeMesons;
668  std::vector< std::pair<double, int> > fAntiStrangeMesonsc = m_AntiStrangeMesons;
669 
670  for (size_t i = 0; i < fStrangeMesonsc.size(); ++i)
671  fStrangeMesonsc[i].first *= VolumeSC / m_THM->Volume();
672 
673  for (size_t i = 0; i < fAntiStrangeMesonsc.size(); ++i)
674  fAntiStrangeMesonsc[i].first *= VolumeSC / m_THM->Volume();
675 
676  double fMeanSMc = m_MeanSM * VolumeSC / m_THM->Volume();
677  double fMeanASMc = m_MeanASM * VolumeSC / m_THM->Volume();
678 
679  while (1) {
680  fCETotal++;
681  const std::vector<double>& densities = m_THM->Densities();
682 
683  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) totals[i] = 0;
684  int netS = 0;
685  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
686  if (m_THM->TPS()->Particles()[i].BaryonCharge() != 0 && m_THM->TPS()->Particles()[i].Strangeness() != 0) {
687  double mean = densities[i] * VolumeSC;
688  int total = RandomGenerators::RandomPoisson(mean);
689  totals[i] = total;
690  netS += totals[i] * m_THM->TPS()->Particles()[i].Strangeness();
691  }
692  }
693  int tSM = RandomGenerators::RandomPoisson(fMeanSMc);
694  int tASM = RandomGenerators::RandomPoisson(fMeanASMc);
695 
696  if (netS != tASM - tSM) continue;
697 
698  for (int i = 0; i < tSM; ++i) {
699  std::vector< std::pair<double, int> >::iterator it = lower_bound(fStrangeMesonsc.begin(), fStrangeMesonsc.end(), std::make_pair(fMeanSMc*RandomGenerators::randgenMT.rand(), 0));
700  int tind = std::distance(fStrangeMesonsc.begin(), it);
701  if (tind < 0) tind = 0;
702  if (tind >= static_cast<int>(fStrangeMesonsc.size())) tind = fStrangeMesonsc.size() - 1;
703  totals[fStrangeMesonsc[tind].second]++;
704  }
705  for (int i = 0; i < tASM; ++i) {
706  std::vector< std::pair<double, int> >::iterator it = lower_bound(fAntiStrangeMesonsc.begin(), fAntiStrangeMesonsc.end(), std::make_pair(fMeanASMc*RandomGenerators::randgenMT.rand(), 0));
707  int tind = std::distance(fAntiStrangeMesonsc.begin(), it);
708  if (tind < 0) tind = 0;
709  if (tind >= static_cast<int>(fAntiStrangeMesonsc.size())) tind = fAntiStrangeMesonsc.size() - 1;
710  totals[fAntiStrangeMesonsc[tind].second]++;
711  }
712 
713  // Cross-check that all resulting strangeness is zero
714  int finS = 0;
715  for (size_t i = 0; i < totals.size(); ++i) {
716  finS += totals[i] * m_THM->TPS()->Particles()[i].Strangeness();
717  }
718 
719  if (finS != 0) {
720  printf("**ERROR** EventGeneratorBase::GenerateTotalsSCESubVolume(): Generated strangeness is non-zero!");
721  exit(1);
722  }
723 
724  return totals;
725  }
726  return totals;
727  }
728 
729  std::vector<int> EventGeneratorBase::GenerateTotalsCCE() const
730  {
731  if (!m_THM->IsGCECalculated())
733 
734  // Check there are no multi-charmed particles, otherwise error
735  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
736  if (abs(m_THM->TPS()->Particles()[i].Charm()) > 1) {
737  printf("**ERROR** CCE Event generator does not support lists with multi-charmed particles\n");
738  exit(1);
739  }
740  }
741 
742  std::vector<int> totals(m_THM->TPS()->Particles().size(), 0);
743 
744  // Generate CCE configuration depending on whether Vc > V, Vc = V, or Vc < V
745  const std::vector<double>& densities = m_THM->Densities();
746 
747  // If Vc = V then just generate yields from a single ensemble
748  if (m_THM->Volume() == m_THM->CanonicalVolume()) {
750  }
751  // If Vc > V then generate yields from a single ensemble with volume Vc
752  // particle from this ensemble is within a smaller volume V
753  // with probability V/Vc
754  else if (m_THM->Volume() < m_THM->CanonicalVolume()) {
755  std::vector<int> totalsaux = GenerateTotalsCCESubVolume(m_THM->CanonicalVolume());
756  double prob = m_THM->Volume() / m_THM->CanonicalVolume();
757  for (size_t i = 0; i < totalsaux.size(); ++i) {
758  for (int j = 0; j < totalsaux[i]; ++j) {
759  if (RandomGenerators::randgenMT.rand() < prob)
760  totals[i]++;
761  }
762  }
763  }
764  // If V > Vc then generate yields from (int)(V/Vc) SCE ensembles
765  // plus special treatment of one more ensemble if (V mod Vc) != 0
766  else {
767  // Number of normal CCE sub-ensembles
768  int multiples = static_cast<int>(m_THM->Volume() / m_THM->CanonicalVolume());
769 
770  for (int iter = 0; iter < multiples; ++iter) {
771  std::vector<int> totalsaux = GenerateTotalsCCESubVolume(m_THM->CanonicalVolume());
772  for (size_t i = 0; i < totalsaux.size(); ++i)
773  totals[i] += totalsaux[i];
774  }
775 
776  // For (V mod Vc) != 0 there is one more subvolume Vsub < Vc
777  double fraction = (m_THM->Volume() - multiples * m_THM->CanonicalVolume()) / m_THM->CanonicalVolume();
778 
779  if (fraction > 0.0) {
780 
781  bool successflag = false;
782 
783  while (!successflag) {
784 
785  std::vector<int> totalsaux = GenerateTotalsCCESubVolume(m_THM->CanonicalVolume());
786  std::vector<int> totalsaux2(m_THM->TPS()->Particles().size(), 0);
787  int netC = 0;
788  for (size_t i = 0; i < totalsaux.size(); ++i) {
789  if (m_THM->TPS()->Particles()[i].Charm() > 0) {
790  for (int j = 0; j < totalsaux[i]; ++j) {
791  if (RandomGenerators::randgenMT.rand() < fraction) {
792  totalsaux2[i]++;
793  netC += m_THM->TPS()->Particles()[i].Charm();
794  }
795  }
796  }
797  }
798 
799  // Check if possible to match C+ with C-
800  // If C = 1 then must be at least one C = -1 hadron
801  if (netC == 1) {
802  bool fl = false;
803  for (size_t i = 0; i < totalsaux.size(); ++i) {
804  if (m_THM->TPS()->Particles()[i].Charm() < 0 && totalsaux[i] > 0) {
805  fl = true;
806  break;
807  }
808  }
809  if (!fl) {
810  printf("**WARNING** CCE Event generator: Cannot match C- with C+ = 1, discarding...\n");
811  continue;
812  }
813  }
814 
815  int repeatmax = 10000;
816  int repeat = 0;
817  while (true) {
818  int netC2 = netC;
819  for (size_t i = 0; i < totalsaux.size(); ++i) {
820  if (m_THM->TPS()->Particles()[i].Charm() < 0) {
821  totalsaux2[i] = 0;
822  for (int j = 0; j < totalsaux[i]; ++j) {
823  if (RandomGenerators::randgenMT.rand() < fraction) {
824  totalsaux2[i]++;
825  netC2 += m_THM->TPS()->Particles()[i].Charm();
826  }
827  }
828  }
829  }
830  if (netC2 == 0) {
831  for (size_t i = 0; i < totalsaux2.size(); ++i)
832  totals[i] += totalsaux2[i];
833  successflag = true;
834  break;
835  }
836  repeat++;
837  if (repeat >= repeatmax) {
838  printf("**WARNING** CCE event generator: Cannot match S- with S+, too many tries, discarding...\n");
839  break;
840  }
841  }
842  }
843  }
844  }
845 
846  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
847  if (m_THM->TPS()->Particles()[i].Charm() == 0) {
848  double mean = densities[i] * m_THM->Volume();
849  int total = RandomGenerators::RandomPoisson(mean);
850  totals[i] = total;
851  }
852  }
853 
854  return totals;
855  }
856 
857  std::vector<int> EventGeneratorBase::GenerateTotalsCCESubVolume(double VolumeSC) const
858  {
859  if (!m_THM->IsGCECalculated())
861 
862  std::vector<int> totals(m_THM->TPS()->Particles().size(), 0);
863 
864  std::vector< std::pair<double, int> > fCharmAllc = m_CharmAll;
865  std::vector< std::pair<double, int> > fAntiCharmAllc = m_AntiCharmAll;
866 
867  for (size_t i = 0; i < fCharmAllc.size(); ++i)
868  fCharmAllc[i].first *= VolumeSC / m_THM->Volume();
869 
870  for (size_t i = 0; i < fAntiCharmAllc.size(); ++i)
871  fAntiCharmAllc[i].first *= VolumeSC / m_THM->Volume();
872 
873  // Assuming no multi-charmed particles
874  double fMeanCharmc = m_MeanCHRM * VolumeSC / m_THM->Volume();
875  double fMeanAntiCharmc = m_MeanACHRM * VolumeSC / m_THM->Volume();
876 
877  fCETotal++;
878 
879  int netC = 0;
880  int tC = RandomGenerators::RandomPoisson(fMeanCharmc);
881  int tAC = RandomGenerators::RandomPoisson(fMeanAntiCharmc);
882  while (tC - tAC != m_THM->Parameters().C - netC) {
883  fCETotal++;
884  tC = RandomGenerators::RandomPoisson(fMeanCharmc);
885  tAC = RandomGenerators::RandomPoisson(fMeanAntiCharmc);
886  }
887 
888  for (int i = 0; i < tC; ++i) {
889  std::vector< std::pair<double, int> >::iterator it = lower_bound(fCharmAllc.begin(), fCharmAllc.end(), std::make_pair(fMeanCharmc*RandomGenerators::randgenMT.rand(), 0));
890  int tind = std::distance(fCharmAllc.begin(), it);
891  if (tind < 0) tind = 0;
892  if (tind >= static_cast<int>(fCharmAllc.size())) tind = fCharmAllc.size() - 1;
893  totals[fCharmAllc[tind].second]++;
894  }
895  for (int i = 0; i < tAC; ++i) {
896  std::vector< std::pair<double, int> >::iterator it = lower_bound(fAntiCharmAllc.begin(), fAntiCharmAllc.end(), std::make_pair(fMeanAntiCharmc*RandomGenerators::randgenMT.rand(), 0));
897  int tind = std::distance(fAntiCharmAllc.begin(), it);
898  if (tind < 0) tind = 0;
899  if (tind >= static_cast<int>(fAntiCharmAllc.size())) tind = fAntiCharmAllc.size() - 1;
900  totals[fAntiCharmAllc[tind].second]++;
901  }
902 
903  // Cross-check that total resulting net charm is zero
904  int finC = 0;
905  for (size_t i = 0; i < totals.size(); ++i) {
906  finC += totals[i] * m_THM->TPS()->Particles()[i].Charm();
907  }
908 
909  if (finC != m_THM->Parameters().C) {
910  printf("**ERROR** EventGeneratorBase::GenerateTotalsCCESubVolume(): Generated charm is non-zero!");
911  exit(1);
912  }
913 
914  return totals;
915  }
916 
917 
918  std::vector<int> EventGeneratorBase::GenerateTotalsCE() const {
920  std::vector<int> totals(m_THM->TPS()->Particles().size(), 0);
921 
922  const std::vector< std::pair<double, int> >& fBaryonsc = m_Baryons;
923  const std::vector< std::pair<double, int> >& fAntiBaryonsc = m_AntiBaryons;
924  const std::vector< std::pair<double, int> >& fStrangeMesonsc = m_StrangeMesons;
925  const std::vector< std::pair<double, int> >& fAntiStrangeMesonsc = m_AntiStrangeMesons;
926  const std::vector< std::pair<double, int> >& fChargeMesonsc = m_ChargeMesons;
927  const std::vector< std::pair<double, int> >& fAntiChargeMesonsc = m_AntiChargeMesons;
928  const std::vector< std::pair<double, int> >& fCharmMesonsc = m_CharmMesons;
929  const std::vector< std::pair<double, int> >& fAntiCharmMesonsc = m_AntiCharmMesons;
930 
931  // Primitive rejection sampling (not used, but can be explored for comparisons)
932  while (0) {
933  fCETotal++;
934  int netB = 0, netS = 0, netQ = 0, netC = 0;
935  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
936  double mean = m_THM->Densities()[i] * m_THM->Volume();
937  int total = RandomGenerators::RandomPoisson(mean);
938  totals[i] = total;
939  netB += totals[i] * m_THM->TPS()->Particles()[i].BaryonCharge();
940  netS += totals[i] * m_THM->TPS()->Particles()[i].Strangeness();
941  netQ += totals[i] * m_THM->TPS()->Particles()[i].ElectricCharge();
942  netC += totals[i] * m_THM->TPS()->Particles()[i].Charm();
943  }
944  if ((!m_Config.CanonicalB || netB == m_THM->Parameters().B)
945  && (!m_Config.CanonicalS || netS == m_THM->Parameters().S)
946  && (!m_Config.CanonicalQ || netQ == m_THM->Parameters().Q)
947  && (!m_Config.CanonicalC || netC == m_THM->Parameters().C)) {
948  fCEAccepted++;
949  return totals;
950  }
951  }
952 
953  // Multi-step procedure as described in F. Becattini, L. Ferroni, hep-ph/0307061
954  while (1) {
955  fCETotal++;
956 
957  const std::vector<double>& densities = m_THM->Densities();
958 
959  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) totals[i] = 0;
960  int netB = 0, netS = 0, netQ = 0, netC = 0;
961 
962 
963  // Light nuclei first
964  bool flNuclei = false; // Whether light nuclei appear at all
965 
966  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
967  if (abs(m_THM->TPS()->Particles()[i].BaryonCharge()) > 1) {
968  flNuclei = true;
969  double mean = densities[i] * m_THM->Volume();
970  int total = RandomGenerators::RandomPoisson(mean);
971  totals[i] = total;
972  netB += totals[i] * m_THM->TPS()->Particles()[i].BaryonCharge();
973  netS += totals[i] * m_THM->TPS()->Particles()[i].Strangeness();
974  netQ += totals[i] * m_THM->TPS()->Particles()[i].ElectricCharge();
975  netC += totals[i] * m_THM->TPS()->Particles()[i].Charm();
976  }
977  }
978 
979  // Then all hadrons
980 
981  int tB = 0, tAB = 0;
982  // First total baryons and antibaryons from the Poisson distribution
983  if (flNuclei || !m_Config.CanonicalB) {
984  tB = RandomGenerators::RandomPoisson(m_MeanB);
985  tAB = RandomGenerators::RandomPoisson(m_MeanAB);
986  if (m_Config.CanonicalB && tB - tAB != m_THM->Parameters().B - netB) continue;
987  //if (RandomGenerators::randgenMT.rand() > RandomGenerators::SkellamProbability(m_THM->Parameters().B - netB, m_MeanB, m_MeanAB))
988  // continue;
989  }
990  else
991  // Generate from the Bessel distribution, using Devroye's method, if no light nuclei
992  {
993  int nu = m_THM->Parameters().B - netB;
994  if (nu < 0) nu = -nu;
995  double a = 2. * sqrt(m_MeanB * m_MeanAB);
996  //int BessN = RandomGenerators::BesselDistributionGenerator::RandomBesselDevroye3(a, nu);
997  //int BessN = RandomGenerators::BesselDistributionGenerator::RandomBesselPoisson(a, nu);
998  //int BessN = RandomGenerators::BesselDistributionGenerator::RandomBesselCombined(a, nu);
1000  if (m_THM->Parameters().B - netB < 0) {
1001  tB = BessN;
1002  tAB = nu + tB;
1003  }
1004  else {
1005  tAB = BessN;
1006  tB = nu + tAB;
1007  }
1008  }
1009 
1010  // Then individual baryons and antibaryons from the multinomial distribution
1011  for (int i = 0; i < tB; ++i) {
1012  std::vector< std::pair<double, int> >::const_iterator it = lower_bound(fBaryonsc.begin(), fBaryonsc.end(), std::make_pair(m_MeanB*RandomGenerators::randgenMT.rand(), 0));
1013  int tind = std::distance(fBaryonsc.begin(), it);
1014  if (tind < 0) tind = 0;
1015  if (tind >= static_cast<int>(fBaryonsc.size())) tind = fBaryonsc.size() - 1;
1016  totals[fBaryonsc[tind].second]++;
1017  netS += m_THM->TPS()->Particles()[fBaryonsc[tind].second].Strangeness();
1018  netQ += m_THM->TPS()->Particles()[fBaryonsc[tind].second].ElectricCharge();
1019  netC += m_THM->TPS()->Particles()[fBaryonsc[tind].second].Charm();
1020  }
1021  for (int i = 0; i < tAB; ++i) {
1022  std::vector< std::pair<double, int> >::const_iterator it = lower_bound(fAntiBaryonsc.begin(), fAntiBaryonsc.end(), std::make_pair(m_MeanAB*RandomGenerators::randgenMT.rand(), 0));
1023  int tind = std::distance(fAntiBaryonsc.begin(), it);
1024  if (tind < 0) tind = 0;
1025  if (tind >= static_cast<int>(fAntiBaryonsc.size())) tind = fAntiBaryonsc.size() - 1;
1026  totals[fAntiBaryonsc[tind].second]++;
1027  netS += m_THM->TPS()->Particles()[fAntiBaryonsc[tind].second].Strangeness();
1028  netQ += m_THM->TPS()->Particles()[fAntiBaryonsc[tind].second].ElectricCharge();
1029  netC += m_THM->TPS()->Particles()[fAntiBaryonsc[tind].second].Charm();
1030  }
1031 
1032  // Total numbers of (anti)strange mesons
1033 
1034  int tSM = RandomGenerators::RandomPoisson(m_MeanSM);
1035  int tASM = RandomGenerators::RandomPoisson(m_MeanASM);
1036  if (m_Config.CanonicalS && netS != tASM - tSM + m_THM->Parameters().S) continue;
1037 
1038 
1039  // Multinomial distribution for individual numbers of (anti)strange mesons
1040  for (int i = 0; i < tSM; ++i) {
1041  std::vector< std::pair<double, int> >::const_iterator it = lower_bound(fStrangeMesonsc.begin(), fStrangeMesonsc.end(), std::make_pair(m_MeanSM*RandomGenerators::randgenMT.rand(), 0));
1042  int tind = std::distance(fStrangeMesonsc.begin(), it);
1043  if (tind < 0) tind = 0;
1044  if (tind >= static_cast<int>(fStrangeMesonsc.size())) tind = fStrangeMesonsc.size() - 1;
1045  totals[fStrangeMesonsc[tind].second]++;
1046  netQ += m_THM->TPS()->Particles()[fStrangeMesonsc[tind].second].ElectricCharge();
1047  netC += m_THM->TPS()->Particles()[fStrangeMesonsc[tind].second].Charm();
1048  }
1049  for (int i = 0; i < tASM; ++i) {
1050  std::vector< std::pair<double, int> >::const_iterator it = lower_bound(fAntiStrangeMesonsc.begin(), fAntiStrangeMesonsc.end(), std::make_pair(m_MeanASM*RandomGenerators::randgenMT.rand(), 0));
1051  int tind = std::distance(fAntiStrangeMesonsc.begin(), it);
1052  if (tind < 0) tind = 0;
1053  if (tind >= static_cast<int>(fAntiStrangeMesonsc.size())) tind = fAntiStrangeMesonsc.size() - 1;
1054  totals[fAntiStrangeMesonsc[tind].second]++;
1055  netQ += m_THM->TPS()->Particles()[fAntiStrangeMesonsc[tind].second].ElectricCharge();
1056  netC += m_THM->TPS()->Particles()[fAntiStrangeMesonsc[tind].second].Charm();
1057  }
1058 
1059  // Total numbers of remaining electrically charged mesons
1060  int tCM = RandomGenerators::RandomPoisson(m_MeanCM);
1061  int tACM = RandomGenerators::RandomPoisson(m_MeanACM);
1062  if (m_Config.CanonicalQ && netQ != tACM - tCM + m_THM->Parameters().Q) continue;
1063 
1064  // Multinomial distribution for individual numbers of remaining electrically charged mesons
1065  for (int i = 0; i < tCM; ++i) {
1066  std::vector< std::pair<double, int> >::const_iterator it = lower_bound(fChargeMesonsc.begin(), fChargeMesonsc.end(), std::make_pair(m_MeanCM*RandomGenerators::randgenMT.rand(), 0));
1067  int tind = std::distance(fChargeMesonsc.begin(), it);
1068  if (tind < 0) tind = 0;
1069  if (tind >= static_cast<int>(fChargeMesonsc.size())) tind = fChargeMesonsc.size() - 1;
1070  totals[fChargeMesonsc[tind].second]++;
1071  netC += m_THM->TPS()->Particles()[fChargeMesonsc[tind].second].Charm();
1072  }
1073  for (int i = 0; i < tACM; ++i) {
1074  std::vector< std::pair<double, int> >::const_iterator it = lower_bound(fAntiChargeMesonsc.begin(), fAntiChargeMesonsc.end(), std::make_pair(m_MeanACM*RandomGenerators::randgenMT.rand(), 0));
1075  int tind = std::distance(fAntiChargeMesonsc.begin(), it);
1076  if (tind < 0) tind = 0;
1077  if (tind >= static_cast<int>(fAntiChargeMesonsc.size())) tind = fAntiChargeMesonsc.size() - 1;
1078  totals[fAntiChargeMesonsc[tind].second]++;
1079  netC += m_THM->TPS()->Particles()[fAntiChargeMesonsc[tind].second].Charm();
1080  }
1081 
1082  // Total numbers of remaining charmed mesons
1083  int tCHRMM = RandomGenerators::RandomPoisson(m_MeanCHRMM);
1084  int tACHRNMM = RandomGenerators::RandomPoisson(m_MeanACHRMM);
1085 
1086  if (m_Config.CanonicalC && netC != tACHRNMM - tCHRMM + m_THM->Parameters().C) continue;
1087 
1088  // Multinomial distribution for individual numbers of the remaining charmed mesons
1089  for (int i = 0; i < tCHRMM; ++i) {
1090  std::vector< std::pair<double, int> >::const_iterator it = lower_bound(fCharmMesonsc.begin(), fCharmMesonsc.end(), std::make_pair(m_MeanCHRMM*RandomGenerators::randgenMT.rand(), 0));
1091  int tind = std::distance(fCharmMesonsc.begin(), it);
1092  if (tind < 0) tind = 0;
1093  if (tind >= static_cast<int>(fCharmMesonsc.size())) tind = fCharmMesonsc.size() - 1;
1094  totals[fCharmMesonsc[tind].second]++;
1095  }
1096  for (int i = 0; i < tACHRNMM; ++i) {
1097  std::vector< std::pair<double, int> >::const_iterator it = lower_bound(fAntiCharmMesonsc.begin(), fAntiCharmMesonsc.end(), std::make_pair(m_MeanACHRMM*RandomGenerators::randgenMT.rand(), 0));
1098  int tind = std::distance(fAntiCharmMesonsc.begin(), it);
1099  if (tind < 0) tind = 0;
1100  if (tind >= static_cast<int>(fAntiCharmMesonsc.size())) tind = fAntiCharmMesonsc.size() - 1;
1101  totals[fAntiCharmMesonsc[tind].second]++;
1102  }
1103 
1104  // Poisson distribution for all neutral particles
1105  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
1106  if (m_THM->TPS()->Particles()[i].BaryonCharge() == 0
1107  && m_THM->TPS()->Particles()[i].Strangeness() == 0
1108  && m_THM->TPS()->Particles()[i].ElectricCharge() == 0
1109  && m_THM->TPS()->Particles()[i].Charm() == 0) {
1110  double mean = densities[i] * m_THM->Volume();
1111  int total = RandomGenerators::RandomPoisson(mean);
1112  totals[i] = total;
1113  }
1114  }
1115 
1116  // Cross-check that all resulting charges are OK
1117  int finB = 0, finQ = 0, finS = 0, finC = 0;
1118  for (size_t i = 0; i < totals.size(); ++i) {
1119  finB += totals[i] * m_THM->TPS()->Particles()[i].BaryonCharge();
1120  finQ += totals[i] * m_THM->TPS()->Particles()[i].ElectricCharge();
1121  finS += totals[i] * m_THM->TPS()->Particles()[i].Strangeness();
1122  finC += totals[i] * m_THM->TPS()->Particles()[i].Charm();
1123  }
1124 
1125  if (m_Config.CanonicalB && finB != m_THM->Parameters().B) {
1126  printf("**ERROR** EventGeneratorBase::GenerateTotalsCE(): Generated baryon number does not match the input!");
1127  exit(1);
1128  }
1129 
1130  if (m_Config.CanonicalQ && finQ != m_THM->Parameters().Q) {
1131  printf("**ERROR** EventGeneratorBase::GenerateTotalsCE(): Generated electric charge does not match the input!");
1132  exit(1);
1133  }
1134 
1135  if (m_Config.CanonicalS && finS != m_THM->Parameters().S) {
1136  printf("**ERROR** EventGeneratorBase::GenerateTotalsCE(): Generated strangeness does not match the input!");
1137  exit(1);
1138  }
1139 
1140  if (m_Config.CanonicalC && finC != m_THM->Parameters().C) {
1141  printf("**ERROR** EventGeneratorBase::GenerateTotalsCE(): Generated charm does not match the input!");
1142  exit(1);
1143  }
1144 
1145  return totals;
1146  }
1147  return totals;
1148  }
1149 
1150  std::pair<std::vector<int>, double> EventGeneratorBase::SampleYields() const
1151  {
1152  std::vector<int> totals = GenerateTotals();
1153  return make_pair(totals, m_LastNormWeight);
1154  //std::vector<int> totals = GenerateTotalsGCE();
1155  //return make_pair(totals, 1.);
1156  }
1157 
1158  SimpleEvent EventGeneratorBase::SampleMomenta(const std::vector<int>& yields) const
1159  {
1160  SimpleEvent ret;
1161 
1162  std::vector< std::vector<SimpleParticle> > primParticles(m_THM->TPS()->Particles().size());
1163 
1164  for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
1165  const ThermalParticle& species = m_THM->TPS()->Particles()[i];
1166  primParticles[i].resize(0);
1167  int total = yields[i];
1168  for (int part = 0; part < total; ++part) {
1169  double tmass = species.Mass();
1171  tmass = m_BWGens[i]->GetRandom();
1172 
1173  // Check for Bose-Einstein condensation
1174  // Force m = mu if the sampled mass is too small
1175  double tmu = m_THM->FullIdealChemicalPotential(i);
1176  if (species.Statistics() == -1 && tmu > tmass) {
1177  tmass = tmu;
1178  }
1179 
1180  std::vector<double> momentum = m_MomentumGens[i]->GetMomentum(tmass);
1181  //std::vector<double> momentum = m_MomentumGens[i]->GetMomentum(0.99999 * m_THM->TPS()->Particles()[i].Mass());
1182 
1183  primParticles[i].push_back(SimpleParticle(momentum[0], momentum[1], momentum[2], tmass, species.PdgId()));
1184  }
1185  }
1186 
1187  for (int i = primParticles.size() - 1; i >= 0; --i) {
1188  ret.Particles.insert(ret.Particles.end(), primParticles[i].begin(), primParticles[i].end());
1189  }
1190 
1191  ret.AllParticles = ret.Particles;
1192 
1193  ret.DecayMap.resize(ret.Particles.size());
1194  fill(ret.DecayMap.begin(), ret.DecayMap.end(), -1);
1195 
1196  ret.DecayMapFinal.resize(ret.Particles.size());
1197  for (int i = 0; i < ret.DecayMapFinal.size(); ++i)
1198  ret.DecayMapFinal[i] = i;
1199 
1200  return ret;
1201  }
1202 
1204  {
1206 
1207  std::vector<int> totals = GenerateTotals();
1208 
1209  SimpleEvent ret = SampleMomenta(totals);
1210  ret.weight = m_LastWeight;
1211  ret.logweight = m_LastLogWeight;
1212  ret.weight = m_LastNormWeight;
1213 
1214  //std::vector< std::vector<SimpleParticle> > primParticles(m_THM->TPS()->Particles().size());
1215  //for (size_t i = 0; i < m_THM->TPS()->Particles().size(); ++i) {
1216  // primParticles[i].resize(0);
1217  // int total = totals[i];
1218  // for (int part = 0; part < total; ++part) {
1219  // const ThermalParticle& tpart = m_THM->TPS()->Particles()[i];
1220  // double tmass = tpart.Mass();
1221  // if (m_THM->UseWidth() && !tpart.ZeroWidthEnforced() && !(tpart.GetResonanceWidthIntegrationType() == ThermalParticle::ZeroWidth))
1222  // tmass = m_BWGens[i]->GetRandom();
1223 
1224  // // Check for Bose-Einstein condensation
1225  // // Force m = mu if the sampled mass is too small
1226  // double tmu = m_THM->FullIdealChemicalPotential(i);
1227  // if (tpart.Statistics() == -1 && tmu > tmass) {
1228  // tmass = tmu;
1229  // }
1230 
1231  // std::vector<double> momentum = m_MomentumGens[i]->GetMomentum(tmass);
1232  // //std::vector<double> momentum = m_MomentumGens[i]->GetMomentum(0.99999 * m_THM->TPS()->Particles()[i].Mass());
1233 
1234  // primParticles[i].push_back(SimpleParticle(momentum[0], momentum[1], momentum[2], tmass, m_THM->TPS()->Particles()[i].PdgId()));
1235  // }
1236  //}
1237  //
1238  //for (int i = primParticles.size() - 1; i >= 0; --i) {
1239  // ret.Particles.insert(ret.Particles.end(), primParticles[i].begin(), primParticles[i].end());
1240  //}
1241 
1242  //ret.AllParticles = ret.Particles;
1243 
1244  //ret.DecayMap.resize(ret.Particles.size());
1245  //fill(ret.DecayMap.begin(), ret.DecayMap.end(), -1);
1246 
1247  //ret.DecayMapFinal.resize(ret.Particles.size());
1248  //for (int i = 0; i < ret.DecayMapFinal.size(); ++i)
1249  // ret.DecayMapFinal[i] = i;
1250 
1251  if (DoDecays)
1252  return PerformDecays(ret, m_THM->TPS());
1253  else
1254  return ret;
1255  }
1256 
1257  // SimpleEvent EventGeneratorBase::PerformDecaysAlternativeWay(const SimpleEvent& evtin, ThermalParticleSystem* TPS)
1258  // {
1259  // SimpleEvent ret;
1260  // ret.weight = evtin.weight;
1261  // ret.logweight = evtin.logweight;
1262  // ret.AllParticles = evtin.Particles;
1263  // reverse(ret.AllParticles.begin(), ret.AllParticles.end());
1264 
1265  // for (auto&& part : ret.AllParticles)
1266  // part.processed = false;
1267 
1268 
1269  // bool flag_repeat = true;
1270  // while (flag_repeat) {
1271  // flag_repeat = false;
1272 
1273  // bool current_stable_flag = false;
1274  // long long current_pdgcode = 0;
1275  // long long current_tid = -1;
1276  // for (int i = ret.AllParticles.size() - 1; i >= 0; --i) {
1277  // SimpleParticle& particle = ret.AllParticles[i];
1278 
1279  // if (particle.processed)
1280  // continue;
1281 
1282  // long long tpdgcode = particle.PDGID;
1283  // if (!(tpdgcode == current_pdgcode))
1284  // {
1285  // current_tid = TPS->PdgToId(tpdgcode);
1286  // if (current_tid != -1)
1287  // current_stable_flag = TPS->Particle(current_tid).IsStable();
1288  // else
1289  // current_stable_flag = true;
1290  // current_pdgcode = tpdgcode;
1291  // }
1292 
1293 
1294  // if (current_stable_flag) {
1295  // //SimpleParticle prt = primParticles[i][j];
1296  // //double tpt = prt.GetPt();
1297  // //double ty = prt.GetY();
1298  // //if (static_cast<int>(m_acc.size()) < i || !m_acc[i].init || m_acc[i].getAcceptance(ty + m_ycm, tpt) > RandomGenerators::randgenMT.rand())
1299  // // ret.Particles.push_back(prt);
1300  // //primParticles[i][j].processed = true;
1301  // ret.Particles.push_back(particle);
1302  // particle.processed = true;
1303  // }
1304  // else {
1305  // flag_repeat = true;
1306  // double DecParam = RandomGenerators::randgenMT.rand(), tsum = 0.;
1307 
1308  // std::vector<double> Bratios;
1309  // if (particle.MotherPDGID != 0 ||
1310  // TPS->ResonanceWidthIntegrationType() != ThermalParticle::eBW) {
1311  // Bratios = TPS->Particles()[current_tid].BranchingRatiosM(particle.m, false);
1312  // }
1313  // else {
1314  // Bratios = TPS->Particles()[current_tid].BranchingRatiosM(particle.m, true);
1315  // }
1316 
1317  // int DecayIndex = 0;
1318  // for (DecayIndex = 0; DecayIndex < static_cast<int>(Bratios.size()); ++DecayIndex) {
1319  // tsum += Bratios[DecayIndex];
1320  // if (tsum > DecParam) break;
1321  // }
1322  // if (DecayIndex < static_cast<int>(TPS->Particles()[current_tid].Decays().size())) {
1323  // std::vector<double> masses(0);
1324  // std::vector<long long> pdgids(0);
1325  // for (size_t di = 0; di < TPS->Particles()[current_tid].Decays()[DecayIndex].mDaughters.size(); di++) {
1326  // long long dpdg = TPS->Particles()[current_tid].Decays()[DecayIndex].mDaughters[di];
1327  // if (TPS->PdgToId(dpdg) == -1) {
1328  // continue;
1329  // }
1330  // masses.push_back(TPS->ParticleByPDG(dpdg).Mass());
1331  // pdgids.push_back(dpdg);
1332  // }
1333  // std::vector<SimpleParticle> decres = ParticleDecaysMC::ManyBodyDecay(particle, masses, pdgids);
1334  // for (size_t ind = 0; ind < decres.size(); ind++) {
1335  // decres[ind].processed = false;
1336  // if (TPS->PdgToId(decres[ind].PDGID) != -1)
1337  // ret.AllParticles.push_back(decres[ind]);
1338  // }
1339  // ret.AllParticles[i].processed = true;
1340  // }
1341  // else {
1342  // // Decay through unknown branching ratio, presumably radiative, no hadrons, just ignore the decay products
1343  // ret.AllParticles[i].processed = true;
1344  // }
1345  // }
1346  // }
1347  // }
1348 
1349  // return ret;
1350  // }
1351 
1353  {
1354  SimpleEvent ret;
1355  ret.weight = evtin.weight;
1356  ret.logweight = evtin.logweight;
1357 
1358  ret.AllParticles = evtin.AllParticles;
1359  ret.DecayMap = evtin.DecayMap;
1360 
1361  std::vector< std::vector<SimpleParticle> > primParticles(TPS->Particles().size(), std::vector<SimpleParticle>(0));
1362  std::vector< std::vector<int> > AllParticlesMap(TPS->Particles().size(), std::vector<int>(0));
1363  for(int i = 0; i < evtin.Particles.size(); ++i) {
1364  const SimpleParticle& particle = evtin.Particles[i];
1365  long long tid = TPS->PdgToId(particle.PDGID);
1366  if (tid != -1) {
1367  primParticles[tid].push_back(particle);
1368  AllParticlesMap[tid].push_back(i);
1369  }
1370  }
1371 
1372  bool flag_repeat = true;
1373  while (flag_repeat) {
1374  flag_repeat = false;
1375  for (int i = static_cast<int>(primParticles.size()) - 1; i >= 0; --i) {
1376  if (TPS->Particles()[i].IsStable()) {
1377  for (size_t j = 0; j < primParticles[i].size(); ++j) {
1378  if (!primParticles[i][j].processed) {
1379  SimpleParticle prt = primParticles[i][j];
1380  ret.Particles.push_back(prt);
1381  primParticles[i][j].processed = true;
1382  int tid = AllParticlesMap[i][j];
1383  while (tid >= 0 && tid < ret.DecayMap.size() && ret.DecayMap[tid] != -1)
1384  tid = ret.DecayMap[tid];
1385  ret.DecayMapFinal.push_back(tid);
1386  }
1387  }
1388  }
1389  else {
1390  for (size_t j = 0; j < primParticles[i].size(); ++j) {
1391  if (!primParticles[i][j].processed) {
1392  flag_repeat = true;
1393  double DecParam = RandomGenerators::randgenMT.rand(), tsum = 0.;
1394 
1395  std::vector<double> Bratios;
1396  if (primParticles[i][j].MotherPDGID != 0 ||
1398  Bratios = TPS->Particles()[i].BranchingRatiosM(primParticles[i][j].m, false);
1399  }
1400  else {
1401  Bratios = TPS->Particles()[i].BranchingRatiosM(primParticles[i][j].m, true);
1402  }
1403 
1404  int DecayIndex = 0;
1405  for (DecayIndex = 0; DecayIndex < static_cast<int>(Bratios.size()); ++DecayIndex) {
1406  tsum += Bratios[DecayIndex];
1407  if (tsum > DecParam) break;
1408  }
1409  if (DecayIndex < static_cast<int>(TPS->Particles()[i].Decays().size())) {
1410  std::vector<double> masses(0);
1411  std::vector<long long> pdgids(0);
1412  for (size_t di = 0; di < TPS->Particles()[i].Decays()[DecayIndex].mDaughters.size(); di++) {
1413  long long dpdg = TPS->Particles()[i].Decays()[DecayIndex].mDaughters[di];
1414  if (TPS->PdgToId(dpdg) == -1) {
1415  // Try to see if the daughter particle is a photon/lepton
1416  if (ExtraParticles::PdgToId(dpdg) == -1)
1417  continue;
1418  else
1419  masses.push_back(ExtraParticles::ParticleByPdg(dpdg).Mass());
1420  }
1421  else {
1422  masses.push_back(TPS->ParticleByPDG(dpdg).Mass());
1423  }
1424  pdgids.push_back(dpdg);
1425  }
1426  std::vector<SimpleParticle> decres = ParticleDecaysMC::ManyBodyDecay(primParticles[i][j], masses, pdgids);
1427  for (size_t ind = 0; ind < decres.size(); ind++) {
1428  decres[ind].processed = false;
1429  if (TPS->PdgToId(decres[ind].PDGID) != -1) {
1430  int tid = TPS->PdgToId(decres[ind].PDGID);
1431  SimpleParticle& dprt = decres[ind];
1432  primParticles[tid].push_back(dprt);
1433  ret.AllParticles.push_back(dprt);
1434  AllParticlesMap[tid].push_back(static_cast<int>(ret.AllParticles.size()) - 1);
1435  ret.DecayMap.push_back(AllParticlesMap[i][j]);
1436  }
1437  else if (ExtraParticles::PdgToId(decres[ind].PDGID) != -1) {
1438  SimpleParticle& dprt = decres[ind];
1439  ret.AllParticles.push_back(dprt);
1440  ret.DecayMap.push_back(AllParticlesMap[i][j]);
1441  ret.PhotonsLeptons.push_back(dprt);
1442  }
1443  }
1444  primParticles[i][j].processed = true;
1445  }
1446  else {
1447  // Decay through unknown branching ratio, presumably radiative, no hadrons, just ignore decay products
1448  primParticles[i][j].processed = true;
1449  }
1450  }
1451  }
1452  }
1453  }
1454  }
1455 
1456  return ret;
1457  }
1458 
1460  {
1462  RescaleCEMeans(V / m_THM->Volume());
1463  m_THM->SetVolume(V);
1464  m_Config.CFOParameters.V = V;
1466  m_Config.CFOParameters.SVc = V;
1467  }
1468 
1470  {
1471  m_MeanB *= Vmod;
1472  m_MeanAB *= Vmod;
1473  m_MeanSM *= Vmod;
1474  m_MeanASM *= Vmod;
1475  m_MeanCM *= Vmod;
1476  m_MeanACM *= Vmod;
1477  m_MeanCHRMM *= Vmod;
1478  m_MeanACHRMM *= Vmod;
1479  m_MeanCHRM *= Vmod;
1480  m_MeanACHRM *= Vmod;
1481 
1482  for (int i = 0; i < static_cast<int>(m_Baryons.size()); ++i) m_Baryons[i].first *= Vmod;
1483  for (int i = 0; i < static_cast<int>(m_AntiBaryons.size()); ++i) m_AntiBaryons[i].first *= Vmod;
1484  for (int i = 0; i < static_cast<int>(m_StrangeMesons.size()); ++i) m_StrangeMesons[i].first *= Vmod;
1485  for (int i = 0; i < static_cast<int>(m_AntiStrangeMesons.size()); ++i) m_AntiStrangeMesons[i].first *= Vmod;
1486  for (int i = 0; i < static_cast<int>(m_ChargeMesons.size()); ++i) m_ChargeMesons[i].first *= Vmod;
1487  for (int i = 0; i < static_cast<int>(m_AntiChargeMesons.size()); ++i) m_AntiChargeMesons[i].first *= Vmod;
1488  for (int i = 0; i < static_cast<int>(m_CharmMesons.size()); ++i) m_CharmMesons[i].first *= Vmod;
1489  for (int i = 0; i < static_cast<int>(m_AntiCharmMesons.size()); ++i) m_AntiCharmMesons[i].first *= Vmod;
1490  for (int i = 0; i < static_cast<int>(m_CharmAll.size()); ++i) m_CharmAll[i].first *= Vmod;
1491  for (int i = 0; i < static_cast<int>(m_AntiCharmAll.size()); ++i) m_AntiCharmAll[i].first *= Vmod;
1492  }
1493 
1495  {
1496  fEnsemble = GCE;
1497  fModelType = PointParticle;
1498  CFOParameters = ThermalModelParameters();
1499  B = Q = S = C = 0;
1500  CanonicalB = CanonicalQ = CanonicalS = CanonicalC = true;
1501  fUsePCE = false;
1502  }
1503 
1504 } // namespace thermalfist
void ConstrainChemicalPotentials(bool resetInitialValues=true)
Constrains the chemical potentials by the conservation laws imposed.
int RandomPoisson(double mean)
Generates random integer distributed by Poisson with specified mean Uses randgenMT.
std::vector< RandomGenerators::ParticleMomentumGenerator * > m_MomentumGens
Vector of momentum generators for each particle species.
void SetVolume(double V)
Set system volume.
virtual void SetStrangenessChemicalPotential(double muS)
Set the strangeness chemical potential.
Quantum van der Waals model.
void RescaleCEMeans(double Vmod)
Rescale the precalculated GCE means.
std::vector< int > GenerateTotalsCE() const
const std::vector< double > & Densities() const
double CanonicalVolume() const
The canonical correlation volume V (fm )
virtual void SetElectricChemicalPotential(double muQ)
Set the electric chemical potential.
bool fUsePCE
Whether partial chemical equilibrium (PCE) is used.
std::vector< int > GenerateTotalsCCE() const
double VirialCoefficient(int i, int j) const
Excluded volume coefficient .
virtual void CalculateDensitiesGCE()
Calculates the particle densities in a grand-canonical ensemble.
ThermalModelInteraction InteractionModel()
The interactions present in the current HRG model.
virtual void SetBaryonChemicalPotential(double muB)
Set the baryon chemical potential.
std::vector< int > GenerateTotalsCCESubVolume(double VolumeSC) const
Ensemble fEnsemble
The statistical ensemble used.
virtual void FixParameters()
Method which actually implements ConstrainChemicalPotentials() (for backward compatibility).
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.
EventGeneratorConfiguration()
Default configuration.
double VirialCoefficient(int i, int j) const
Excluded volume coefficient .
long long PdgId() const
Particle&#39;s Particle Data Group (PDG) ID number.
Class implementing the diagonal excluded-volume model.
Class containing the particle list.
Structure containing the thermal event generator configuration.
Energy-dependent Breit-Wigner scheme (eBW)
std::vector< double > m_DensitiesIdeal
Ideal gas densities used for sampling an interacting HRG.
int B
The total values of conserved charges in the CE.
Crossterms excluded volume model.
Structure holding information about a single event in the event generator.
Definition: SimpleEvent.h:19
void SetConfiguration(ThermalParticleSystem *TPS, const EventGeneratorConfiguration &config)
Sets the event generator configuration.
Structure containing all thermal parameters of the model.
double AttractionCoefficient(int i, int j) const
QvdW mean field attraction coefficient .
std::vector< SimpleParticle > AllParticles
Vector of all particles which ever appeared in the event (including those that decay and photons/lept...
Definition: SimpleEvent.h:30
virtual double CalculateStrangenessDensity()
std::vector< int > GenerateTotalsSCESubVolume(double VolumeSC) const
std::vector< SimpleParticle > PhotonsLeptons
Vector of all decay photons/leptons.
Definition: SimpleEvent.h:33
Class implementing the quantum van der Waals HRG model.
static int RandomBesselDevroye1(double a, int nu, MTRand &rangen)
void SetQoverB(double QB)
The electric-to-baryon charge ratio to be used to constrain the electric chemical potential...
virtual void SetVirial(int, int, double)
Set the excluded volume coefficient .
virtual double FullIdealChemicalPotential(int i) const
Chemical potential entering the ideal gas expressions of particle species i.
Contains some extra mathematical functions used in the code.
std::vector< int > GenerateTotalsGCE() const
static SimpleEvent PerformDecays(const SimpleEvent &evtin, ThermalParticleSystem *TPS)
Performs decays of all unstable particles until only stable ones left.
virtual void FillChemicalPotentials()
Sets the chemical potentials of all particles.
const ThermalParticle & ParticleByPdg(long long pdg)
double logweight
Log of the event weight factor.
Definition: SimpleEvent.h:24
MTRand randgenMT
The Mersenne Twister random number generator.
Class containing all information about a particle specie.
ModelType fModelType
The type of interaction model.
std::vector< int > GenerateTotals() const
Structure holding information about a single particle in the event generator.
std::vector< double > fPCEChems
PCE chemical potentials.
const std::vector< ThermalParticle > & Particles() const
Returns the vector of all particle species.
Class implementing the crossterms excluded-volume model.
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...
virtual void SetCharmChemicalPotential(double muC)
Set the charm chemical potential.
bool UseWidth() const
Whether finite resonance widths are considered.
long long PDGID
PDG code.
std::vector< std::vector< double > > bij
The matrix of excluded volume coefficients .
virtual ~EventGeneratorBase()
Destructor.
EventGeneratorConfiguration m_Config
virtual SimpleEvent GetEvent(bool PerformDecays=true) const
Generates a single event.
double ExcludedVolume(int i) const
The excluded volume parameter of particle species i.
std::vector< SimpleParticle > Particles
Vector of all final particles in the event.
Definition: SimpleEvent.h:27
virtual void CalculateDensities()
Calculates the primordial and total (after decays) densities of all species.
std::vector< int > GenerateTotalsSCE() const
double Mass() const
Particle&#39;s mass [GeV].
std::vector< int > DecayMap
Definition: SimpleEvent.h:37
std::pair< std::vector< int >, double > SampleYields() const
Samples the primordial yields for each particle species.
Diagonal excluded volume model.
bool CanonicalB
Mixed-canonical configuration (full canonical by default)
ResonanceWidthIntegration GetResonanceWidthIntegrationType() const
Resonance width integration scheme used to treat finite resonance widths.
bool ZeroWidthEnforced() const
Whether zero-width approximation is enforced for this particle species.
void SetCanonicalVolume(double Volume)
Set the canonical correlation volume V .
ThermalModelParameters CFOParameters
The chemical freeze-out parameters.
virtual void SetAttraction(int, int, double)
Set the vdW mean field attraction coefficient .
std::vector< double > GetIdealGasDensities() const
virtual SimpleEvent SampleMomenta(const std::vector< int > &yields) const
Samples the momenta of the particles and returns the sampled list of particles as an event...
std::vector< RandomGenerators::ThermalBreitWignerGenerator * > m_BWGens
Class implementing the Ideal HRG model.
std::vector< std::vector< double > > aij
The matrix of van der Waals attraction coefficients .
ThermalModelVDW ThermalModelVDWFull
For backward compatibility.
std::vector< SimpleParticle > ManyBodyDecay(const SimpleParticle &Mother, std::vector< double > masses, std::vector< long long > pdgs)
Samples the decay products of a many-body decay.
ThermalParticle::ResonanceWidthIntegration ResonanceWidthIntegrationType() const
const ThermalModelParameters & Parameters() const
void ClearMomentumGenerators()
Clears the momentum generators for all particles.
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.
double Volume() const
System volume (fm )
std::vector< int > DecayMapFinal
Vector for each Particles element pointing to the index of the primordial resonance from which this p...
Definition: SimpleEvent.h:40
double weight
Event weight factor.
Definition: SimpleEvent.h:21
ThermalParticleSystem * TPS()
int Statistics() const
Particle&#39;s statistics.
ThermalParticle & ParticleByPDG(long long pdgid)
ThermalParticle object corresponding to particle species with a provided PDG ID.
void SetVolume(double Volume)
Sets the system volume.