ROOTPWA
nBodyPhaseSpaceGen.h
Go to the documentation of this file.
1 
2 //
3 // Copyright 2010
4 //
5 // This file is part of rootpwa
6 //
7 // rootpwa 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 // rootpwa 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 rootpwa. If not, see <http://www.gnu.org/licenses/>.
19 //
21 //-------------------------------------------------------------------------
22 // File and Version Information:
23 // $Rev:: $: revision of last commit
24 // $Author:: $: author of last commit
25 // $Date:: $: date of last commit
26 //
27 // Description:
28 //
29 // calculates n-body phase space (constant matrix element) using various algorithms
30 //
31 // the n-body decay is split up into (n - 2) successive 2-body decays
32 // each 2-body decay is considered in its own center-of-mass frame thereby
33 // separating the mass from the (trivial) angular dependence
34 //
35 // the event is boosted into the same frame in which the n-body system is
36 // given
37 //
38 // !Note! some of the implemented weights can be applied only in
39 // certain cases; if you are not sure, use the "S.U. Chung"
40 // weight
41 //
42 // !Note! in case this class is used to calculate the absolute value
43 // of the phase space integral, be sure to use the "S.U. Chung"
44 // weight; if in the integral the phase space is weighted with
45 // some amplitude with angular depdendence, the integral has to
46 // be divided by the correct power of (2) pi (the "S.U. Chung"
47 // already contains a factor (4 pi)^(n - 1) from (trivial)
48 // integration over all angles)
49 //
50 // based on:
51 // GENBOD (CERNLIB W515), see F. James, "Monte Carlo Phase Space", CERN 68-15 (1968)
52 // NUPHAZ, see M. M. Block, "Monte Carlo phase space evaluation", Comp. Phys. Commun. 69, 459 (1992)
53 // S. U. Chung, "Spin Formalism", CERN Yellow Report
54 // S. U. Chung et. al., "Diffractive Dissociation for COMPASS"
55 //
56 // index convention:
57 // - all vectors have the same size (= number of decay daughters)
58 // - index i corresponds to the respective value in the (i + 1)-body system: effective mass M, break-up momentum, angles
59 // - thus some vector elements are not used like breakupMom[0], theta[0], phi[0], ...
60 // this overhead is negligible compared to the ease of notation
61 //
62 // the following graph illustrates how the n-body decay is decomposed into a sequence of two-body decays
63 //
64 // n-body ... 3-body 2-body single daughter
65 //
66 // m[n - 1] m[2] m[1]
67 // ^ ^ ^
68 // | | |
69 // | | |
70 // M[n - 1] --> ... --> M[2] --> M[1] --> M [0] = m[0]
71 // theta[n - 1] ... theta[2] theta[1] theta[0] = 0 (not used)
72 // phi [n - 1] ... phi [2] phi [1] phi [0] = 0 (not used)
73 // mSum [n - 1] ... mSum [2] mSum [1] mSum [0] = m[0]
74 // = sum_0^(n - 1) m[i] = m[2] + m[1] + m[0] = m[1] + m[0]
75 // breakUpMom[n - 1] ... breakUpMom[2] breakUpMom[1] breakUpMom[0] = 0 (not used)
76 // = q(M[n - 1], m[n - 1], M[n - 2]) = q(M[2], m[2], M[1]) = q(M[1], m[1], m[0])
77 //
78 //
79 // Author List:
80 // Boris Grube TUM (original author)
81 //
82 //
83 //-------------------------------------------------------------------------
84 
85 
86 #ifndef NBODYPHASESPACEGEN_HH
87 #define NBODYPHASESPACEGEN_HH
88 
89 
90 #include <iostream>
91 #include <vector>
92 
93 #include "TLorentzVector.h"
94 #include "TRandom3.h"
95 
96 #ifndef __CINT__
97 #include "reportingUtils.hpp"
98 #include "mathUtils.hpp"
99 #endif
100 
101 
102 #define DEBUG 0
103 
104 
105 namespace rpwa {
106 
107 
109 
110  public:
111 
113  virtual ~nBodyPhaseSpaceGen();
114 
115  //----------------------------------------------------------------------------
116  // generator setup
118  bool setDecay(const std::vector<double>& daughterMasses); // daughter particle masses
119  bool setDecay(const unsigned int nmbOfDaughters, // number of daughter particles
120  const double* daughterMasses); // array of daughter particle masses
121 
122  void setSeed(const unsigned int seed) { _rnd.setSeed(seed); }
123  unsigned int seed () { return _rnd.seed(); }
124  double random () { return _rnd.pick(); }
125 
126 
127  void setProposalBW(double mass, double width) { _isoBWMass=mass;_isoBWWidth=width;}
128 
129  // high-level generator interface
131  double generateDecay (const TLorentzVector& nBody); // Lorentz vector of n-body system in lab frame
134  bool generateDecayAccepted(const TLorentzVector& nBody, // Lorentz vector of n-body system in lab frame
135  const double maxWeight = 0); // if positive, given value is used as maximum weight, otherwise _maxWeight
136 
137 
138  //----------------------------------------------------------------------------
139  // low-level generator interface
141  void pickMasses(const double nBodyMass); // total energy of n-body system in its RF
142 
145  double calcWeight();
146 
148  inline void pickAngles();
149 
152  void calcEventKinematics(const TLorentzVector& nBody); // Lorentz vector of n-body system in lab frame
153 
154  enum kinematicsTypeEnum {BLOCK = 1, // method for calculation of event kinematics used in nuphaz (faster)
155  RAUBOLD_LYNCH = 2}; // method for calculation of event kinematics used in genbod
158 
159 
160  void setVerbose(bool flag){_verbose=flag;}
161 
162  //----------------------------------------------------------------------------
163  // weight routines
164  enum weightTypeEnum {S_U_CHUNG = 1, // gives physically correct mass dependence
165  NUPHAZ = 2, // weight used in nuphaz
166  GENBOD = 3, // default weight used in genbod (gives wrong mass dependence)
167  FLAT = 4, // uniform mass distribution; warning: produces distorted angular distribution
168  IMPORTANCE = 5}; // like S_U_CHUNG but with importance sampling in (n-1) fs particle state (single breitwigner)
170 
171  weightTypeEnum weightType () const { return _weightType; }
172 
173 
174  void setMaxWeight (const double maxWeight) { _maxWeight = maxWeight; }
175  double maxWeight () const { return _maxWeight; }
176  double normalization () const { return _norm; }
177  double eventWeight () const { return _weight; }
178  double maxWeightObserved () const { return _maxWeightObserved; }
180 
182  double estimateMaxWeight(const double nBodyMass, // sic!
183  const unsigned int nmbOfIterations = 10000); // number of generated events
184 
188  inline bool eventAccepted(const double maxWeight = 0);
189 
190  //----------------------------------------------------------------------------
191  // trivial accessors
192  const TLorentzVector& daughter (const int index) const { return _daughters[index]; }
193  const std::vector<TLorentzVector>& daughters () const { return _daughters; }
194  unsigned int nmbOfDaughters () const { return _n; }
195  double daughterMass (const int index) const { return _m[index]; }
196  double intermediateMass(const int index) const { return _M[index]; }
197  double breakupMom (const int index) const { return _breakupMom[index]; }
198  double cosTheta (const int index) const { return _cosTheta[index]; }
199  double phi (const int index) const { return _phi[index]; }
200 
201 
202 
203  double impWeight() const {return _impweight;}
204  std::ostream& print(std::ostream& out = std::cout) const;
205  friend std::ostream& operator << (std::ostream& out,
206  const nBodyPhaseSpaceGen& gen) { return gen.print(out); }
207 
208  private:
209 
212  static inline double F(const double x,
213  const double y);
214 
215  // external parameters
216  std::vector<double> _m;
217 
218 
219  // internal variables
220  unsigned int _n;
221  std::vector<double> _M;
222  std::vector<double> _cosTheta;
223  std::vector<double> _phi;
224  std::vector<double> _mSum;
225  std::vector<double> _breakupMom;
226  std::vector<TLorentzVector> _daughters;
228  double _norm;
229  double _weight;
230  double _impweight;
232  double _maxWeight;
234 
235 
236 
237  bool _verbose;
238 
239  double _isoBWMass;
240  double _isoBWWidth;
241 
242 
243  // wrapper class for random number generator
244  class rndGen {
245 
246 
247  public:
248 
249  rndGen() { }
250  rndGen(const unsigned int seed) { setSeed(seed); }
251  virtual ~rndGen() { }
252 
253  unsigned int seed () { return _rndGen.GetSeed(); }
254  void setSeed(unsigned int seed) { _rndGen.SetSeed(seed); }
255  double pick () { return _rndGen.Rndm(); }
256 
257  private:
258 
259  TRandom3 _rndGen;
260 
261  };
262 
264 
265  ClassDef(nBodyPhaseSpaceGen,1)
266 
267  };
268 
269 } // namespace rpwa
270 
271 
272 inline
273 void
275 {
276  for (unsigned int i = 1; i < _n; ++i) { // loop over 2- to n-bodies
277  _cosTheta[i] = 2 * random() - 1; // range [-1, 1]
278  _phi[i] = rpwa::twoPi * random(); // range [ 0, 2 pi]
279  }
280 }
281 
282 
283 inline
284 bool
285 rpwa::nBodyPhaseSpaceGen::eventAccepted(const double maxWeight) // if maxWeight > 0, given value is used as maximum weight, otherwise _maxWeight
286 {
287  if (_weightType == FLAT)
288  return true; // no weighting
289  const double max = (maxWeight <= 0) ? _maxWeight : maxWeight;
290  if (max <= 0) {
291  printErr << "maximum weight = " << max << " does not make sense. rejecting event." << std::endl;
292  return false;
293  }
294  if ((_weight / max) > random())
295  return true;
296  return false;
297 }
298 
299 
300 inline
301 double
303  const double y)
304 {
305  const double val = 1 + (x - y) * (x - y) - 2 * (x + y);
306  if (val < 0)
307  return 0;
308  else
309  return sqrt(val);
310 }
311 
312 
313 #endif // NBODYPHASESPACEGEN_H