File indexing completed on 2024-09-27 07:03:41
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #include <algorithm>
0035
0036 #include "nBodyPhaseSpaceGen.h"
0037
0038
0039 using namespace std;
0040 using namespace starlightConstants;
0041
0042
0043 nBodyPhaseSpaceGen::nBodyPhaseSpaceGen(const randomGenerator& randy)
0044 : _n (0),
0045 _norm (0),
0046 _weight (0),
0047 _maxWeightObserved(0),
0048 _maxWeight (0),
0049 _randy (randy)
0050 { }
0051
0052
0053 nBodyPhaseSpaceGen::~nBodyPhaseSpaceGen()
0054 { }
0055
0056
0057
0058 bool
0059 nBodyPhaseSpaceGen::setDecay(const vector<double>& daughterMasses)
0060 {
0061 _n = daughterMasses.size();
0062 if (_n < 2) {
0063 printWarn << "number of daughters = " << _n << " does not make sense." << endl;
0064 return false;
0065 }
0066
0067 _m.clear();
0068 _m = daughterMasses;
0069
0070 _M.clear();
0071 _M.resize(_n, 0);
0072 _M[0] = _m[0];
0073
0074 _cosTheta.clear();
0075 _cosTheta.resize(_n, 0);
0076 _phi.clear();
0077 _phi.resize(_n, 0);
0078
0079 _mSum.clear();
0080 _mSum.resize(_n, 0);
0081 _mSum[0] = _m[0];
0082 for (unsigned int i = 1; i < _n; ++i)
0083 _mSum[i] = _mSum[i - 1] + _m[i];
0084
0085 _breakupMom.clear();
0086 _breakupMom.resize(_n, 0);
0087
0088 _daughters.clear();
0089 _daughters.resize(_n, lorentzVector(0, 0, 0, 0));
0090
0091 _norm = 1 / (2 * pow(twoPi, 2 * (int)_n - 3) * factorial(_n - 2));
0092 resetMaxWeightObserved();
0093 return true;
0094 }
0095
0096
0097
0098 bool
0099 nBodyPhaseSpaceGen::setDecay(const unsigned int nmbOfDaughters,
0100 const double* daughterMasses)
0101 {
0102 vector <double> m;
0103 m.resize(nmbOfDaughters, 0);
0104 for (unsigned int i = 0; i < nmbOfDaughters; ++i)
0105 m[i] = daughterMasses[i];
0106 return setDecay(m);
0107 }
0108
0109
0110
0111
0112 double
0113 nBodyPhaseSpaceGen::generateDecay(const lorentzVector& nBody)
0114 {
0115 const double nBodyMass = nBody.M();
0116 if (_n < 2) {
0117 printWarn << "number of daughter particles = " << _n << " is smaller than 2. "
0118 << "weight is set to 0." << endl;
0119 _weight = 0;
0120 } else if (nBodyMass < _mSum[_n - 1]) {
0121 printWarn << "n-body mass = " << nBodyMass << " is smaller than sum of daughter masses = "
0122 << _mSum[_n - 1] << ". weight is set to 0." << endl;
0123 _weight = 0;
0124 } else {
0125 pickMasses(nBodyMass);
0126 calcWeight();
0127 pickAngles();
0128 calcEventKinematics(nBody);
0129 }
0130 return _weight;
0131 }
0132
0133
0134
0135
0136 bool
0137 nBodyPhaseSpaceGen::generateDecayAccepted(const lorentzVector& nBody,
0138 const double maxWeight)
0139 {
0140 const double nBodyMass = nBody.M();
0141 if (_n < 2) {
0142 printWarn << "number of daughter particles = " << _n << " is smaller than 2. "
0143 << "no event generated." << endl;
0144 return false;
0145 } else if (nBodyMass < _mSum[_n - 1]) {
0146 printWarn << "n-body mass = " << nBodyMass << " is smaller than sum of daughter masses = "
0147 << _mSum[_n - 1] << ". no event generated." << endl;
0148 return false;
0149 }
0150 pickMasses(nBodyMass);
0151 calcWeight();
0152 if (!eventAccepted(maxWeight))
0153 return false;
0154 pickAngles();
0155 calcEventKinematics(nBody);
0156 return true;
0157 }
0158
0159
0160
0161 void
0162 nBodyPhaseSpaceGen::pickMasses(const double nBodyMass)
0163 {
0164 _M[_n - 1] = nBodyMass;
0165
0166 vector<double> r(_n - 2, 0);
0167 for (unsigned int i = 0; i < (_n - 2); ++i)
0168 r[i] = random();
0169 sort(r.begin(), r.end());
0170
0171 const double massInterval = nBodyMass - _mSum[_n - 1];
0172 for (unsigned int i = 1; i < (_n - 1); ++i)
0173 _M[i] = _mSum[i] + r[i - 1] * massInterval;
0174 }
0175
0176
0177
0178
0179 double
0180 nBodyPhaseSpaceGen::calcWeight()
0181 {
0182 for (unsigned int i = 1; i < _n; ++i)
0183 _breakupMom[i] = breakupMomentum(_M[i], _M[i - 1], _m[i]);
0184 double momProd = 1;
0185 for (unsigned int i = 1; i < _n; ++i)
0186 momProd *= _breakupMom[i];
0187 const double massInterval = _M[_n - 1] - _mSum[_n - 1];
0188 _weight = _norm * pow(massInterval, (int)_n - 2) * momProd / _M[_n - 1];
0189 if (_weight > _maxWeightObserved)
0190 _maxWeightObserved = _weight;
0191 if (std::isnan(_weight))
0192 printWarn << "weight = " << _weight << endl;
0193 return _weight;
0194 }
0195
0196
0197
0198
0199
0200 void
0201 nBodyPhaseSpaceGen::calcEventKinematics(const lorentzVector& nBody)
0202 {
0203
0204
0205 lorentzVector P = nBody;
0206 for (unsigned int i = _n - 1; i >= 1; --i) {
0207
0208 const double sinTheta = sqrt(1 - _cosTheta[i] * _cosTheta[i]);
0209 const double pT = _breakupMom[i] * sinTheta;
0210 lorentzVector& daughter = _daughters[i];
0211 daughter.SetPxPyPzE(pT * cos(_phi[i]),
0212 pT * sin(_phi[i]),
0213 _breakupMom[i] * _cosTheta[i],
0214 sqrt(_m[i] * _m[i] + _breakupMom[i] * _breakupMom[i]));
0215
0216 daughter.Boost(P.BoostVector());
0217
0218 P -= daughter;
0219 }
0220
0221 _daughters[0] = P;
0222 }
0223
0224
0225
0226 double
0227 nBodyPhaseSpaceGen::estimateMaxWeight(const double nBodyMass,
0228 const unsigned int nmbOfIterations)
0229 {
0230 double maxWeight = 0;
0231 for (unsigned int i = 0; i < nmbOfIterations; ++i) {
0232 pickMasses(nBodyMass);
0233 calcWeight();
0234 maxWeight = max(_weight, maxWeight);
0235 }
0236 return maxWeight;
0237 }
0238
0239
0240 ostream&
0241 nBodyPhaseSpaceGen::print(ostream& out) const
0242 {
0243 out << "nBodyPhaseSpaceGen parameters:" << endl
0244 << " number of daughter particles ............... " << _n << endl
0245 << " masses of the daughter particles ........... " << _m << endl
0246 << " sums of daughter particle masses ........... " << _mSum << endl
0247 << " effective masses of (i + 1)-body systems ... " << _M << endl
0248 << " cos(polar angle) in (i + 1)-body systems ... " << _cosTheta << endl
0249 << " azimuth in (i + 1)-body systems ............ " << _phi << endl
0250 << " breakup momenta in (i + 1)-body systems .... " << _breakupMom << endl
0251 << " normalization value ........................ " << _norm << endl
0252 << " weight of generated event .................. " << _weight << endl
0253 << " maximum weight used in hit-miss MC ......... " << _maxWeight << endl
0254 << " maximum weight since instantiation ......... " << _maxWeightObserved << endl
0255 << " daughter four-momenta:" << endl;
0256 for (unsigned int i = 0; i < _n; ++i)
0257 out << " daughter " << i << ": " << _daughters[i] << endl;
0258 return out;
0259 }