]> git.uio.no Git - u/mrichter/AliRoot.git/blame - STARLIGHT/starlight/src/nBodyPhaseSpaceGen.cpp
Update to trunk of hepforge
[u/mrichter/AliRoot.git] / STARLIGHT / starlight / src / nBodyPhaseSpaceGen.cpp
CommitLineData
da32329d
AM
1///////////////////////////////////////////////////////////////////////////
2//
3// Copyright 2010
4//
5// This file is part of starlight.
6//
7// starlight is free software: you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation, either version 3 of the License, or
10// (at your option) any later version.
11//
12// starlight is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with starlight. If not, see <http://www.gnu.org/licenses/>.
19//
20///////////////////////////////////////////////////////////////////////////
21//
22// File and Version Information:
23// $Rev:: 159 $: revision of last commit
24// $Author:: odjuvsla $: author of last commit
25// $Date:: 2013-10-06 16:17:58 +0200 #$: date of last commit
26//
27// Description:
28// see nBodyPhaseSpaceGen.h
29//
30//
31///////////////////////////////////////////////////////////////////////////
32
33
34#include <algorithm>
35
36#include "nBodyPhaseSpaceGen.h"
37
38
39using namespace std;
40using namespace starlightConstants;
41
42
43nBodyPhaseSpaceGen::nBodyPhaseSpaceGen()
44 : _n (0),
45 _norm (0),
46 _weight (0),
47 _maxWeightObserved(0),
48 _maxWeight (0)
49{ }
50
51
52nBodyPhaseSpaceGen::~nBodyPhaseSpaceGen()
53{ }
54
55
56// sets decay constants and prepares internal variables
57bool
58nBodyPhaseSpaceGen::setDecay(const vector<double>& daughterMasses) // array of daughter particle masses
59{
60 _n = daughterMasses.size();
61 if (_n < 2) {
62 printWarn << "number of daughters = " << _n << " does not make sense." << endl;
63 return false;
64 }
65 // copy daughter masses
66 _m.clear();
67 _m = daughterMasses;
68 // prepare effective mass vector
69 _M.clear();
70 _M.resize(_n, 0);
71 _M[0] = _m[0];
72 // prepare angle vectors
73 _cosTheta.clear();
74 _cosTheta.resize(_n, 0);
75 _phi.clear();
76 _phi.resize(_n, 0);
77 // calculate daughter mass sums
78 _mSum.clear();
79 _mSum.resize(_n, 0);
80 _mSum[0] = _m[0];
81 for (unsigned int i = 1; i < _n; ++i)
82 _mSum[i] = _mSum[i - 1] + _m[i];
83 // prepare breakup momentum vector
84 _breakupMom.clear();
85 _breakupMom.resize(_n, 0);
86 // prepare vector for daughter Lorentz vectors
87 _daughters.clear();
88 _daughters.resize(_n, lorentzVector(0, 0, 0, 0));
89 // calculate normalization
90 _norm = 1 / (2 * pow(twoPi, 2 * (int)_n - 3) * factorial(_n - 2));
91 resetMaxWeightObserved();
92 return true;
93}
94
95
96// set decay constants and prepare internal variables
97bool
45d54d9a 98nBodyPhaseSpaceGen::setDecay(const unsigned int nmbOfDaughters, // number of daughter particles
99 const double* daughterMasses) // array of daughter particle masses
da32329d
AM
100{
101 vector <double> m;
45d54d9a 102 m.resize(nmbOfDaughters, 0);
103 for (unsigned int i = 0; i < nmbOfDaughters; ++i)
da32329d
AM
104 m[i] = daughterMasses[i];
105 return setDecay(m);
106}
107
108
109// generates event with certain n-body mass and momentum and returns event weigth
110// general purpose function
111double
112nBodyPhaseSpaceGen::generateDecay(const lorentzVector& nBody) // Lorentz vector of n-body system in lab frame
113{
114 const double nBodyMass = nBody.M();
115 if (_n < 2) {
116 printWarn << "number of daughter particles = " << _n << " is smaller than 2. "
117 << "weight is set to 0." << endl;
118 _weight = 0;
119 } else if (nBodyMass < _mSum[_n - 1]) {
120 printWarn << "n-body mass = " << nBodyMass << " is smaller than sum of daughter masses = "
121 << _mSum[_n - 1] << ". weight is set to 0." << endl;
122 _weight = 0;
123 } else {
124 pickMasses(nBodyMass);
125 calcWeight();
126 pickAngles();
127 calcEventKinematics(nBody);
128 }
129 return _weight;
130}
131
132
133// generates full event with certain n-body mass and momentum only, when event is accepted (return value = true)
134// this function is more efficient, if only weighted evens are needed
135bool
45d54d9a 136nBodyPhaseSpaceGen::generateDecayAccepted(const lorentzVector& nBody, // Lorentz vector of n-body system in lab frame
137 const double maxWeight) // if positive, given value is used as maximum weight, otherwise _maxWeight
da32329d
AM
138{
139 const double nBodyMass = nBody.M();
140 if (_n < 2) {
141 printWarn << "number of daughter particles = " << _n << " is smaller than 2. "
142 << "no event generated." << endl;
143 return false;
144 } else if (nBodyMass < _mSum[_n - 1]) {
145 printWarn << "n-body mass = " << nBodyMass << " is smaller than sum of daughter masses = "
146 << _mSum[_n - 1] << ". no event generated." << endl;
147 return false;
148 }
149 pickMasses(nBodyMass);
150 calcWeight();
45d54d9a 151 if (!eventAccepted(maxWeight))
da32329d
AM
152 return false;
153 pickAngles();
154 calcEventKinematics(nBody);
155 return true;
156}
157
158
159// randomly choses the (n - 2) effective masses of the respective (i + 1)-body systems
160void
161nBodyPhaseSpaceGen::pickMasses(const double nBodyMass) // total energy of the system in its RF
162{
163 _M[_n - 1] = nBodyMass;
164 // create vector of sorted random values
165 vector<double> r(_n - 2, 0); // (n - 2) values needed for 2- through (n - 1)-body systems
166 for (unsigned int i = 0; i < (_n - 2); ++i)
167 r[i] = random();
168 sort(r.begin(), r.end());
169 // set effective masses of (intermediate) two-body decays
170 const double massInterval = nBodyMass - _mSum[_n - 1]; // kinematically allowed mass interval
171 for (unsigned int i = 1; i < (_n - 1); ++i) // loop over intermediate 2- to (n - 1)-bodies
172 _M[i] = _mSum[i] + r[i - 1] * massInterval; // _mSum[i] is minimum effective mass
173}
174
175
176// computes event weight (= integrand value) and breakup momenta
177// uses vector of intermediate two-body masses prepared by pickMasses()
178double
179nBodyPhaseSpaceGen::calcWeight()
180{
181 for (unsigned int i = 1; i < _n; ++i) // loop over 2- to n-bodies
182 _breakupMom[i] = breakupMomentum(_M[i], _M[i - 1], _m[i]);
183 double momProd = 1; // product of breakup momenta
184 for (unsigned int i = 1; i < _n; ++i) // loop over 2- to n-bodies
185 momProd *= _breakupMom[i];
186 const double massInterval = _M[_n - 1] - _mSum[_n - 1]; // kinematically allowed mass interval
187 _weight = _norm * pow(massInterval, (int)_n - 2) * momProd / _M[_n - 1];
188 if (_weight > _maxWeightObserved)
189 _maxWeightObserved = _weight;
190 if (std::isnan(_weight))
191 printWarn << "weight = " << _weight << endl;
192 return _weight;
193}
194
195
196// calculates complete event from the effective masses of the (i + 1)-body
197// systems, the Lorentz vector of the decaying system, and the decay angles
198// uses the break-up momenta calculated by calcWeight()
199void
200nBodyPhaseSpaceGen::calcEventKinematics(const lorentzVector& nBody) // Lorentz vector of n-body system in lab frame
201{
202 // build event starting in n-body RF going down to 2-body RF
203 // is more efficicient than Raubold-Lynch method, since it requitres only one rotation and boost per daughter
204 lorentzVector P = nBody; // Lorentz of (i + 1)-body system in lab frame
205 for (unsigned int i = _n - 1; i >= 1; --i) { // loop from n-body down to 2-body
206 // construct Lorentz vector of daughter _m[i] in (i + 1)-body RF
45d54d9a 207 const double sinTheta = sqrt(1 - _cosTheta[i] * _cosTheta[i]);
208 const double pT = _breakupMom[i] * sinTheta;
209 lorentzVector& daughter = _daughters[i];
210 daughter.SetPxPyPzE(pT * cos(_phi[i]),
211 pT * sin(_phi[i]),
212 _breakupMom[i] * _cosTheta[i],
213 sqrt(_m[i] * _m[i] + _breakupMom[i] * _breakupMom[i]));
da32329d 214 // boost daughter into lab frame
45d54d9a 215 daughter.Boost(P.BoostVector());
da32329d 216 // calculate Lorentz vector of i-body system in lab frame
45d54d9a 217 P -= daughter;
da32329d
AM
218 }
219 // set last daughter
220 _daughters[0] = P;
221}
222
223
224// calculates maximum weight for given n-body mass
225double
226nBodyPhaseSpaceGen::estimateMaxWeight(const double nBodyMass, // sic!
227 const unsigned int nmbOfIterations) // number of generated events
228{
45d54d9a 229 double maxWeight = 0;
da32329d
AM
230 for (unsigned int i = 0; i < nmbOfIterations; ++i) {
231 pickMasses(nBodyMass);
232 calcWeight();
45d54d9a 233 maxWeight = max(_weight, maxWeight);
da32329d 234 }
45d54d9a 235 return maxWeight;
da32329d
AM
236}
237
238
239ostream&
240nBodyPhaseSpaceGen::print(ostream& out) const
241{
242 out << "nBodyPhaseSpaceGen parameters:" << endl
243 << " number of daughter particles ............... " << _n << endl
244 << " masses of the daughter particles ........... " << _m << endl
245 << " sums of daughter particle masses ........... " << _mSum << endl
246 << " effective masses of (i + 1)-body systems ... " << _M << endl
247 << " cos(polar angle) in (i + 1)-body systems ... " << _cosTheta << endl
248 << " azimuth in (i + 1)-body systems ............ " << _phi << endl
249 << " breakup momenta in (i + 1)-body systems .... " << _breakupMom << endl
250 << " normalization value ........................ " << _norm << endl
251 << " weight of generated event .................. " << _weight << endl
252 << " maximum weight used in hit-miss MC ......... " << _maxWeight << endl
253 << " maximum weight since instantiation ......... " << _maxWeightObserved << endl
254 << " daughter four-momenta:" << endl;
255 for (unsigned int i = 0; i < _n; ++i)
256 out << " daughter " << i << ": " << _daughters[i] << endl;
257 return out;
258}