1 //--------------------------------------------------------------------------
4 // This software is part of the EvtGen package developed jointly
5 // for the BaBar and CLEO collaborations. If you use all or part
6 // of it, please give an appropriate acknowledgement.
8 // Copyright Information: See EvtGen/COPYRIGHT
9 // Copyright (C) 1998 Caltech, UCSB
11 // Module: EvtCPUtil.cc
13 // Description: Utilities needed for generation of CP violating
16 // Modification history:
18 // RYD March 24, 1998 Module created
20 // COWAN June 10, 2009 Added methods for getting dGamma(s)
21 // and dm(s) using B(s)0H and B(s)0L.
22 //------------------------------------------------------------------------
24 #include "EvtGenBase/EvtPatches.hh"
25 #include "EvtGenBase/EvtPatches.hh"
26 #include "EvtGenBase/EvtParticle.hh"
27 #include "EvtGenBase/EvtScalarParticle.hh"
28 #include "EvtGenBase/EvtRandom.hh"
29 #include "EvtGenBase/EvtCPUtil.hh"
30 #include "EvtGenBase/EvtPDL.hh"
31 #include "EvtGenBase/EvtReport.hh"
32 #include "EvtGenBase/EvtSymTable.hh"
33 #include "EvtGenBase/EvtConst.hh"
40 EvtCPUtil::EvtCPUtil(int mixingType) {
42 _mixingType = mixingType;
45 EvtCPUtil::~EvtCPUtil() {
48 EvtCPUtil* EvtCPUtil::getInstance() {
50 static EvtCPUtil* theCPUtil = 0;
53 theCPUtil = new EvtCPUtil(1);
60 //added two functions for finding the fraction of B0 tags for decays into
61 //both CP eigenstates and non-CP eigenstates -- NK, Jan. 27th, 1998
63 void EvtCPUtil::fractB0CP(EvtComplex Af, EvtComplex Abarf,
64 double /*deltam*/, double beta, double &fract) {
66 //This function returns the number of B0 tags for decays into CP-eigenstates
67 //(the "probB0" in the new EvtOtherB)
69 //double gamma_B = EvtPDL::getWidth(B0);
70 //double xd = deltam/gamma_B;
72 double ratio = 1/(1 + 0.65*0.65);
76 rf = EvtComplex(cos(2.0*beta),sin(2.0*beta))*Abarf/Af;
77 rbarf = EvtComplex(1.0)/rf;
79 double A2 = real(Af)*real(Af) + imag(Af)*imag(Af);
80 double Abar2 = real(Abarf)*real(Abarf) + imag(Abarf)*imag(Abarf);
82 double rf2 = real(rf)*real(rf) + imag(rf)*imag(rf);
83 double rbarf2 = real(rbarf)*real(rbarf) + imag(rbarf)*imag(rbarf);
85 fract = (Abar2*(1+ rbarf2 + (1 - rbarf2)*ratio))/(Abar2*(1+ rbarf2 + (1 - rbarf2)*ratio) + A2*(1+ rf2 + (1 - rf2)*ratio));
90 void EvtCPUtil::fractB0nonCP(EvtComplex Af, EvtComplex Abarf,
91 EvtComplex Afbar, EvtComplex Abarfbar,
92 double deltam, double beta,
93 int flip, double &fract) {
95 //this function returns the number of B0 tags for decays into non-CP eigenstates
96 //(the "probB0" in the new EvtOtherB)
97 //this needs more thought...
99 //double gamma_B = EvtPDL::getWidth(B0);
100 //report(INFO,"EvtGen") << "gamma " << gamma_B<< endl;
101 //double xd = deltam/gamma_B;
103 //why is the width of B0 0 in PDL??
106 double gamma_B = deltam/xd;
107 double IAf, IAfbar, IAbarf, IAbarfbar;
108 EvtComplex rf, rfbar, rbarf, rbarfbar;
109 double rf2, rfbar2, rbarf2, rbarfbar2;
110 double Af2, Afbar2, Abarf2, Abarfbar2;
112 rf = EvtComplex(cos(2.0*beta),sin(2.0*beta))*Abarf/Af;
113 rfbar = EvtComplex(cos(2.0*beta),sin(2.0*beta))*Abarfbar/Afbar;
114 rbarf = EvtComplex(cos(-2.0*beta),sin(-2.0*beta))*Af/Abarf;
115 rbarfbar = EvtComplex(cos(-2.0*beta),sin(-2.0*beta))*Afbar/Abarfbar;
118 rf2 = real(rf)*real(rf) + imag(rf)*imag(rf);
119 rfbar2 = real(rfbar)*real(rfbar) + imag(rfbar)*imag(rfbar);
120 rbarf2 = real(rbarf)*real(rbarf) + imag(rbarf)*imag(rbarf);
121 rbarfbar2 = real(rbarfbar)*real(rbarfbar) + imag(rbarfbar)*imag(rbarfbar);
123 Af2 = real(Af)*real(Af) + imag(Af)*imag(Af);
124 Afbar2 = real(Afbar)*real(Afbar) + imag(Afbar)*imag(Afbar);
125 Abarf2 = real(Abarf)*real(Abarf) + imag(Abarf)*imag(Abarf);
126 Abarfbar2 = real(Abarfbar)*real(Abarfbar) + imag(Abarfbar)*imag(Abarfbar);
130 //IAf = integral(gamma(B0->f)), etc.
133 IAf = (Af2/(2*gamma_B))*(1+rf2+(1-rf2)/(1+xd*xd));
134 IAfbar = (Afbar2/(2*gamma_B))*(1+rfbar2+(1-rfbar2)/(1+xd*xd));
135 IAbarf = (Abarf2/(2*gamma_B))*(1+rbarf2+(1-rbarf2)/(1+xd*xd));
136 IAbarfbar = (Abarfbar2/(2*gamma_B))*(1+rbarfbar2+(1-rbarfbar2)/(1+xd*xd));
138 //flip specifies the relative fraction of fbar events
140 fract = IAbarf/(IAbarf+IAf) + flip*IAbarfbar/(IAfbar+IAbarfbar);
146 void EvtCPUtil::OtherB( EvtParticle *p,double &t, EvtId &otherb, double probB0){
148 if (_mixingType == EvtCPUtil::Coherent) {
150 OtherCoherentB(p, t, otherb, probB0);
152 } else if (_mixingType == EvtCPUtil::Incoherent) {
154 OtherIncoherentB(p, t, otherb, probB0);
160 void EvtCPUtil::OtherCoherentB( EvtParticle *p,double &t, EvtId &otherb, double probB0){
162 //Can not call this recursively!!!
163 static int entryCount=0;
166 //added by Lange Jan4,2000
167 static EvtId B0B=EvtPDL::getId("anti-B0");
168 static EvtId B0=EvtPDL::getId("B0");
169 static EvtId BSB=EvtPDL::getId("anti-B_s0");
170 static EvtId BS=EvtPDL::getId("B_s0");
172 static EvtId UPS4S=EvtPDL::getId("Upsilon(4S)");
174 int isB0=EvtRandom::Flat(0.0,1.0)<probB0;
180 // now get the time between the decay of this B and the other B!
182 EvtParticle *parent=p->getParent();
186 bool incoherentmix=false;
188 if ((parent!=0)&&(parent->getId()==B0||
189 parent->getId()==B0B||
190 parent->getId()==BS||
191 parent->getId()==BSB)) {
195 if (incoherentmix) parent=parent->getParent();
197 if (parent==0||parent->getId()!=UPS4S) {
198 //Need to make this more general, but for now
199 //assume no parent. If we have parent of B we
200 //need to charge conj. full decay tree.
204 report(INFO,"EvtGen") << "p="<<EvtPDL::name(p->getId())
205 << " parent="<<EvtPDL::name(parent->getId())
211 bool needToChargeConj=false;
212 if (p->getId()==B0B&&isB0) needToChargeConj=true;
213 if (p->getId()==B0&&!isB0) needToChargeConj=true;
214 if (p->getId()==BSB&&isB0) needToChargeConj=true;
215 if (p->getId()==BS&&!isB0) needToChargeConj=true;
217 if (needToChargeConj) {
218 p->setId( EvtPDL::chargeConj(p->getId()));
220 p->getDaug(0)->setId(EvtPDL::chargeConj(p->getDaug(0)->getId()));
223 otherb=EvtPDL::chargeConj(p->getId());
229 if (parent->getDaug(0)!=p){
230 other=parent->getDaug(0);
234 other=parent->getDaug(1);
242 // report(INFO,"EvtGen") << "Double CP decay:"<<entryCount<<endl;
245 //kludge!! Lange Mar21, 2003
246 // if the other B is an alias... don't change the flavor..
247 if ( other->getId().isAlias() ) {
256 EvtVector4R p_init=other->getP4();
257 //int decayed=other->getNDaug()>0;
258 bool decayed = other->isDecayed();
262 EvtScalarParticle* scalar_part;
264 scalar_part=new EvtScalarParticle;
266 scalar_part->init(B0,p_init);
269 scalar_part->init(B0B,p_init);
271 other=(EvtParticle *)scalar_part;
272 // other->set_type(EvtSpinType::SCALAR);
273 other->setDiagonalSpinDensity();
275 parent->insertDaugPtr(idaug,other);
278 //report(INFO,"EvtGen") << "In CP Util calling decay \n";
284 otherb=other->getId();
286 other->setLifetime();
287 t=p->getLifetime()-other->getLifetime();
289 otherb = other->getId();
293 report(INFO,"EvtGen") << "We have an error here!!!!"<<endl;
294 otherb = EvtId(-1,-1);
301 // ========================================================================
302 bool EvtCPUtil::isBsMixed ( EvtParticle * p )
304 if ( ! ( p->getParent() ) ) return false ;
306 static EvtId BS0=EvtPDL::getId("B_s0");
307 static EvtId BSB=EvtPDL::getId("anti-B_s0");
309 if ( ( p->getId() != BS0 ) && ( p->getId() != BSB ) ) return false ;
311 if ( ( p->getParent()->getId() == BS0 ) ||
312 ( p->getParent()->getId() == BSB ) ) return true ;
317 // ========================================================================
318 bool EvtCPUtil::isB0Mixed ( EvtParticle * p )
320 if ( ! ( p->getParent() ) ) return false ;
322 static EvtId B0 =EvtPDL::getId("B0");
323 static EvtId B0B=EvtPDL::getId("anti-B0");
325 if ( ( p->getId() != B0 ) && ( p->getId() != B0B ) ) return false ;
327 if ( ( p->getParent()->getId() == B0 ) ||
328 ( p->getParent()->getId() == B0B ) ) return true ;
332 //============================================================================
333 // Return the tag of the event (ie the anti-flavour of the produced
334 // B meson). Flip the flavour of the event with probB probability
335 //============================================================================
336 void EvtCPUtil::OtherIncoherentB( EvtParticle * p ,
341 //std::cout<<"New routine running"<<endl;
342 //if(p->getId() == B0 || p->getId() == B0B)
343 //added by liming Zhang
345 if ( ( isB0Mixed( p ) ) || ( isBsMixed( p ) ) ) {
346 p->getParent()->setLifetime() ;
347 t = p->getParent()->getLifetime() ;
351 t = p->getLifetime() ;
354 if ( flipIsEnabled() ) {
355 //std::cout << " liming << flipIsEnabled " << std::endl;
356 // Flip the flavour of the particle with probability probB
357 bool isFlipped = ( EvtRandom::Flat( 0. , 1. ) < probB ) ;
360 if ( ( isB0Mixed( p ) ) || ( isBsMixed( p ) ) ) {
362 ->setId( EvtPDL::chargeConj( p->getParent()->getId() ) ) ;
363 p->setId( EvtPDL::chargeConj( p->getId() ) ) ;
366 p->setId( EvtPDL::chargeConj( p->getId() ) ) ;
371 if ( ( isB0Mixed( p ) ) || ( isBsMixed( p ) ) ) {
372 // if B has mixed, tag flavour is charge conjugate of parent of B-meson
373 otherb = EvtPDL::chargeConj( p->getParent()->getId() ) ;
376 // else it is opposite flavour than this B hadron
377 otherb = EvtPDL::chargeConj( p->getId() ) ;
382 //============================================================================
383 void EvtCPUtil::OtherB( EvtParticle *p,double &t, EvtId &otherb){
385 static EvtId BSB=EvtPDL::getId("anti-B_s0");
386 static EvtId BS0=EvtPDL::getId("B_s0");
387 static EvtId B0B=EvtPDL::getId("anti-B0");
388 static EvtId B0=EvtPDL::getId("B0");
389 static EvtId D0B=EvtPDL::getId("anti-D0");
390 static EvtId D0=EvtPDL::getId("D0");
391 static EvtId UPS4=EvtPDL::getId("Upsilon(4S)");
393 if (p->getId()==BS0||p->getId()==BSB){
394 static double ctauL=EvtPDL::getctau(EvtPDL::getId("B_s0L"));
395 static double ctauH=EvtPDL::getctau(EvtPDL::getId("B_s0H"));
396 static double ctau=ctauL<ctauH?ctauH:ctauL;
397 t=-log(EvtRandom::Flat())*ctau;
398 EvtParticle* parent=p->getParent();
399 if (parent!=0&&(parent->getId()==BS0||parent->getId()==BSB)){
400 if (parent->getId()==BS0) otherb=BSB;
401 if (parent->getId()==BSB) otherb=BS0;
402 parent->setLifetime(t);
405 if (p->getId()==BS0) otherb=BSB;
406 if (p->getId()==BSB) otherb=BS0;
411 if (p->getId()==D0||p->getId()==D0B){
412 static double ctauL=EvtPDL::getctau(EvtPDL::getId("D0L"));
413 static double ctauH=EvtPDL::getctau(EvtPDL::getId("D0H"));
414 static double ctau=ctauL<ctauH?ctauH:ctauL;
415 t=-log(EvtRandom::Flat())*ctau;
416 EvtParticle* parent=p->getParent();
417 if (parent!=0&&(parent->getId()==D0||parent->getId()==D0B)){
418 if (parent->getId()==D0) otherb=D0B;
419 if (parent->getId()==D0B) otherb=D0;
420 parent->setLifetime(t);
423 if (p->getId()==D0) otherb=D0B;
424 if (p->getId()==D0B) otherb=D0;
431 // now get the time between the decay of this B and the other B!
433 EvtParticle *parent=p->getParent();
435 if (parent==0||parent->getId()!=UPS4) {
436 //report(ERROR,"EvtGen") <<
437 // "Warning CP violation with B having no parent!"<<endl;
439 if (p->getId()==B0) otherb=B0B;
440 if (p->getId()==B0B) otherb=B0;
441 if (p->getId()==BS0) otherb=BSB;
442 if (p->getId()==BSB) otherb=BS0;
446 if (parent->getDaug(0)!=p){
447 otherb=parent->getDaug(0)->getId();
448 parent->getDaug(0)->setLifetime();
449 t=p->getLifetime()-parent->getDaug(0)->getLifetime();
452 otherb=parent->getDaug(1)->getId();
453 parent->getDaug(1)->setLifetime();
454 t=p->getLifetime()-parent->getDaug(1)->getLifetime();
462 // No CP violation is assumed
463 void EvtCPUtil::incoherentMix(const EvtId id, double &t, int &mix){
465 int stdHepNum=EvtPDL::getStdHep(id);
466 stdHepNum=abs(stdHepNum);
468 EvtId partId=EvtPDL::evtIdFromStdHep(stdHepNum);
470 std::string partName=EvtPDL::name(partId);
471 std::string hname=partName+std::string("H");
472 std::string lname=partName+std::string("L");
474 EvtId lId=EvtPDL::getId(lname);
475 EvtId hId=EvtPDL::getId(hname);
477 double ctauL=EvtPDL::getctau(lId);
478 double ctauH=EvtPDL::getctau(hId);
480 // Bug Fixed: Corrected the average as gamma is the relevent parameter
481 double ctau=2.0*(ctauL*ctauH)/(ctauL+ctauH);
482 //double ctau=0.5*(ctauL+ctauH);
484 // Bug Fixed: ctau definition changed above
485 //double y=(ctauH-ctauL)/(2*ctau);
486 double y=(ctauH-ctauL)/(ctauH+ctauL);
488 //deltam and qoverp defined in DECAY.DEC
490 std::string qoverpParmName=std::string("qoverp_incohMix_")+partName;
491 std::string mdParmName=std::string("dm_incohMix_")+partName;
493 double qoverp=atof(EvtSymTable::get(qoverpParmName,ierr).c_str());
494 double x=atof(EvtSymTable::get(mdParmName,ierr).c_str())*ctau/EvtConst::c;
498 fac=1.0/(qoverp*qoverp);
504 double mixprob=(x*x+y*y)/(x*x+y*y+fac*(2.0+x*x-y*y));
508 mixsign=(mixprob>EvtRandom::Flat(0.0,1.0))?-1:1;
512 // Find the longest of the two lifetimes
513 double ctaulong = ctauL<=ctauH?ctauH:ctauL;
515 // Bug fixed: Ensure cosine argument is dimensionless so /ctau
517 t=-log(EvtRandom::Flat())*ctaulong;
518 prob=1.0+exp(-2.0*fabs(y)*t/ctau)+mixsign*2.0*exp(-fabs(y)*t/ctau)*cos(x*t/ctau);
519 }while(prob<4.0*EvtRandom::Flat());
523 if (mixsign==-1) mix=1;
529 double EvtCPUtil::getDeltaGamma(const EvtId id){
531 int stdHepNum = EvtPDL::getStdHep(id);
532 stdHepNum = abs(stdHepNum);
533 EvtId partId = EvtPDL::evtIdFromStdHep(stdHepNum);
535 std::string partName = EvtPDL::name(partId);
536 std::string hname = partName + std::string("H");
537 std::string lname = partName + std::string("L");
539 EvtId lId = EvtPDL::getId(lname);
540 EvtId hId = EvtPDL::getId(hname);
542 double ctauL = EvtPDL::getctau(lId);
543 double ctauH = EvtPDL::getctau(hId);
545 double dGamma = (1/ctauL - 1/ctauH)*EvtConst::c;
549 double EvtCPUtil::getDeltaM(const EvtId id){
551 int stdHepNum = EvtPDL::getStdHep(id);
552 stdHepNum = abs(stdHepNum);
553 EvtId partId = EvtPDL::evtIdFromStdHep(stdHepNum);
555 std::string partName = EvtPDL::name(partId);
556 std::string parmName = std::string("dm_incohMix_") + partName;
559 double dM = atof(EvtSymTable::get(parmName,ierr).c_str());
563 bool EvtCPUtil::flipIsEnabled() { return _enableFlip ; }
564 void EvtCPUtil::enableFlip() { _enableFlip = true ; }
565 void EvtCPUtil::disableFlip() { _enableFlip = false ; }