EvtGen 2.2.0
Monte Carlo generator of particle decays, in particular the weak decays of heavy flavour particles such as B mesons.
Loading...
Searching...
No Matches
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
24#include "EvtGenBase/EvtPDL.hh"
29
32
33#include <fstream>
34#include <iostream>
35#include <stdlib.h>
36#include <string>
37using std::cout;
38using std::endl;
39using std::ifstream;
40
41std::string EvtVubHybrid::getName() const
42{
43 return "VUBHYBRID";
44}
45
47{
48 return new EvtVubHybrid;
49}
50
52{
53 // check that there are at least 3 arguments
55 EvtGenReport( EVTGEN_ERROR, "EvtVubHybrid" )
56 << "EvtVub generator expected "
57 << "at least " << EvtVubHybrid::nParameters
58 << " arguments but found: " << getNArg()
59 << "\nWill terminate execution!" << endl;
60 ::abort();
61 } else if ( getNArg() == EvtVubHybrid::nParameters ) {
62 EvtGenReport( EVTGEN_WARNING, "EvtVubHybrid" )
63 << "EvtVub: generate B -> Xu l nu events "
64 << "without using the hybrid reweighting." << endl;
65 m_noHybrid = true;
67 EvtGenReport( EVTGEN_ERROR, "EvtVubHybrid" )
68 << "EvtVub could not read number of bins for "
69 << "all variables used in the reweighting\n"
70 << "Will terminate execution!" << endl;
71 ::abort();
72 }
73
74 // check that there are 3 daughters
75 checkNDaug( 3 );
76
77 // read minimum required parameters from decay.dec
78 m_mb = getArg( 0 );
79 m_a = getArg( 1 );
80 m_alphas = getArg( 2 );
81
82 // the maximum dGamma*p2 value depends on alpha_s only:
83 const double dGMax0 = 3.;
84 m_dGMax = 0.21344 + 8.905 * m_alphas;
85 if ( m_dGMax < dGMax0 )
86 m_dGMax = dGMax0;
87
88 // for the Fermi Motion we need a B-Meson mass - but it's not critical
89 // to get an exact value; in order to stay in the phase space for
90 // B+- and B0 use the smaller mass
91
92 static const double mB0 = EvtPDL::getMaxMass( EvtPDL::getId( "B0" ) );
93 static const double mBP = EvtPDL::getMaxMass( EvtPDL::getId( "B+" ) );
94 static const double mB = ( mB0 < mBP ? mB0 : mBP );
95
96 const double xlow = -m_mb;
97 const double xhigh = mB - m_mb;
98 const int aSize = 10000;
99
100 EvtPFermi pFermi( m_a, mB, m_mb );
101 // pf is the cumulative distribution normalized to 1.
102 m_pf.resize( aSize );
103 for ( int i = 0; i < aSize; i++ ) {
104 double kplus = xlow + (double)( i + 0.5 ) / ( (double)aSize ) *
105 ( xhigh - xlow );
106 if ( i == 0 )
107 m_pf[i] = pFermi.getFPFermi( kplus );
108 else
109 m_pf[i] = m_pf[i - 1] + pFermi.getFPFermi( kplus );
110 }
111 for ( size_t index = 0; index < m_pf.size(); index++ ) {
112 m_pf[index] /= m_pf[m_pf.size() - 1];
113 }
114
115 m_dGamma = std::make_unique<EvtVubdGamma>( m_alphas );
116
117 if ( m_noHybrid )
118 return; // Without hybrid weighting, nothing else to do
119
120 m_bins_mX.resize( abs( (int)getArg( 3 ) ) );
121 m_bins_q2.resize( abs( (int)getArg( 4 ) ) );
122 m_bins_El.resize( abs( (int)getArg( 5 ) ) );
123
125
126 m_nbins = m_bins_mX.size() * m_bins_q2.size() *
127 m_bins_El.size(); // Binning of weight table
128
129 int expectArgs = nextArg + m_bins_mX.size() + m_bins_q2.size() +
130 m_bins_El.size() + m_nbins;
131
132 if ( getNArg() < expectArgs ) {
133 EvtGenReport( EVTGEN_ERROR, "EvtVubHybrid" )
134 << " finds " << getNArg() << " arguments, expected " << expectArgs
135 << ". Something is wrong with the tables of weights or thresholds."
136 << "\nWill terminate execution!" << endl;
137 ::abort();
138 }
139
140 // read bin boundaries from decay.dec
141 for ( auto& b : m_bins_mX )
142 b = getArg( nextArg++ );
143 m_masscut = m_bins_mX[0];
144
145 for ( auto& b : m_bins_q2 )
146 b = getArg( nextArg++ );
147 for ( auto& b : m_bins_El )
148 b = getArg( nextArg++ );
149
150 // read in weights (and rescale to range 0..1)
151 readWeights( nextArg );
152}
153
155{
156 noProbMax();
157}
158
160{
161 int j;
162 // B+ -> u-bar specflav l+ nu
163
164 EvtParticle *xuhad( nullptr ), *lepton( nullptr ), *neutrino( nullptr );
165 EvtVector4R p4;
166 // R. Faccini 21/02/03
167 // move the reweighting up , before also shooting the fermi distribution
168 double x, z, p2;
169 double sh = 0.0;
170 double mB, ml, xlow, xhigh, qplus;
171 double El = 0.0;
172 double Eh = 0.0;
173 double kplus;
174 double q2, mX;
175
176 const double lp2epsilon = -10;
177 bool rew( true );
178 while ( rew ) {
180
181 xuhad = p->getDaug( 0 );
182 lepton = p->getDaug( 1 );
183 neutrino = p->getDaug( 2 );
184
185 mB = p->mass();
186 ml = lepton->mass();
187
188 xlow = -m_mb;
189 xhigh = mB - m_mb;
190
191 // Fermi motion does not need to be computed inside the
192 // tryit loop as m_b in Gamma0 does not need to be replaced by (m_b+kplus).
193 // The difference however should be of the Order (lambda/m_b)^2 which is
194 // beyond the considered orders in the paper anyway ...
195
196 // for alpha_S = 0 and a mass cut on X_u not all values of kplus are
197 // possible. The maximum value is mB/2-m_mb + sqrt(mB^2/4-m_masscut^2)
198 kplus = 2 * xhigh;
199
200 while ( kplus >= xhigh || kplus <= xlow ||
201 ( m_alphas == 0 &&
202 kplus >= mB / 2 - m_mb +
203 sqrt( mB * mB / 4 - m_masscut * m_masscut ) ) ) {
204 kplus = findPFermi(); //_pFermi->shoot();
205 kplus = xlow + kplus * ( xhigh - xlow );
206 }
207 qplus = mB - m_mb - kplus;
208 if ( ( mB - qplus ) / 2. <= ml )
209 continue;
210
211 int tryit = 1;
212 while ( tryit ) {
213 x = EvtRandom::Flat();
214 z = EvtRandom::Flat( 0, 2 );
215 p2 = EvtRandom::Flat();
216 p2 = pow( 10, lp2epsilon * p2 );
217
218 El = x * ( mB - qplus ) / 2;
219 if ( El > ml && El < mB / 2 ) {
220 Eh = z * ( mB - qplus ) / 2 + qplus;
221 if ( Eh > 0 && Eh < mB ) {
222 sh = p2 * pow( mB - qplus, 2 ) +
223 2 * qplus * ( Eh - qplus ) + qplus * qplus;
224 if ( sh > m_masscut * m_masscut &&
225 mB * mB + sh - 2 * mB * Eh > ml * ml ) {
226 double xran = EvtRandom::Flat();
227
228 double y = m_dGamma->getdGdxdzdp( x, z, p2 ) / m_dGMax *
229 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 ( !m_weights.empty() ) {
248 double xran1 = EvtRandom::Flat();
249 double w = 1.0;
250 if ( !m_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 ( m_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( m_pf.size() ) );
384 int nBinsBelow = 0; // largest k such that I[k] is known to be <= rand
385 int nBinsAbove = m_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 >= m_pf[middle] ) {
391 nBinsBelow = middle;
392 } else {
393 nBinsAbove = middle;
394 }
395 }
396
397 double bSize = m_pf[nBinsAbove] - m_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 - m_pf[nBinsBelow] ) / bSize;
408 return ( nBinsBelow + bFract ) * oOverBins;
409}
410
411double 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 < m_bins_mX.size(); i++ ) {
418 if ( mX >= m_bins_mX[i] )
419 ibin_mX = i;
420 }
421 for ( unsigned i = 0; i < m_bins_q2.size(); i++ ) {
422 if ( q2 >= m_bins_q2[i] )
423 ibin_q2 = i;
424 }
425 for ( unsigned i = 0; i < m_bins_El.size(); i++ ) {
426 if ( El >= m_bins_El[i] )
427 ibin_El = i;
428 }
429 int ibin = ibin_mX + ibin_q2 * m_bins_mX.size() +
430 ibin_El * m_bins_mX.size() * m_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 m_weights[ibin];
441}
442
443void EvtVubHybrid::readWeights( int startArg )
444{
445 m_weights.resize( m_nbins );
446
447 double maxw = 0.0;
448 for ( auto& w : m_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 : m_weights )
464 w /= maxw;
465}
double abs(const EvtComplex &c)
std::ostream & EvtGenReport(EvtGenSeverity severity, const char *facility=nullptr)
Definition EvtReport.cpp:32
@ EVTGEN_WARNING
Definition EvtReport.hh:50
@ EVTGEN_ERROR
Definition EvtReport.hh:49
EvtDecayBase()=default
int getNDaug() const
int getNArg() const
double getArg(unsigned int j)
EvtId getDaug(int i) const
void checkNDaug(int d1, int d2=-1)
const EvtId * getDaugs() const
static double getMaxMass(EvtId i)
Definition EvtPDL.cpp:331
static EvtId getId(const std::string &name)
Definition EvtPDL.cpp:283
double getFPFermi(const double &kplus)
Definition EvtPFermi.cpp:51
virtual void init(EvtId part_n, const EvtVector4R &p4)=0
double initializePhaseSpace(size_t numdaughter, const EvtId *daughters, bool forceResetMasses=false, double poleSize=-1., int whichTwo1=0, int whichTwo2=1)
EvtParticle * getDaug(const int i)
double mass() const
static double Flat()
Definition EvtRandom.cpp:95
void set(int i, double d)
void readWeights(int startArg=0)
double getWeight(double mX, double q2, double El)
double findPFermi()
EvtDecayBase * clone() const override
void init() override
std::vector< double > m_weights
std::string getName() const override
void decay(EvtParticle *p) override
void initProbMax() override
std::vector< double > m_bins_q2
std::unique_ptr< EvtVubdGamma > m_dGamma
std::vector< double > m_bins_mX
std::vector< double > m_pf
std::vector< double > m_bins_El