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.
EvtVubHybrid.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 
22 
23 #include "EvtGenBase/EvtGenKine.hh"
24 #include "EvtGenBase/EvtPDL.hh"
26 #include "EvtGenBase/EvtPatches.hh"
27 #include "EvtGenBase/EvtRandom.hh"
28 #include "EvtGenBase/EvtReport.hh"
30 
33 
34 #include <fstream>
35 #include <iostream>
36 #include <stdlib.h>
37 #include <string>
38 using std::cout;
39 using std::endl;
40 using std::ifstream;
41 
42 std::string EvtVubHybrid::getName()
43 {
44  return "VUBHYBRID";
45 }
46 
48 {
49  return new EvtVubHybrid;
50 }
51 
53 {
54  // check that there are at least 3 arguments
56  EvtGenReport( EVTGEN_ERROR, "EvtVubHybrid" )
57  << "EvtVub generator expected "
58  << "at least " << EvtVubHybrid::nParameters
59  << " arguments but found: " << getNArg()
60  << "\nWill terminate execution!" << endl;
61  ::abort();
62  } else if ( getNArg() == EvtVubHybrid::nParameters ) {
63  EvtGenReport( EVTGEN_WARNING, "EvtVubHybrid" )
64  << "EvtVub: generate B -> Xu l nu events "
65  << "without using the hybrid reweighting." << endl;
66  _noHybrid = true;
68  EvtGenReport( EVTGEN_ERROR, "EvtVubHybrid" )
69  << "EvtVub could not read number of bins for "
70  << "all variables used in the reweighting\n"
71  << "Will terminate execution!" << endl;
72  ::abort();
73  }
74 
75  // check that there are 3 daughters
76  checkNDaug( 3 );
77 
78  // read minimum required parameters from decay.dec
79  _mb = getArg( 0 );
80  _a = getArg( 1 );
81  _alphas = getArg( 2 );
82 
83  // the maximum dGamma*p2 value depends on alpha_s only:
84  const double dGMax0 = 3.;
85  _dGMax = 0.21344 + 8.905 * _alphas;
86  if ( _dGMax < dGMax0 )
87  _dGMax = dGMax0;
88 
89  // for the Fermi Motion we need a B-Meson mass - but it's not critical
90  // to get an exact value; in order to stay in the phase space for
91  // B+- and B0 use the smaller mass
92 
93  static double mB0 = EvtPDL::getMaxMass( EvtPDL::getId( "B0" ) );
94  static double mBP = EvtPDL::getMaxMass( EvtPDL::getId( "B+" ) );
95  static double mB = ( mB0 < mBP ? mB0 : mBP );
96 
97  const double xlow = -_mb;
98  const double xhigh = mB - _mb;
99  const int aSize = 10000;
100 
101  EvtPFermi pFermi( _a, mB, _mb );
102  // pf is the cumulative distribution normalized to 1.
103  _pf.resize( aSize );
104  for ( int i = 0; i < aSize; i++ ) {
105  double kplus = xlow + (double)( i + 0.5 ) / ( (double)aSize ) *
106  ( xhigh - xlow );
107  if ( i == 0 )
108  _pf[i] = pFermi.getFPFermi( kplus );
109  else
110  _pf[i] = _pf[i - 1] + pFermi.getFPFermi( kplus );
111  }
112  for ( size_t index = 0; index < _pf.size(); index++ ) {
113  _pf[index] /= _pf[_pf.size() - 1];
114  }
115 
116  _dGamma = std::make_unique<EvtVubdGamma>( _alphas );
117 
118  if ( _noHybrid )
119  return; // Without hybrid weighting, nothing else to do
120 
121  _bins_mX.resize( abs( (int)getArg( 3 ) ) );
122  _bins_q2.resize( abs( (int)getArg( 4 ) ) );
123  _bins_El.resize( abs( (int)getArg( 5 ) ) );
124 
126 
127  _nbins = _bins_mX.size() * _bins_q2.size() *
128  _bins_El.size(); // Binning of weight table
129 
130  int expectArgs = nextArg + _bins_mX.size() + _bins_q2.size() +
131  _bins_El.size() + _nbins;
132 
133  if ( getNArg() < expectArgs ) {
134  EvtGenReport( EVTGEN_ERROR, "EvtVubHybrid" )
135  << " finds " << getNArg() << " arguments, expected " << expectArgs
136  << ". Something is wrong with the tables of weights or thresholds."
137  << "\nWill terminate execution!" << endl;
138  ::abort();
139  }
140 
141  // read bin boundaries from decay.dec
142  for ( auto& b : _bins_mX )
143  b = getArg( nextArg++ );
144  _masscut = _bins_mX[0];
145 
146  for ( auto& b : _bins_q2 )
147  b = getArg( nextArg++ );
148  for ( auto& b : _bins_El )
149  b = getArg( nextArg++ );
150 
151  // read in weights (and rescale to range 0..1)
152  readWeights( nextArg );
153 }
154 
156 {
157  noProbMax();
158 }
159 
161 {
162  int j;
163  // B+ -> u-bar specflav l+ nu
164 
165  EvtParticle *xuhad( 0 ), *lepton( 0 ), *neutrino( 0 );
166  EvtVector4R p4;
167  // R. Faccini 21/02/03
168  // move the reweighting up , before also shooting the fermi distribution
169  double x, z, p2;
170  double sh = 0.0;
171  double mB, ml, xlow, xhigh, qplus;
172  double El = 0.0;
173  double Eh = 0.0;
174  double kplus;
175  double q2, mX;
176 
177  const double lp2epsilon = -10;
178  bool rew( true );
179  while ( rew ) {
181 
182  xuhad = p->getDaug( 0 );
183  lepton = p->getDaug( 1 );
184  neutrino = p->getDaug( 2 );
185 
186  mB = p->mass();
187  ml = lepton->mass();
188 
189  xlow = -_mb;
190  xhigh = mB - _mb;
191 
192  // Fermi motion does not need to be computed inside the
193  // tryit loop as m_b in Gamma0 does not need to be replaced by (m_b+kplus).
194  // The difference however should be of the Order (lambda/m_b)^2 which is
195  // beyond the considered orders in the paper anyway ...
196 
197  // for alpha_S = 0 and a mass cut on X_u not all values of kplus are
198  // possible. The maximum value is mB/2-_mb + sqrt(mB^2/4-_masscut^2)
199  kplus = 2 * xhigh;
200 
201  while ( kplus >= xhigh || kplus <= xlow ||
202  ( _alphas == 0 &&
203  kplus >= mB / 2 - _mb +
204  sqrt( mB * mB / 4 - _masscut * _masscut ) ) ) {
205  kplus = findPFermi(); //_pFermi->shoot();
206  kplus = xlow + kplus * ( xhigh - xlow );
207  }
208  qplus = mB - _mb - kplus;
209  if ( ( mB - qplus ) / 2. <= ml )
210  continue;
211 
212  int tryit = 1;
213  while ( tryit ) {
214  x = EvtRandom::Flat();
215  z = EvtRandom::Flat( 0, 2 );
216  p2 = EvtRandom::Flat();
217  p2 = pow( 10, lp2epsilon * p2 );
218 
219  El = x * ( mB - qplus ) / 2;
220  if ( El > ml && El < mB / 2 ) {
221  Eh = z * ( mB - qplus ) / 2 + qplus;
222  if ( Eh > 0 && Eh < mB ) {
223  sh = p2 * pow( mB - qplus, 2 ) +
224  2 * qplus * ( Eh - qplus ) + qplus * qplus;
225  if ( sh > _masscut * _masscut &&
226  mB * mB + sh - 2 * mB * Eh > ml * ml ) {
227  double xran = EvtRandom::Flat();
228 
229  double y = _dGamma->getdGdxdzdp( x, z, p2 ) / _dGMax * p2;
230 
231  if ( y > 1 )
232  EvtGenReport( EVTGEN_WARNING, "EvtVubHybrid" )
233  << "EvtVubHybrid decay probability > 1 found: "
234  << y << endl;
235  if ( y >= xran )
236  tryit = 0;
237  }
238  }
239  }
240  }
241 
242  // compute all kinematic variables needed for reweighting (J. Dingfelder)
243  mX = sqrt( sh );
244  q2 = mB * mB + sh - 2 * mB * Eh;
245 
246  // Reweighting in bins of mX, q2, El (J. Dingfelder)
247  if ( !_weights.empty() ) {
248  double xran1 = EvtRandom::Flat();
249  double w = 1.0;
250  if ( !_noHybrid )
251  w = getWeight( mX, q2, El );
252  if ( w >= xran1 )
253  rew = false;
254  } else {
255  rew = false;
256  }
257  }
258 
259  // o.k. we have the three kineamtic variables
260  // now calculate a flat cos Theta_H [-1,1] distribution of the
261  // hadron flight direction w.r.t the B flight direction
262  // because the B is a scalar and should decay isotropic.
263  // Then chose a flat Phi_H [0,2Pi] w.r.t the B flight direction
264  // and and a flat Phi_L [0,2Pi] in the W restframe w.r.t the
265  // W flight direction.
266 
267  double ctH = EvtRandom::Flat( -1, 1 );
268  double phH = EvtRandom::Flat( 0, 2 * M_PI );
269  double phL = EvtRandom::Flat( 0, 2 * M_PI );
270 
271  // now compute the four vectors in the B Meson restframe
272 
273  double ptmp, sttmp;
274  // calculate the hadron 4 vector in the B Meson restframe
275 
276  sttmp = sqrt( 1 - ctH * ctH );
277  ptmp = sqrt( Eh * Eh - sh );
278  double pHB[4] = {Eh, ptmp * sttmp * cos( phH ), ptmp * sttmp * sin( phH ),
279  ptmp * ctH};
280  p4.set( pHB[0], pHB[1], pHB[2], pHB[3] );
281  xuhad->init( getDaug( 0 ), p4 );
282 
283  if ( _storeQplus ) {
284  // cludge to store the hidden parameter q+ with the decay;
285  // the lifetime of the Xu is abused for this purpose.
286  // tau = 1 ps corresponds to ctau = 0.3 mm -> in order to
287  // stay well below BaBars sensitivity we take q+/(10000 GeV) which
288  // goes up to 0.0005 in the most extreme cases as ctau in mm.
289  // To extract q+ back from the StdHepTrk its necessary to get
290  // delta_ctau = Xu->anyDaughter->getVertexTime()-Xu->getVertexTime()
291  // where these pseudo calls refere to the StdHep time stored at
292  // the production vertex in the lab for each particle. The boost
293  // has to be reversed and the result is:
294  //
295  // q+ = delta_ctau * 10000 GeV/mm * Mass_Xu/Energy_Xu
296  //
297  xuhad->setLifetime( qplus / 10000. );
298  }
299 
300  // calculate the W 4 vector in the B Meson restrframe
301 
302  double apWB = ptmp;
303  double pWB[4] = {mB - Eh, -pHB[1], -pHB[2], -pHB[3]};
304 
305  // first go in the W restframe and calculate the lepton and
306  // the neutrino in the W frame
307 
308  double mW2 = mB * mB + sh - 2 * mB * Eh;
309  double beta = ptmp / pWB[0];
310  double gamma = pWB[0] / sqrt( mW2 );
311 
312  double pLW[4];
313 
314  ptmp = ( mW2 - ml * ml ) / 2 / sqrt( mW2 );
315  pLW[0] = sqrt( ml * ml + ptmp * ptmp );
316 
317  double ctL = ( El - gamma * pLW[0] ) / beta / gamma / ptmp;
318  if ( ctL < -1 )
319  ctL = -1;
320  if ( ctL > 1 )
321  ctL = 1;
322  sttmp = sqrt( 1 - ctL * ctL );
323 
324  // eX' = eZ x eW
325  double xW[3] = {-pWB[2], pWB[1], 0};
326  // eZ' = eW
327  double zW[3] = {pWB[1] / apWB, pWB[2] / apWB, pWB[3] / apWB};
328 
329  double lx = sqrt( xW[0] * xW[0] + xW[1] * xW[1] );
330  for ( j = 0; j < 2; j++ )
331  xW[j] /= lx;
332 
333  // eY' = eZ' x eX'
334  double yW[3] = {-pWB[1] * pWB[3], -pWB[2] * pWB[3],
335  pWB[1] * pWB[1] + pWB[2] * pWB[2]};
336  double ly = sqrt( yW[0] * yW[0] + yW[1] * yW[1] + yW[2] * yW[2] );
337  for ( j = 0; j < 3; j++ )
338  yW[j] /= ly;
339 
340  // p_lep = |p_lep| * ( sin(Theta) * cos(Phi) * eX'
341  // + sin(Theta) * sin(Phi) * eY'
342  // + cos(Theta) * eZ')
343  for ( j = 0; j < 3; j++ )
344  pLW[j + 1] = sttmp * cos( phL ) * ptmp * xW[j] +
345  sttmp * sin( phL ) * ptmp * yW[j] + ctL * ptmp * zW[j];
346 
347  double apLW = ptmp;
348  // calculate the neutrino 4 vector in the W restframe
349  //double pNW[4] = {sqrt(mW2)-pLW[0],-pLW[1],-pLW[2],-pLW[3]};
350 
351  // boost them back in the B Meson restframe
352 
353  double appLB = beta * gamma * pLW[0] + gamma * ctL * apLW;
354 
355  ptmp = sqrt( El * El - ml * ml );
356  double ctLL = appLB / ptmp;
357 
358  if ( ctLL > 1 )
359  ctLL = 1;
360  if ( ctLL < -1 )
361  ctLL = -1;
362 
363  double pLB[4] = {El, 0, 0, 0};
364  double pNB[4] = {pWB[0] - El, 0, 0, 0};
365 
366  for ( j = 1; j < 4; j++ ) {
367  pLB[j] = pLW[j] + ( ctLL * ptmp - ctL * apLW ) / apWB * pWB[j];
368  pNB[j] = pWB[j] - pLB[j];
369  }
370 
371  p4.set( pLB[0], pLB[1], pLB[2], pLB[3] );
372  lepton->init( getDaug( 1 ), p4 );
373 
374  p4.set( pNB[0], pNB[1], pNB[2], pNB[3] );
375  neutrino->init( getDaug( 2 ), p4 );
376 
377  return;
378 }
379 
381 {
382  double ranNum = EvtRandom::Flat();
383  double oOverBins = 1.0 / ( float( _pf.size() ) );
384  int nBinsBelow = 0; // largest k such that I[k] is known to be <= rand
385  int nBinsAbove = _pf.size(); // largest k such that I[k] is known to be > rand
386  int middle;
387 
388  while ( nBinsAbove > nBinsBelow + 1 ) {
389  middle = ( nBinsAbove + nBinsBelow + 1 ) >> 1;
390  if ( ranNum >= _pf[middle] ) {
391  nBinsBelow = middle;
392  } else {
393  nBinsAbove = middle;
394  }
395  }
396 
397  double bSize = _pf[nBinsAbove] - _pf[nBinsBelow];
398  // binMeasure is always aProbFunc[nBinsBelow],
399 
400  if ( bSize == 0 ) {
401  // rand lies right in a bin of measure 0. Simply return the center
402  // of the range of that bin. (Any value between k/N and (k+1)/N is
403  // equally good, in this rare case.)
404  return ( nBinsBelow + .5 ) * oOverBins;
405  }
406 
407  double bFract = ( ranNum - _pf[nBinsBelow] ) / bSize;
408  return ( nBinsBelow + bFract ) * oOverBins;
409 }
410 
411 double EvtVubHybrid::getWeight( double mX, double q2, double El )
412 {
413  int ibin_mX = -1;
414  int ibin_q2 = -1;
415  int ibin_El = -1;
416 
417  for ( unsigned i = 0; i < _bins_mX.size(); i++ ) {
418  if ( mX >= _bins_mX[i] )
419  ibin_mX = i;
420  }
421  for ( unsigned i = 0; i < _bins_q2.size(); i++ ) {
422  if ( q2 >= _bins_q2[i] )
423  ibin_q2 = i;
424  }
425  for ( unsigned i = 0; i < _bins_El.size(); i++ ) {
426  if ( El >= _bins_El[i] )
427  ibin_El = i;
428  }
429  int ibin = ibin_mX + ibin_q2 * _bins_mX.size() +
430  ibin_El * _bins_mX.size() * _bins_q2.size();
431 
432  if ( ( ibin_mX < 0 ) || ( ibin_q2 < 0 ) || ( ibin_El < 0 ) ) {
433  EvtGenReport( EVTGEN_ERROR, "EvtVubHybrid" )
434  << "Cannot determine hybrid weight "
435  << "for this event "
436  << "-> assign weight = 0" << endl;
437  return 0.0;
438  }
439 
440  return _weights[ibin];
441 }
442 
443 void EvtVubHybrid::readWeights( int startArg )
444 {
445  _weights.resize( _nbins );
446 
447  double maxw = 0.0;
448  for ( auto& w : _weights ) {
449  w = getArg( startArg++ );
450  if ( w > maxw )
451  maxw = w;
452  }
453 
454  if ( maxw == 0 ) {
455  EvtGenReport( EVTGEN_ERROR, "EvtVubHybrid" )
456  << "EvtVub generator expected at least one "
457  << " weight > 0, but found none! "
458  << "Will terminate execution!" << endl;
459  ::abort();
460  }
461 
462  // rescale weights (to be in range 0..1)
463  for ( auto& w : _weights )
464  w /= maxw;
465 }
double getWeight(double mX, double q2, double El)
double _masscut
Definition: EvtVubHybrid.hh:82
void initProbMax() override
std::unique_ptr< EvtVubdGamma > _dGamma
Definition: EvtVubHybrid.hh:87
double getArg(unsigned int j)
void decay(EvtParticle *p) override
double _alphas
Definition: EvtVubHybrid.hh:79
std::ostream & EvtGenReport(EvtGenSeverity severity, const char *facility=0)
Definition: EvtReport.cpp:33
virtual void init(EvtId part_n, const EvtVector4R &p4)=0
double getFPFermi(const double &kplus)
Definition: EvtPFermi.cpp:52
std::string getName() override
void set(int i, double d)
Definition: EvtVector4R.hh:167
EvtId * getDaugs()
Definition: EvtDecayBase.hh:66
std::vector< double > _pf
Definition: EvtVubHybrid.hh:88
double findPFermi()
std::vector< double > _bins_mX
Definition: EvtVubHybrid.hh:83
void readWeights(int startArg=0)
double initializePhaseSpace(unsigned int numdaughter, EvtId *daughters, bool forceResetMasses=false, double poleSize=-1., int whichTwo1=0, int whichTwo2=1)
void checkNDaug(int d1, int d2=-1)
static double Flat()
Definition: EvtRandom.cpp:72
double abs(const EvtComplex &c)
Definition: EvtComplex.hh:201
static EvtId getId(const std::string &name)
Definition: EvtPDL.cpp:287
double mass() const
std::vector< double > _weights
Definition: EvtVubHybrid.hh:86
int getNDaug() const
Definition: EvtDecayBase.hh:65
EvtParticle * getDaug(int i)
Definition: EvtParticle.cpp:91
std::vector< double > _bins_q2
Definition: EvtVubHybrid.hh:84
void init() override
std::vector< double > _bins_El
Definition: EvtVubHybrid.hh:85
EvtDecayBase * clone() override
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