evtgen is hosted by Hepforge, IPPP Durham
EvtGen  2.0.0
Monte Carlo generator of particle decays, in particular the weak decays of heavy flavour particles such as B mesons.
EvtFourBodyPhsp.cpp
Go to the documentation of this file.
1 
2 /***********************************************************************
3 * Copyright 1998-2020 CERN for the benefit of the EvtGen authors *
4 * *
5 * This file is part of EvtGen. *
6 * *
7 * EvtGen 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 * EvtGen 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 EvtGen. If not, see <https://www.gnu.org/licenses/>. *
19 ***********************************************************************/
20 
21 #include <cmath>
22 
23 #include "EvtGenBase/EvtKine.hh"
24 #include "EvtGenBase/EvtPDL.hh"
26 #include "EvtGenBase/EvtRandom.hh"
27 #include "EvtGenBase/EvtReport.hh"
29 
31 {
32  return "FOURBODYPHSP";
33 }
34 
36 {
37  return new EvtFourBodyPhsp;
38 }
39 
40 std::array<double, 4> EvtFourBodyPhsp::phspFactor(
41  const double mM, const double m12, const double m34,
42  std::array<double, 4>& daughters ) const
43 {
44  std::array<double, 4> result;
45  result[1] = twoBodyMomentum( mM, m12, m34 );
46  result[2] = twoBodyMomentum( m12, daughters[0], daughters[1] );
47  result[3] = twoBodyMomentum( m34, daughters[2], daughters[3] );
48  result[0] = result[1] * result[2] * result[3];
49 
50  return result;
51 }
52 
54 {
55  // Check that we have right number of daughters
56  checkNDaug( 4 );
57 
58  // Check whether mother is quasi-stable
59  auto parent = getParentId();
60  double width = EvtPDL::getWidth( parent );
61  if ( width > 1e-6 ) {
62  m_stableMother = false;
63  }
64 
65  // Check whether all daughters are stable
66  for ( int i = 0; i < 4; ++i ) {
67  auto daughter = getDaug( i );
68  width = EvtPDL::getWidth( daughter );
69  if ( width > 1e-6 ) {
70  m_stableDaughters = false;
71  m_daughterMasses[i] = EvtPDL::getMinMass( daughter );
72  } else {
73  m_daughterMasses[i] = EvtPDL::getMass( daughter );
74  }
75  }
76 
77  // check correct number of arguments
78  checkNArg( 0, 2, 4 );
79  double mass1 = m_daughterMasses[0];
80  double mass2 = m_daughterMasses[1];
81  double mass3 = m_daughterMasses[2];
82  double mass4 = m_daughterMasses[3];
83  double mMother = EvtPDL::getMaxMass( parent );
84  if ( getNArg() > 2 ) {
85  m_m12Min = getArg( 0 );
86  m_m12Max = getArg( 1 );
87  m_m34Min = getArg( 2 );
88  m_m34Max = getArg( 3 );
89  } else {
90  if ( getNArg() > 0 ) {
91  m_m12Min = getArg( 0 );
92  m_m12Max = getArg( 1 );
93  } else {
94  m_m12Min = mass1 + mass2;
95  m_m12Max = mMother - mass3 - mass4;
96  }
97  m_m34Min = mass3 + mass4;
98  m_m34Max = mMother - mass1 - mass2;
99  if ( m_stableDaughters == false || m_stableMother == false ) {
100  m_fixedBoundary = false;
101  }
102  }
103  // Make sure that we have correct boundaries
104  if ( m_m12Min < mass1 + mass2 ) {
105  m_m12Min = mass1 + mass2;
106  }
107  if ( m_m12Max > mMother - mass3 - mass4 ) {
108  m_m12Max = mMother - mass3 - mass4;
109  }
110  if ( m_m34Min < mass3 + mass4 ) {
111  m_m34Min = mass3 + mass4;
112  }
113  if ( m_m34Max > mMother - mass1 - mass2 ) {
114  m_m34Max = mMother - mass1 - mass2;
115  }
116 
119  mMother );
120  } else {
121  m_boundaryShape = Shape::variable;
122  }
123  // If we have fixed boundary, we can precalculate some variables for
124  // m12 and m34 generation
125  if ( m_fixedBoundary ) {
126  if ( m_boundaryShape == Shape::trapezoid ) {
127  const double m12Diff = m_m12Max - m_m12Min;
128  const double minSum = m_m12Min + m_m34Min;
129  m_trapNorm = ( mMother - m_m34Min ) * m12Diff -
130  0.5 * ( m12Diff * ( m_m12Max + m_m12Min ) );
131  m_trapCoeff1 = mMother - m_m34Min;
132  m_trapCoeff2 = mMother * mMother - 2 * mMother * minSum +
133  minSum * minSum;
134  }
135  if ( m_boundaryShape == Shape::pentagon ) {
136  m_pentagonSplit = mMother - m_m34Max;
137  const double area1 = ( m_pentagonSplit - m_m12Min ) *
138  ( m_m34Max - m_m34Min );
139  const double pm12Diff = m_m12Max - m_pentagonSplit;
140  const double area2 = 0.5 * pm12Diff *
141  ( mMother + m_m34Max - m_m12Max ) -
142  pm12Diff * m_m34Min;
143  m_pentagonFraction = area1 / ( area1 + area2 );
144  const double m12Diff = m_m12Max - m_pentagonSplit;
145  const double minSum = m_pentagonSplit + m_m34Min;
146  m_trapNorm = ( mMother - m_m34Min ) * m12Diff -
147  0.5 * ( m12Diff * ( m_m12Max + m_pentagonSplit ) );
148  m_trapCoeff1 = mMother - m_m34Min;
149  m_trapCoeff2 = mMother * mMother - 2 * mMother * minSum +
150  minSum * minSum;
151  }
152  }
153 }
154 
156 {
157  double startM12 = m_m12Min + ( m_m12Max - m_m12Min ) / 20.;
158  double startM34 = m_m34Min + ( m_m34Max - m_m34Min ) / 20.;
159  bool contCond = true;
160  int iteration = 0;
161 
162  auto parent = getParentId();
163  double mMother = EvtPDL::getMaxMass( parent );
164 
165  double funcValue = 0;
166  while (contCond){
167  ++iteration;
168  double currentM12 = startM12;
169  double currentM34 = startM34;
170  funcValue = phspFactor( mMother, currentM12, currentM34,
171  m_daughterMasses )[0];
172  // Maximum along m12
173  double step = ( m_m12Max - m_m12Min ) / 100.;
174  while ( step > 1e-4 ) {
175  double point1 = currentM12 + step;
176  if ( point1 > m_m12Max ) {
177  point1 = m_m12Max;
178  }
179  if ( currentM34 > mMother - point1 ) {
180  point1 = mMother - currentM34;
181  }
182  double point2 = currentM12 - step;
183  if ( point2 < m_m12Min ) {
184  point2 = m_m12Min;
185  }
186  double value1 = phspFactor( mMother, point1, currentM34,
187  m_daughterMasses )[0];
188  double value2 = phspFactor( mMother, point2, currentM34,
189  m_daughterMasses )[0];
190  if ( value1 > funcValue && value1 > value2 ) {
191  currentM12 = point1;
192  funcValue = value1;
193  } else if ( value2 > funcValue ) {
194  currentM12 = point2;
195  funcValue = value2;
196  }
197  step /= 2.;
198  }
199  // Maximum along m34
200  step = ( mMother - currentM12 - m_m34Min ) / 100.;
201  while ( step > 1e-4 ) {
202  double point1 = currentM34 + step;
203  if ( point1 > m_m34Max ) {
204  point1 = m_m34Max;
205  }
206  if ( point1 > mMother - currentM12 ) {
207  point1 = mMother - currentM12;
208  }
209  double point2 = currentM34 - step;
210  if ( point2 < m_m34Min ) {
211  point2 = m_m34Min;
212  }
213  double value1 = phspFactor( mMother, currentM12, point1,
214  m_daughterMasses )[0];
215  double value2 = phspFactor( mMother, currentM12, point2,
216  m_daughterMasses )[0];
217  if ( value1 > funcValue && value1 > value2 ) {
218  currentM34 = point1;
219  funcValue = value1;
220  } else if ( value2 > funcValue ) {
221  currentM34 = point2;
222  funcValue = value2;
223  }
224  step /= 2.;
225  }
226 
227  // Check termination condition
228  double m12Diff = currentM12 - startM12;
229  double m34Diff = currentM34 - startM34;
230  double distSq = m12Diff * m12Diff + m34Diff * m34Diff;
231  if (distSq < 1e-8 || iteration > 50){
232  contCond = false;
233  }
234  startM12 = currentM12;
235  startM34 = currentM34;
236  }
237 
238  setProbMax( funcValue * 1.05 );
239 }
240 
242 {
243 
244  parent->makeDaughters( getNDaug(), getDaugs() );
245  bool massTreeStatus = parent->generateMassTree();
246  if ( !massTreeStatus ) {
247  EvtGenReport( EVTGEN_ERROR, "EvtGen" )
248  << "Failed to generate daughters masses in EvtFourBodyPhsp."
249  << std::endl;
250  ::abort();
251  }
252 
253  double mMother = parent->mass();
254 
255  // Need to check whether boundaries are OK and whether we need to work
256  // out boundary shape
257  double cM12Min, cM12Max;
258  double cM34Min, cM34Max;
259  EvtFourBodyPhsp::Shape cShape;
260  if ( m_fixedBoundary ) {
261  cM12Min = m_m12Min;
262  cM12Max = m_m12Max;
263  cM34Min = m_m34Min;
264  cM34Max = m_m34Max;
265  cShape = m_boundaryShape;
266  } else {
267  // In this case at least one particle has non-zero width and thus
268  // boundaries and shape of the region can change
269  for ( int i = 0; i < 4; ++i ) {
270  auto daughter = parent->getDaug( i );
271  m_daughterMasses[i] = daughter->mass();
272  }
273  cM12Min = m_m12Min > ( m_daughterMasses[0] + m_daughterMasses[1] )
274  ? m_m12Min
276  cM12Max = m_m12Max <
277  ( mMother - m_daughterMasses[2] - m_daughterMasses[3] )
278  ? m_m12Max
279  : mMother - m_daughterMasses[2] - m_daughterMasses[3];
280  cM34Min = m_m34Min > ( m_daughterMasses[2] + m_daughterMasses[3] )
281  ? m_m34Min
283  cM34Max = m_m34Max <
284  ( mMother - m_daughterMasses[0] - m_daughterMasses[1] )
285  ? m_m34Max
286  : mMother - m_daughterMasses[0] - m_daughterMasses[1];
287  cShape = determineBoundaryShape( cM12Min, cM12Max, cM34Max, mMother );
288  }
289 
290  // Generate m12 and m34
291  auto masses = generatePairMasses( cM12Min, cM12Max, cM34Min, cM34Max,
292  mMother, cShape );
293  const double m12 = masses.first;
294  const double m34 = masses.second;
295 
296  // calculate probability, it will return array with 4 elements with
297  // probability, q, p1 and p3
298  auto probEval = phspFactor( mMother, m12, m34, m_daughterMasses );
299  setProb( probEval[0] );
300 
301  // initialise kinematics
302  const double cosTheta1 = EvtRandom::Flat(-1.0, 1.0);
303  const double sinTheta1 = std::sqrt( 1 - cosTheta1 * cosTheta1 );
304  const double cosTheta3 = EvtRandom::Flat(-1.0, 1.0);
305  const double sinTheta3 = std::sqrt( 1 - cosTheta3 * cosTheta3 );
306  const double phi = EvtRandom::Flat( 0., EvtConst::twoPi );
307  // m12 and m34 are put along z-axis, 1 and 2 go to x-z plane and 3-4
308  // plane is rotated by phi compared to 1-2 plane. All momenta are set
309  // in 12 and 34 rest frames and then boosted to parent rest frame
310  const double p1x = probEval[2] * sinTheta1;
311  const double p1z = probEval[2] * cosTheta1;
312  const double p1Sq = probEval[2] * probEval[2];
313  const double en1 = std::sqrt( m_daughterMasses[0] * m_daughterMasses[0] +
314  p1Sq );
315  const double en2 = std::sqrt( m_daughterMasses[1] * m_daughterMasses[1] +
316  p1Sq );
317  const double p3T = probEval[3] * sinTheta3;
318  const double p3x = p3T * std::cos( phi );
319  const double p3y = p3T * std::sin( phi );
320  const double p3z = probEval[3] * cosTheta3;
321  const double p3Sq = probEval[3] * probEval[3];
322  const double en3 = std::sqrt( m_daughterMasses[2] * m_daughterMasses[2] +
323  p3Sq );
324  const double en4 = std::sqrt( m_daughterMasses[3] * m_daughterMasses[3] +
325  p3Sq );
326 
327  EvtVector4R mom1( en1, p1x, 0.0, p1z );
328  EvtVector4R mom2( en2, -p1x, 0.0, -p1z );
329  EvtVector4R mom3( en3, p3x, p3y, p3z );
330  EvtVector4R mom4( en4, -p3x, -p3y, -p3z );
331 
332  const double qSq = probEval[1] * probEval[1];
333  const double en12 = std::sqrt( m12 * m12 + qSq );
334  const double en34 = std::sqrt( m34 * m34 + qSq );
335  EvtVector4R q12( en12, 0.0, 0.0, probEval[1] );
336  EvtVector4R q34( en34, 0.0, 0.0, -probEval[1] );
337  mom1.applyBoostTo( q12 );
338  mom2.applyBoostTo( q12 );
339  mom3.applyBoostTo( q34 );
340  mom4.applyBoostTo( q34 );
341 
342  // As final step, rotate everything randomly in space
343  const double euler1 = EvtRandom::Flat( 0., EvtConst::twoPi );
344  const double euler2 = std::acos( EvtRandom::Flat( -1.0, 1.0 ) );
345  const double euler3 = EvtRandom::Flat( 0., EvtConst::twoPi );
346  mom1.applyRotateEuler( euler1, euler2, euler3 );
347  mom2.applyRotateEuler( euler1, euler2, euler3 );
348  mom3.applyRotateEuler( euler1, euler2, euler3 );
349  mom4.applyRotateEuler( euler1, euler2, euler3 );
350 
351  // Set momenta for daughters
352  auto daug = parent->getDaug( 0 );
353  daug->init( daug->getId(), mom1 );
354  daug = parent->getDaug( 1 );
355  daug->init( daug->getId(), mom2 );
356  daug = parent->getDaug( 2 );
357  daug->init( daug->getId(), mom3 );
358  daug = parent->getDaug( 3 );
359  daug->init( daug->getId(), mom4 );
360 }
361 
363  const double m12Min, const double m12Max, const double m34Max,
364  const double mMother ) const
365 {
366  double maxY = mMother - m12Min;
367  const bool corner1 = m34Max < maxY;
368  maxY = mMother - m12Max;
369  const bool corner2 = m34Max < maxY;
370 
371  if ( corner1 && corner2 ) {
372  return Shape::rectangle;
373  } else if ( !corner1 && !corner2 ) {
374  return Shape::trapezoid;
375  }
376  return Shape::pentagon;
377 }
378 
379 std::pair<double, double> EvtFourBodyPhsp::generatePairMasses(
380  const double m12Min, const double m12Max, const double m34Min,
381  const double m34Max, const double mMother,
382  const EvtFourBodyPhsp::Shape shape ) const
383 {
384  switch ( shape ) {
385  case EvtFourBodyPhsp::Shape::rectangle:
386  return generateRectangle( m12Min, m12Max, m34Min, m34Max );
387  break;
388  case EvtFourBodyPhsp::Shape::trapezoid:
389  return generateTrapezoid( m12Min, m12Max, m34Min, mMother );
390  break;
391  case EvtFourBodyPhsp::Shape::pentagon:
392  double split, fraction;
393  if ( m_fixedBoundary ) {
394  split = m_pentagonSplit;
395  fraction = m_pentagonFraction;
396  } else {
397  split = mMother - m34Max;
398  const double area1 = ( split - m12Min ) * ( m34Max - m34Min );
399  const double pm12Diff = m12Max - split;
400  const double area2 = 0.5 * pm12Diff *
401  ( mMother + m34Max - m12Max ) -
402  pm12Diff * m34Min;
403  fraction = area1 / ( area1 + area2 );
404  }
405  if ( EvtRandom::Flat() < fraction ) {
406  return generateRectangle( m12Min, split, m34Min, m34Max );
407  } else {
408  return generateTrapezoid( split, m12Max, m34Min, mMother );
409  }
410  break;
411  default:
412  return std::make_pair( m12Min, m34Min );
413  break;
414  }
415 }
416 
417 std::pair<double, double> EvtFourBodyPhsp::generateRectangle(
418  const double m12Min, const double m12Max, const double m34Min,
419  const double m34Max ) const
420 {
421  return std::make_pair( EvtRandom::Flat( m12Min, m12Max ),
422  EvtRandom::Flat( m34Min, m34Max ) );
423 }
424 
425 std::pair<double, double> EvtFourBodyPhsp::generateTrapezoid(
426  const double m12Min, const double m12Max, const double m34Min,
427  const double mMother ) const
428 {
429  double norm, coeff1, coeff2;
430  if ( m_fixedBoundary ) {
431  norm = m_trapNorm;
432  coeff1 = m_trapCoeff1;
433  coeff2 = m_trapCoeff2;
434  } else {
435  const double m12Diff = m12Max - m12Min;
436  const double minSum = m12Min + m34Min;
437  norm = ( mMother - m34Min ) * m12Diff -
438  0.5 * ( m12Diff * ( m12Max + m12Min ) );
439  coeff1 = mMother - m34Min;
440  coeff2 = mMother * mMother - 2 * mMother * minSum + minSum * minSum;
441  }
442  const double rnd = EvtRandom::Flat();
443  const double m12 = coeff1 - std::sqrt( -2.0 * rnd * norm + coeff2 );
444  const double m34 = EvtRandom::Flat( m34Min, mMother - m12 );
445  return std::make_pair( m12, m34 );
446 }
void setProb(double prob)
Definition: EvtDecayProb.hh:32
void initProbMax() override
void applyRotateEuler(double alpha, double beta, double gamma)
Definition: EvtVector4R.cpp:83
double getArg(unsigned int j)
std::ostream & EvtGenReport(EvtGenSeverity severity, const char *facility=0)
Definition: EvtReport.cpp:33
virtual void init(EvtId part_n, const EvtVector4R &p4)=0
Shape determineBoundaryShape(const double m12Min, const double m12Max, const double m34Max, const double mMother) const
void decay(EvtParticle *parent) override
double twoBodyMomentum(const double M, const double m1, const double m2)
Definition: EvtKine.cpp:135
static const double twoPi
Definition: EvtConst.hh:27
void makeDaughters(unsigned int ndaug, EvtId *id)
std::pair< double, double > generatePairMasses(const double m12Min, const double m12Max, const double m34Min, const double m34Max, const double mMother, const EvtFourBodyPhsp::Shape shape) const
EvtId * getDaugs()
Definition: EvtDecayBase.hh:66
void init() override
void setProbMax(double prbmx)
EvtId getParentId() const
Definition: EvtDecayBase.hh:61
bool generateMassTree()
std::array< double, 4 > phspFactor(const double mM, const double m12, const double m34, std::array< double, 4 > &daughters) const
void checkNDaug(int d1, int d2=-1)
static double getMinMass(EvtId i)
Definition: EvtPDL.cpp:342
static double Flat()
Definition: EvtRandom.cpp:72
std::array< double, 4 > m_daughterMasses
void checkNArg(int a1, int a2=-1, int a3=-1, int a4=-1)
EvtDecayBase * clone() override
std::pair< double, double > generateTrapezoid(const double m12Min, const double m12Max, const double m34Min, const double mMother) const
void applyBoostTo(const EvtVector4R &p4, bool inverse=false)
double mass() const
static double getWidth(EvtId i)
Definition: EvtPDL.cpp:352
std::string getName() override
int getNDaug() const
Definition: EvtDecayBase.hh:65
EvtParticle * getDaug(int i)
Definition: EvtParticle.cpp:91
std::pair< double, double > generateRectangle(const double m12Min, const double m12Max, const double m34Min, const double m34Max) const
static double getMass(EvtId i)
Definition: EvtPDL.cpp:319
int getNArg() const
Definition: EvtDecayBase.hh:68
static double getMaxMass(EvtId i)
Definition: EvtPDL.cpp:337
EvtId getDaug(int i) const
Definition: EvtDecayBase.hh:67