Thermal-FIST  1.3
Package for hadron resonance gas model applications
ParticleDecaysMC.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 "HRGBase/xMath.h"
12 
13 namespace thermalfist {
14 
15  namespace ParticleDecaysMC {
16 
17 
18  double ThreeBodym12F2(double m12, double M, double m1, double m2, double m3) {
19  double m12k = m12 * m12;
20  return (m12k - (m1 + m2)*(m1 + m2)) * (m12k - (m1 - m2)*(m1 - m2)) * (M*M - (m12 + m3)*(m12 + m3)) * (M*M - (m12 - m3)*(m12 - m3)) / m12k;
21  }
22 
23  // Ternary search for maximum of probability density for m12
24  double TernaryThreeBodym12Maximum(double M, double m1_, double m2_, double m3_) {
25  double l = m1_ + m2_, r = M - m3_;
26  double m1 = 0., m2 = 0.;
27  m1 = l + (r - l) / 3.;
28  m2 = r - (r - l) / 3.;
29  while ((m2 - m1) > 1e-8) {
30  double f1 = ThreeBodym12F2(m1, M, m1_, m2_, m3_);
31  double f2 = ThreeBodym12F2(m2, M, m1_, m2_, m3_);
32  if (f1 < f2) {
33  l = m1;
34  }
35  else {
36  r = m2;
37  }
38  m1 = l + (r - l) / 3.;
39  m2 = r - (r - l) / 3.;
40  }
41  return sqrt(ThreeBodym12F2((m1 + m2) / 2., M, m1_, m2_, m3_));
42  }
43 
45 
46  // Random sample for m12 in a 3-body decay
47  double GetRandomThreeBodym12(double M, double m1_, double m2_, double m3_, double fm12max) {
48  while (true) {
49  threebodytot++;
50  double x0 = m1_ + m2_ + (M - m1_ - m2_ - m3_) * RandomGenerators::randgenMT.randDblExc();
51  double y0 = fm12max * RandomGenerators::randgenMT.randDblExc();
52  if (y0*y0 < ThreeBodym12F2(x0, M, m1_, m2_, m3_)) {
53  threebodysucc++;
54  return x0;
55  }
56  }
57  return 0.;
58  }
59 
60 
61 
62 
63  SimpleParticle LorentzBoost(const SimpleParticle &part, double vx, double vy, double vz) {
64  SimpleParticle ret = part;
65  double v2 = vx * vx + vy * vy + vz * vz;
66  double gamma = 1. / sqrt(1. - v2);
67  ret.p0 = gamma * part.p0 - gamma * (vx * part.px + vy * part.py + vz * part.pz);
68  ret.px = -gamma * vx * part.p0 + (1. + (gamma - 1.)*vx*vx / v2) * part.px +
69  (gamma - 1.)*vx*vy / v2 * part.py + (gamma - 1.)*vx*vz / v2 * part.pz;
70  ret.py = -gamma * vy * part.p0 + (1. + (gamma - 1.)*vy*vy / v2) * part.py +
71  (gamma - 1.)*vy*vx / v2 * part.px + (gamma - 1.)*vy*vz / v2 * part.pz;
72  ret.pz = -gamma * vz * part.p0 + (1. + (gamma - 1.)*vz*vz / v2) * part.pz +
73  (gamma - 1.)*vz*vx / v2 * part.px + (gamma - 1.)*vz*vy / v2 * part.py;
74  return ret;
75  }
76 
77  std::vector<SimpleParticle> TwoBodyDecay(const SimpleParticle & Mother, double m1, long long pdg1, double m2, long long pdg2) {
78  std::vector<SimpleParticle> ret(0);
79  ret.push_back(Mother);
80  ret.push_back(Mother);
81  ret[0].PDGID = pdg1;
82  ret[0].m = m1;
83  ret[1].PDGID = pdg2;
84  ret[1].m = m2;
85 
86  double vx = Mother.px / Mother.p0;
87  double vy = Mother.py / Mother.p0;
88  double vz = Mother.pz / Mother.p0;
89  SimpleParticle Mo = LorentzBoost(Mother, vx, vy, vz);
90  double ten1 = (Mo.m*Mo.m - m2 * m2 + m1 * m1) / 2. / Mo.m;
91  double tp = sqrt(ten1*ten1 - m1 * m1);
92  double tphi = 2. * xMath::Pi() * RandomGenerators::randgenMT.rand();
93  double cthe = 2. * RandomGenerators::randgenMT.rand() - 1.;
94  double sthe = sqrt(1. - cthe * cthe);
95  ret[0].px = tp * cos(tphi) * sthe;
96  ret[0].py = tp * sin(tphi) * sthe;
97  ret[0].pz = tp * cthe;
98  ret[0].p0 = ten1;
99  ret[1].px = -ret[0].px;
100  ret[1].py = -ret[0].py;
101  ret[1].pz = -ret[0].pz;
102  ret[1].p0 = sqrt(m2*m2 + ret[1].px*ret[1].px + ret[1].py*ret[1].py + ret[1].pz*ret[1].pz);
103 
104  ret[0] = LorentzBoost(ret[0], -vx, -vy, -vz);
105  ret[1] = LorentzBoost(ret[1], -vx, -vy, -vz);
106 
107  ret[0].MotherPDGID = Mother.PDGID;
108  ret[1].MotherPDGID = Mother.PDGID;
109 
110  ret[0].epoch = Mother.epoch + 1;
111  ret[1].epoch = Mother.epoch + 1;
112 
113  for (size_t i = 0; i < ret.size(); ++i)
114  if (ret[i].px != ret[i].px) {
115  printf("**WARNING** Issue in a two-body decay!\n");
116  }
117 
118  return ret;
119  }
120 
121  std::vector<SimpleParticle> ManyBodyDecay(const SimpleParticle & Mother, std::vector<double> masses, std::vector<long long> pdgs) {
122  std::vector<SimpleParticle> ret(0);
123  if (masses.size() < 1) return ret;
124 
125  // If only one daughter listed, assume a radiative decay A -> B + gamma
126  if (masses.size() == 1)
127  {
128  masses.push_back(0.);
129  pdgs.push_back(22);
130  }
131 
132  if (masses.size() > 3) {
133  ShuffleDecayProducts(masses, pdgs);
134  }
135 
136  SimpleParticle Mother2 = Mother;
137  // Mass validation
138  double tmasssum = 0.;
139  for (size_t i = 0; i < masses.size(); ++i) tmasssum += masses[i];
140  if (Mother2.m < tmasssum) Mother2.m = tmasssum + 1e-7;
141 
142  if (masses.size() == 2) return TwoBodyDecay(Mother2, masses[0], pdgs[0], masses[1], pdgs[1]);
143  double tmin = 0.;
144  for (size_t i = 0; i < masses.size() - 1; ++i) tmin += masses[i];
145  double tmax = Mother2.m - masses[masses.size() - 1];
146  double mijk = 0.;
147  if (masses.size() == 3) {
148  mijk = GetRandomThreeBodym12(Mother2.m, masses[0], masses[1], masses[2], 1.01*TernaryThreeBodym12Maximum(Mother2.m, masses[0], masses[1], masses[2]));
149  }
150  else // More than 3 body decay kinematics are only approximate!
151  {
152  mijk = tmin + (tmax - tmin) * RandomGenerators::randgenMT.rand();
153  }
154  std::vector<SimpleParticle> ret1 = TwoBodyDecay(Mother2, mijk, 11111, masses[masses.size() - 1], pdgs[pdgs.size() - 1]);
155  ret.push_back(ret1[1]);
156  masses.resize(masses.size() - 1);
157  pdgs.resize(pdgs.size() - 1);
158  ret1 = ManyBodyDecay(ret1[0], masses, pdgs);
159  for (size_t i = 0; i < ret1.size(); ++i)
160  ret.push_back(ret1[i]);
161 
162  for (size_t i = 0; i < ret.size(); ++i) {
163  ret[i].MotherPDGID = Mother.PDGID;
164  ret[i].epoch = Mother.epoch + 1;
165  }
166 
167 #ifdef DEBUGDECAYS
168  for (int i = 0; i < ret.size(); ++i)
169  if (ret[i].px != ret[i].px) std::cout << "**WARNING** NaN in NBodyDecay procedure output!\n";
170 #endif
171 
172  return ret;
173  }
174 
175  void ShuffleDecayProducts(std::vector<double>& masses, std::vector<long long>& pdgs)
176  {
177  if (masses.size() != pdgs.size()) {
178  std::cout << "**WARNING** ShuffleDecayProducts(): size of masses does not match size of pdgs!\n";
179  return;
180  }
181  int N = masses.size();
182  for (int i = N - 1; i >= 1; --i) {
183  int j = RandomGenerators::randgenMT.randInt() % (i + 1);
184  std::swap(masses[j], masses[i]);
185  std::swap(pdgs[j], pdgs[i]);
186  }
187  }
188 
189  }
190 
191 } // namespace thermalfist
int threebodysucc
Used for debugging the succes rate in the rejection sampling of .
double TernaryThreeBodym12Maximum(double M, double m1, double m2, double m3)
Determines the maximum of the probability density function used in a three-body decay.
double Pi()
Pi constant.
Definition: xMath.h:24
std::vector< SimpleParticle > TwoBodyDecay(const SimpleParticle &Mother, double m1, long long pdg1, double m2, long long pdg2)
Samples the decay products of a two-body decay.
double GetRandomThreeBodym12(double M, double m1, double m2, double m3, double fm12max)
Sample the invariant mass of the leading two daughter particles in a three-body decay.
Contains some extra mathematical functions used in the code.
double m
Mass (in GeV)
MTRand randgenMT
The Mersenne Twister random number generator.
Structure holding information about a single particle in the event generator.
long long PDGID
PDG code.
double ThreeBodym12F2(double m12, double M, double m1, double m2, double m3)
Square of the probability density function used in a three-body decay (unnormalized) ...
void ShuffleDecayProducts(std::vector< double > &masses, std::vector< long long > &pdgs)
Shuffles the decay products.
double p0
Energy (in GeV)
double pz
3-momentum components (in GeV)
int epoch
0 - primary particle, 1 - after decay of primary particles, 2 - after a casacde of two decays and so ...
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.
SimpleParticle LorentzBoost(const SimpleParticle &part, double vx, double vy, double vz)
Lorentz boost of the 4-momentum of a particle.
The main namespace where all classes and functions of the Thermal-FIST library reside.