diff --git a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc --- a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc +++ b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc @@ -1,2200 +1,2201 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEPP2GammaGammaPowheg class. // #include "MEPP2GammaGammaPowheg.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Cuts/Cuts.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Utilities/Maths.h" #include "Herwig/Shower/Base/ShowerTree.h" #include "Herwig/Shower/Base/ShowerProgenitor.h" #include "Herwig/Shower/Base/ShowerParticle.h" #include "Herwig/Shower/Base/Branching.h" #include "Herwig/Shower/Base/HardTree.h" #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeMEPP2GammaGammaPowheg("Herwig::MEPP2GammaGammaPowheg", "HwMEHadron.so HwPowhegMEHadron.so"); unsigned int MEPP2GammaGammaPowheg::orderInAlphaS() const { return 0; } unsigned int MEPP2GammaGammaPowheg::orderInAlphaEW() const { return 2; } IBPtr MEPP2GammaGammaPowheg::clone() const { return new_ptr(*this); } IBPtr MEPP2GammaGammaPowheg::fullclone() const { return new_ptr(*this); } MEPP2GammaGammaPowheg::MEPP2GammaGammaPowheg() : contrib_(1), power_(0.1), process_(0), threeBodyProcess_(0), maxflavour_(5), alphaS_(0.), fixedAlphaS_(false), supressionFunction_(0), supressionScale_(0), lambda_(20.*GeV), preQCDqqbarq_(5.), preQCDqqbarqbar_(0.5), preQCDqg_(50.), preQCDgqbar_(50.), preQEDqqbarq_(40.), preQEDqqbarqbar_(0.5), preQEDqgq_(1.), preQEDgqbarqbar_(1.), minpT_(2.*GeV), scaleChoice_(0), scalePreFactor_(1.) {} void MEPP2GammaGammaPowheg::getDiagrams() const { tcPDPtr gamma = getParticleData(ParticleID::gamma); tcPDPtr g = getParticleData(ParticleID::g); for(int ix=1;ix<=maxflavour_;++ix) { tcPDPtr qk = getParticleData(ix); tcPDPtr qb = qk->CC(); // gamma gamma if(process_==0 || process_ == 1) { add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 1, gamma, 2, gamma, -1))); add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 2, gamma, 1, gamma, -2))); } // gamma +jet if(process_==0 || process_ == 2) { add(new_ptr((Tree2toNDiagram(3), qk, qb, qb, 1, gamma, 2, g, -4))); add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 2, gamma, 1, g, -5))); add(new_ptr((Tree2toNDiagram(3), qk, qk, g, 1, gamma, 2, qk, -6))); add(new_ptr((Tree2toNDiagram(2), qk, g, 1, qk, 3, gamma, 3, qk, -7))); add(new_ptr((Tree2toNDiagram(3), g, qb, qb, 2, gamma, 1, qb, -8))); add(new_ptr((Tree2toNDiagram(2), g, qb, 1, qb, 3, gamma, 3, qb, -9))); } // gamma + jet + gamma if((process_==0 && contrib_==1) || process_ == 3) { // gamma + g + gamma if(threeBodyProcess_==0 || threeBodyProcess_==1) { add(new_ptr((Tree2toNDiagram(4), qk, qk, qk, qb, 1, gamma, 2, gamma, 3, g, -10))); add(new_ptr((Tree2toNDiagram(4), qk, qk, qk, qb, 3, gamma, 2, gamma, 1, g, -12))); } // Z + q + gamma if(threeBodyProcess_==0 || threeBodyProcess_==2) { add(new_ptr((Tree2toNDiagram(4),qk,qk,qk,g,1,gamma,2,gamma,3,qk, -20))); add(new_ptr((Tree2toNDiagram(4),qk,qk,qk,g,2,gamma,1,gamma,3,qk, -21))); add(new_ptr((Tree2toNDiagram(3),qk,qk,g,1,gamma,2,qk,5,gamma,5,qk,-22))); } // Z + qbar + gamma if(threeBodyProcess_==0 || threeBodyProcess_==3) { add(new_ptr((Tree2toNDiagram(4),g,qb,qb,qb,3,gamma,2,gamma,1,qb ,-30))); add(new_ptr((Tree2toNDiagram(4),g,qb,qb,qb,2,gamma,3,gamma,1,qb ,-31))); add(new_ptr((Tree2toNDiagram(3),g,qb,qb ,2,gamma,1,qb,5,gamma,5,qb,-32))); } } } } Energy2 MEPP2GammaGammaPowheg::scale() const { Energy2 scale; if(scaleChoice_==0) { Energy pt; if(meMomenta()[2].perp(meMomenta()[0].vect())>= meMomenta()[3].perp(meMomenta()[0].vect())){ pt = meMomenta()[2].perp(meMomenta()[0].vect()); } else { pt = meMomenta()[3].perp(meMomenta()[0].vect()); } scale = sqr(pt); } else if(scaleChoice_==1) { scale = sHat(); } return scalePreFactor_*scale; } int MEPP2GammaGammaPowheg::nDim() const { return HwMEBase::nDim() + ( contrib_>=1 ? 3 : 0 ); } bool MEPP2GammaGammaPowheg::generateKinematics(const double * r) { // radiative variables if(contrib_>=1) { zTilde_ = r[nDim()-1]; vTilde_ = r[nDim()-2]; phi_ = Constants::twopi*r[nDim()-3]; } // set the jacobian jacobian(1.0); // set up the momenta for ( int i = 2, N = meMomenta().size(); i < N; ++i ) meMomenta()[i] = Lorentz5Momentum(ZERO); // generate sHat Energy2 shat(sHat()); if(mePartonData().size()==5) { double eps = sqr(meMomenta()[2].mass())/shat; jacobian(jacobian()*(1.-eps)); shat *= eps+zTilde_*(1.-eps); } // momenta of the core process double ctmin = -1.0, ctmax = 1.0; Energy q = ZERO; try { q = SimplePhaseSpace:: getMagnitude(shat, meMomenta()[2].mass(), ZERO); } catch ( ImpossibleKinematics ) { return false; } Energy e = 0.5*sqrt(shat); Energy2 m22 = meMomenta()[2].mass2(); Energy2 e0e2 = 2.0*e*sqrt(sqr(q) + m22); Energy2 e1e2 = 2.0*e*sqrt(sqr(q) + m22); Energy2 e0e3 = 2.0*e*sqrt(sqr(q)); Energy2 e1e3 = 2.0*e*sqrt(sqr(q)); Energy2 pq = 2.0*e*q; if(mePartonData().size()==4) { Energy2 thmin = lastCuts().minTij(mePartonData()[0], mePartonData()[2]); if ( thmin > ZERO ) ctmax = min(ctmax, (e0e2 - m22 - thmin)/pq); thmin = lastCuts().minTij(mePartonData()[1], mePartonData()[2]); if ( thmin > ZERO ) ctmin = max(ctmin, (thmin + m22 - e1e2)/pq); thmin = lastCuts().minTij(mePartonData()[1], mePartonData()[3]); if ( thmin > ZERO ) ctmax = min(ctmax, (e1e3 - thmin)/pq); thmin = lastCuts().minTij(mePartonData()[0], mePartonData()[3]); if ( thmin > ZERO ) ctmin = max(ctmin, (thmin - e0e3)/pq); Energy ptmin = max(lastCuts().minKT(mePartonData()[2]), lastCuts().minKT(mePartonData()[3])); if ( ptmin > ZERO ) { double ctm = 1.0 - sqr(ptmin/q); if ( ctm <= 0.0 ) return false; ctmin = max(ctmin, -sqrt(ctm)); ctmax = min(ctmax, sqrt(ctm)); } double ymin2 = lastCuts().minYStar(mePartonData()[2]); double ymax2 = lastCuts().maxYStar(mePartonData()[2]); double ymin3 = lastCuts().minYStar(mePartonData()[3]); double ymax3 = lastCuts().maxYStar(mePartonData()[3]); double ytot = lastCuts().Y() + lastCuts().currentYHat(); if ( ymin2 + ytot > -0.9*Constants::MaxRapidity ) ctmin = max(ctmin, sqrt(sqr(q) + m22)*tanh(ymin2)/q); if ( ymax2 + ytot < 0.9*Constants::MaxRapidity ) ctmax = min(ctmax, sqrt(sqr(q) + m22)*tanh(ymax2)/q); if ( ymin3 + ytot > -0.9*Constants::MaxRapidity ) ctmax = min(ctmax, tanh(-ymin3)); if ( ymax3 + ytot < 0.9*Constants::MaxRapidity ) ctmin = max(ctmin, tanh(-ymax3)); if ( ctmin >= ctmax ) return false; } double cth = getCosTheta(ctmin, ctmax, r[0]); Energy pt = q*sqrt(1.0-sqr(cth)); phi(rnd(2.0*Constants::pi)); meMomenta()[2].setVect(Momentum3( pt*sin(phi()), pt*cos(phi()), q*cth)); meMomenta()[3].setVect(Momentum3(-pt*sin(phi()), -pt*cos(phi()), -q*cth)); meMomenta()[2].rescaleEnergy(); meMomenta()[3].rescaleEnergy(); // jacobian tHat(pq*cth + m22 - e0e2); uHat(m22 - shat - tHat()); jacobian(pq/shat*Constants::pi*jacobian()); // end for 2->2 processes if(mePartonData().size()==4) { vector out(2); out[0] = meMomenta()[2]; out[1] = meMomenta()[3]; tcPDVector tout(2); tout[0] = mePartonData()[2]; tout[1] = mePartonData()[3]; if ( !lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]) ) return false; return true; } // special for 2-3 processes pair x = make_pair(lastX1(),lastX2()); // partons pair partons = make_pair(mePartonData()[0],mePartonData()[1]); // If necessary swap the particle data objects so that // first beam gives the incoming quark if(lastPartons().first ->dataPtr()!=partons.first) { swap(x.first,x.second); } // use vTilde to select the dipole for emission // gamma gamma g processes if(mePartonData()[4]->id()==ParticleID::g) { if(vTilde_<=0.5) { dipole_ = IIQCD1; vTilde_ = 4.*vTilde_; } else { dipole_ = IIQCD2; vTilde_ = 4.*(vTilde_-0.25); } jacobian(2.*jacobian()); } // gamma gamma q processes else if(mePartonData()[4]->id()>0&&mePartonData()[4]->id()<6) { if(vTilde_<=1./3.) { dipole_ = IIQCD2; vTilde_ = 3.*vTilde_; } else if(vTilde_<=2./3.) { dipole_ = IFQED1; vTilde_ = 3.*vTilde_-1.; } else { dipole_ = FIQED1; vTilde_ = 3.*vTilde_-2.; } jacobian(3.*jacobian()); } // gamma gamma qbar processes else if(mePartonData()[4]->id()<0&&mePartonData()[4]->id()>-6) { if(vTilde_<=1./3.) { dipole_ = IIQCD1; vTilde_ = 3.*vTilde_; } else if(vTilde_<=2./3.) { dipole_ = IFQED2; vTilde_ = 3.*vTilde_-1.; } else { dipole_ = FIQED2; vTilde_ = 3.*vTilde_-2.; } jacobian(3.*jacobian()); } else { assert(false); } // initial-initial dipoles if(dipole_<=4) { double z = shat/sHat(); double vt = vTilde_*(1.-z); double vJac = 1.-z; Energy pT = sqrt(shat*vt*(1.-vt-z)/z); if(pT pnew(5); pnew [0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first, 0.5*rs*x.first,ZERO); pnew [1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second, 0.5*rs*x.second,ZERO) ; pnew [2] = meMomenta()[2]; pnew [3] = meMomenta()[3]; pnew [4] = Lorentz5Momentum(pT*cos(phi_),pT*sin(phi_), pT*sinh(rapidity), pT*cosh(rapidity), ZERO); pnew[4].rescaleEnergy(); Lorentz5Momentum K = pnew [0]+pnew [1]-pnew [4]; Lorentz5Momentum Kt = pcmf; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); for(unsigned int ix=2;ix<4;++ix) { pnew [ix].boost(blab); pnew [ix] = pnew [ix] - 2.*Ksum*(Ksum*pnew [ix])/Ksum2 +2*K*(Kt*pnew [ix])/K2; pnew[ix].rescaleEnergy(); } pcmf = Lorentz5Momentum(ZERO,ZERO, 0.5*rs*(x.first-x.second), 0.5*rs*(x.first+x.second)); pcmf.rescaleMass(); blab = pcmf.boostVector(); for(unsigned int ix=0;ix1e-20) { rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot.rotateX(Constants::pi); } if(abs(1.-q.e()/q.vect().mag())>1e-6) rot.boostZ(q.e()/q.vect().mag()); pin *= rot; if(pin.perp2()/GeV2>1e-20) { Boost trans = -1./pin.e()*pin.vect(); trans.setZ(0.); rot.boost(trans); } rot.invert(); Energy Q = sqrt(-q.m2()); meMomenta()[4] = rot*Lorentz5Momentum( 0.5*Q*xT*cos(phi_), 0.5*Q*xT*sin(phi_), -0.5*Q*x2,0.5*Q*sqrt(sqr(x2)+sqr(xT))); meMomenta()[3] = rot*Lorentz5Momentum(-0.5*Q*xT*cos(phi_),-0.5*Q*xT*sin(phi_), -0.5*Q*x3,0.5*Q*sqrt(sqr(x3)+sqr(xT))); double ratio; if(dipole_<=6) { ratio = 2.*((meMomenta()[3]+meMomenta()[4])*meMomenta()[0])/sHat(); } else { ratio = 2.*((meMomenta()[3]+meMomenta()[4])*meMomenta()[1])/sHat(); } jacobian(jacobian()*ratio); } else { assert(false); } vector out(3); tcPDVector tout(3); for(unsigned int ix=0;ix<3;++ix) { out[ix] = meMomenta() [2+ix]; tout[ix] = mePartonData()[2+ix]; } return lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]); } double MEPP2GammaGammaPowheg::me2() const { // Born configurations if(mePartonData().size()==4) { // gamma gamma core process if(mePartonData()[3]->id()==ParticleID::gamma) { return 2.*Constants::twopi*alphaEM_* loGammaGammaME(mePartonData(),meMomenta(),true); } // V jet core process else if(mePartonData()[3]->id()==ParticleID::g) { return 2.*Constants::twopi*alphaS_* loGammagME(mePartonData(),meMomenta(),true); } else if(mePartonData()[3]->id()>0) { return 2.*Constants::twopi*alphaS_* loGammaqME(mePartonData(),meMomenta(),true); } else if(mePartonData()[3]->id()<0) { return 2.*Constants::twopi*alphaS_* loGammaqbarME(mePartonData(),meMomenta(),true); } else assert(false); } // hard emission configurations else { if(mePartonData()[4]->id()==ParticleID::g) return sHat()*realGammaGammagME (mePartonData(),meMomenta(),dipole_,Hard,true); else if(mePartonData()[4]->id()>0&&mePartonData()[4]->id()<6) return sHat()*realGammaGammaqME (mePartonData(),meMomenta(),dipole_,Hard,true); else if(mePartonData()[4]->id()<0&&mePartonData()[4]->id()>-6) return sHat()*realGammaGammaqbarME(mePartonData(),meMomenta(),dipole_,Hard,true); else assert(false); } } CrossSection MEPP2GammaGammaPowheg::dSigHatDR() const { // couplings if(!fixedAlphaS_) alphaS_ = SM().alphaS(scale()); alphaEM_ = SM().alphaEM(); // cross section CrossSection preFactor = jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc); loME_ = me2(); if( contrib_== 0 || mePartonData().size()==5 || (mePartonData().size()==4&& mePartonData()[3]->coloured())) return loME_*preFactor; else return NLOWeight()*preFactor; } Selector MEPP2GammaGammaPowheg::diagrams(const DiagramVector & diags) const { if(mePartonData().size()==4) { if(mePartonData()[3]->id()==ParticleID::gamma) { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ){ sel.insert(meInfo()[abs(diags[i]->id())], i); } return sel; } else { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ){ sel.insert(meInfo()[abs(diags[i]->id())%2], i); } return sel; } } else { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { if(abs(diags[i]->id()) == 10 && dipole_ == IIQCD2 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 12 && dipole_ == IIQCD1 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 20 && dipole_ == IIQCD2 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 21 && dipole_ == IFQED1 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 22 && dipole_ == FIQED1 ) sel.insert(1., i); else sel.insert(0., i); } return sel; } } Selector MEPP2GammaGammaPowheg::colourGeometries(tcDiagPtr diag) const { // colour lines for V gamma static ColourLines cs("1 -2"); static ColourLines ct("1 2 -3"); // colour lines for q qbar -> V g static const ColourLines cqqbar[2]={ColourLines("1 -2 5,-3 -5"), ColourLines("1 5,-5 2 -3")}; // colour lines for q g -> V q static const ColourLines cqg [2]={ColourLines("1 2 -3,3 5"), ColourLines("1 -2,2 3 5")}; // colour lines for g qbar -> V qbar static const ColourLines cgqbar[2]={ColourLines("-3 -2 1,-1 -5"), ColourLines("-2 1,-1 -3 -5")}; // colour lines for q qbar -> V gamma g static const ColourLines cqqbarg[4]={ColourLines("1 2 3 7,-4 -7"), ColourLines("1 2 7,-4 3 -7"), ColourLines("1 7,-4 3 2 -7"), ColourLines("1 2 7,-4 3 -7")}; // colour lines for q g -> V gamma q static const ColourLines cqgq [3]={ColourLines("1 2 3 -4,4 7"), ColourLines("1 2 3 -4,4 7"), ColourLines("1 2 -3,3 5 7")}; // colour lines for gbar -> V gamma qbar static const ColourLines cqbargqbar[3]={ColourLines("1 -2 -3 -4,-1 -7"), ColourLines("1 -2 -3 -4,-1 -7"), ColourLines("1 -2 -3,-1 -5 -7")}; Selector sel; switch(abs(diag->id())) { case 1 :case 2 : sel.insert(1.0, &ct); break; case 3 : sel.insert(1.0, &cs); break; case 4 : sel.insert(1.0, &cqqbar[0]); break; case 5: sel.insert(1.0, &cqqbar[1]); break; case 6: sel.insert(1.0, &cqg[0]); break; case 7: sel.insert(1.0, &cqg[1]); break; case 8: sel.insert(1.0, &cgqbar[0]); break; case 9: sel.insert(1.0, &cgqbar[1]); break; case 10: case 11: case 12: case 13: sel.insert(1.0, &cqqbarg[abs(diag->id())-10]); break; case 20: case 21: case 22: sel.insert(1.0, &cqgq[abs(diag->id())-20]); break; case 30: case 31: case 32: sel.insert(1.0, &cqbargqbar[abs(diag->id())-30]); break; default: assert(false); } return sel; } void MEPP2GammaGammaPowheg::persistentOutput(PersistentOStream & os) const { os << FFPvertex_ << FFGvertex_ << contrib_ << power_ << gluon_ << prefactor_ << process_ << threeBodyProcess_<< maxflavour_ << alphaS_ << fixedAlphaS_ << supressionFunction_ << supressionScale_ << ounit(lambda_,GeV) << alphaQCD_ << alphaQED_ << ounit(minpT_,GeV) << preQCDqqbarq_ << preQCDqqbarqbar_ << preQCDqg_ << preQCDgqbar_ << preQEDqqbarq_ << preQEDqqbarqbar_ << preQEDqgq_ << preQEDgqbarqbar_ << scaleChoice_ << scalePreFactor_; } void MEPP2GammaGammaPowheg::persistentInput(PersistentIStream & is, int) { is >> FFPvertex_ >> FFGvertex_ >> contrib_ >> power_ >> gluon_ >> prefactor_ >> process_ >> threeBodyProcess_ >> maxflavour_ >> alphaS_ >> fixedAlphaS_ >> supressionFunction_ >> supressionScale_ >> iunit(lambda_,GeV) >> alphaQCD_ >> alphaQED_ >> iunit(minpT_,GeV) >> preQCDqqbarq_ >> preQCDqqbarqbar_ >> preQCDqg_ >> preQCDgqbar_ >> preQEDqqbarq_ >> preQEDqqbarqbar_ >> preQEDqgq_ >> preQEDgqbarqbar_ >> scaleChoice_ >> scalePreFactor_; } void MEPP2GammaGammaPowheg::Init() { static ClassDocumentation documentation ("TheMEPP2GammaGammaPowheg class implements gamma gamma production at NLO"); static Switch interfaceProcess ("Process", "Which processes to include", &MEPP2GammaGammaPowheg::process_, 0, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all the processes", 0); static SwitchOption interfaceProcessGammaGamma (interfaceProcess, "GammaGamma", "Only include gamma gamma", 1); static SwitchOption interfaceProcessVJet (interfaceProcess, "VJet", "Only include gamma + jet", 2); static SwitchOption interfaceProcessHard (interfaceProcess, "Hard", "Only include hard radiation contributions", 3); static Switch interfaceThreeBodyProcess ("ThreeBodyProcess", "The possible three body processes to include", &MEPP2GammaGammaPowheg::threeBodyProcess_, 0, false, false); static SwitchOption interfaceThreeBodyProcessAll (interfaceThreeBodyProcess, "All", "Include all processes", 0); static SwitchOption interfaceThreeBodyProcessqqbar (interfaceThreeBodyProcess, "qqbar", "Only include q qbar -> gamma gamma g processes", 1); static SwitchOption interfaceThreeBodyProcessqg (interfaceThreeBodyProcess, "qg", "Only include q g -> gamma gamma q processes", 2); static SwitchOption interfaceThreeBodyProcessgqbar (interfaceThreeBodyProcess, "gqbar", "Only include g qbar -> gamma gamma qbar processes", 3); static Switch interfaceContribution ("Contribution", "Which contributions to the cross section to include", &MEPP2GammaGammaPowheg::contrib_, 1, false, false); static SwitchOption interfaceContributionLeadingOrder (interfaceContribution, "LeadingOrder", "Just generate the leading order cross section", 0); static SwitchOption interfaceContributionPositiveNLO (interfaceContribution, "PositiveNLO", "Generate the positive contribution to the full NLO cross section", 1); static SwitchOption interfaceContributionNegativeNLO (interfaceContribution, "NegativeNLO", "Generate the negative contribution to the full NLO cross section", 2); static Parameter interfaceMaximumFlavour ("MaximumFlavour", "The maximum flavour allowed for the incoming quarks", &MEPP2GammaGammaPowheg::maxflavour_, 5, 1, 5, false, false, Interface::limited); static Parameter interfaceAlphaS ("AlphaS", "The value of alphaS to use if using a fixed alphaS", &MEPP2GammaGammaPowheg::alphaS_, 0.118, 0.0, 0.2, false, false, Interface::limited); static Switch interfaceFixedAlphaS ("FixedAlphaS", "Use a fixed value of alphaS", &MEPP2GammaGammaPowheg::fixedAlphaS_, false, false, false); static SwitchOption interfaceFixedAlphaSYes (interfaceFixedAlphaS, "Yes", "Use a fixed alphaS", true); static SwitchOption interfaceFixedAlphaSNo (interfaceFixedAlphaS, "No", "Use a running alphaS", false); static Switch interfaceSupressionFunction ("SupressionFunction", "Choice of the supression function", &MEPP2GammaGammaPowheg::supressionFunction_, 0, false, false); static SwitchOption interfaceSupressionFunctionNone (interfaceSupressionFunction, "None", "Default POWHEG approach", 0); static SwitchOption interfaceSupressionFunctionThetaFunction (interfaceSupressionFunction, "ThetaFunction", "Use theta functions at scale Lambda", 1); static SwitchOption interfaceSupressionFunctionSmooth (interfaceSupressionFunction, "Smooth", "Supress high pT by pt^2/(pt^2+lambda^2)", 2); static Parameter interfaceSupressionScale ("SupressionScale", "The square of the scale for the supression function", &MEPP2GammaGammaPowheg::lambda_, GeV, 20.0*GeV, 0.0*GeV, 0*GeV, false, false, Interface::lowerlim); static Switch interfaceSupressionScaleChoice ("SupressionScaleChoice", "Choice of the supression scale", &MEPP2GammaGammaPowheg::supressionScale_, 0, false, false); static SwitchOption interfaceSupressionScaleChoiceFixed (interfaceSupressionScaleChoice, "Fixed", "Use a fixed scale", 0); static SwitchOption interfaceSupressionScaleChoiceVariable (interfaceSupressionScaleChoice, "Variable", "Use the pT of the hard process as the scale", 1); static Reference interfaceShowerAlphaQCD ("ShowerAlphaQCD", "Reference to the object calculating the QCD coupling for the shower", &MEPP2GammaGammaPowheg::alphaQCD_, false, false, true, false, false); static Reference interfaceShowerAlphaQED ("ShowerAlphaQED", "Reference to the object calculating the QED coupling for the shower", &MEPP2GammaGammaPowheg::alphaQED_, false, false, true, false, false); static Parameter interfacepreQCDqqbarq ("preQCDqqbarq", "The constant for the Sudakov overestimate for the " "q qbar -> V Gamma +g with emission from the q", &MEPP2GammaGammaPowheg::preQCDqqbarq_, 23.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacepreQCDqqbarqbar ("preQCDqqbarqbar", "The constant for the Sudakov overestimate for the " "q qbar -> V Gamma +g with emission from the qbar", &MEPP2GammaGammaPowheg::preQCDqqbarqbar_, 23.0, 0.0, 1000.0, false, false, Interface::limited); static Switch interfaceScaleChoice ("ScaleChoice", "The scale choice to use", &MEPP2GammaGammaPowheg::scaleChoice_, 0, false, false); static SwitchOption interfaceScaleChoicepT (interfaceScaleChoice, "pT", "Use the pT of the photons", 0); static SwitchOption interfaceScaleChoiceMGammaGamma (interfaceScaleChoice, "MGammaGamma", "Use the mass of the photon pair", 1); static Parameter interfaceScalePreFactor ("ScalePreFactor", "Prefactor to change factorization/renormalisation scale", &MEPP2GammaGammaPowheg::scalePreFactor_, 1.0, 0.1, 10.0, false, false, Interface::limited); // prefactor_.push_back(preQCDqg_); // prefactor_.push_back(preQCDgqbar_); // prefactor_.push_back(preQEDqqbarq_); // prefactor_.push_back(preQEDqqbarqbar_); // prefactor_.push_back(preQEDqgq_); // prefactor_.push_back(preQEDgqbarqbar_); } double MEPP2GammaGammaPowheg::NLOWeight() const { // if leading-order return if(contrib_==0) return loME_; // prefactors CFfact_ = 4./3.*alphaS_/Constants::twopi; TRfact_ = 1./2.*alphaS_/Constants::twopi; // scale Energy2 mu2 = scale(); // virtual pieces double virt = CFfact_*subtractedVirtual(); // extract the partons and stuff for the real emission // and collinear counter terms // hadrons pair hadrons= make_pair(dynamic_ptr_cast(lastParticles().first->dataPtr() ), dynamic_ptr_cast(lastParticles().second->dataPtr())); // momentum fractions pair x = make_pair(lastX1(),lastX2()); // partons pair partons = make_pair(mePartonData()[0],mePartonData()[1]); // If necessary swap the particle data objects so that // first beam gives the incoming quark if(lastPartons().first ->dataPtr()!=partons.first) { swap(x.first,x.second); swap(hadrons.first,hadrons.second); } // convert the values of z tilde to z pair z; pair zJac; double rhomax(pow(1.-x.first,1.-power_)); double rho = zTilde_*rhomax; z.first = 1.-pow(rho,1./(1.-power_)); zJac.first = rhomax*pow(1.-z.first,power_)/(1.-power_); rhomax = pow(1.-x.second,1.-power_); rho = zTilde_*rhomax; z.second = 1.-pow(rho,1./(1.-power_)); zJac.second = rhomax*pow(1.-z.second,power_)/(1.-power_); // calculate the PDFs pair oldqPDF = make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,partons.first ,scale(), x.first )/x.first , hadrons.second->pdf()->xfx(hadrons.second,partons.second,scale(), x.second)/x.second); // real/coll q/qbar pair newqPDF = make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,partons.first ,scale(), x.first /z.first )*z.first /x.first , hadrons.second->pdf()->xfx(hadrons.second,partons.second,scale(), x.second/z.second)*z.second/x.second); // real/coll gluon pair newgPDF = make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,gluon_,scale(), x.first /z.first )*z.first /x.first , hadrons.second->pdf()->xfx(hadrons.second,gluon_,scale(), x.second/z.second)*z.second/x.second); // coll terms // g -> q double collGQ = collinearGluon(mu2,zJac.first,z.first, oldqPDF.first,newgPDF.first); // g -> qbar double collGQbar = collinearGluon(mu2,zJac.second,z.second, oldqPDF.second,newgPDF.second); // q -> q double collQQ = collinearQuark(x.first ,mu2,zJac.first ,z.first , oldqPDF.first ,newqPDF.first ); // qbar -> qbar double collQbarQbar = collinearQuark(x.second,mu2,zJac.second,z.second, oldqPDF.second,newqPDF.second); // collinear remnants double coll = collQQ+collQbarQbar+collGQ+collGQbar; // real emission contribution double real1 = subtractedReal(x,z. first,zJac. first,oldqPDF. first, newqPDF. first,newgPDF. first, true); double real2 = subtractedReal(x,z.second,zJac.second,oldqPDF.second, newqPDF.second,newgPDF.second,false); // the total weight double wgt = loME_ + loME_*virt + loME_*coll + real1 + real2; return contrib_ == 1 ? max(0.,wgt) : max(0.,-wgt); } double MEPP2GammaGammaPowheg::loGammaGammaME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 th = (momenta[0]-momenta[2]).m2(); Energy2 uh = (momenta[0]-momenta[3]).m2(); output = 4./3.*Constants::pi*SM().alphaEM(ZERO)*(th/uh+uh/th)* pow(double(particles[0]->iCharge())/3.,4); } // HE code result else { // wavefunctions for the incoming fermions SpinorWaveFunction em_in( momenta[0],particles[0],incoming); SpinorBarWaveFunction ep_in( momenta[1],particles[1],incoming); // wavefunctions for the outgoing bosons VectorWaveFunction v1_out(momenta[2],particles[2],outgoing); VectorWaveFunction v2_out(momenta[3],particles[3],outgoing); vector f1; vector a1; vector v1,v2; // calculate the wavefunctions for(unsigned int ix=0;ix<2;++ix) { em_in.reset(ix); f1.push_back(em_in); ep_in.reset(ix); a1.push_back(ep_in); v1_out.reset(2*ix); v1.push_back(v1_out); v2_out.reset(2*ix); v2.push_back(v2_out); } vector me(4,0.0); me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1,PDT::Spin1)); vector diag(2,0.0); SpinorWaveFunction inter; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { for(unsigned int ohel2=0;ohel2<2;++ohel2) { inter = FFPvertex_->evaluate(ZERO,5,f1[ihel1].particle(), f1[ihel1],v1[ohel1]); diag[0] = FFPvertex_->evaluate(ZERO,inter,a1[ihel2],v2[ohel2]); inter = FFPvertex_->evaluate(ZERO,5,f1[ihel1].particle(), f1[ihel1] ,v2[ohel2]); diag[1] = FFPvertex_->evaluate(ZERO,inter,a1[ihel2],v1[ohel1]); // individual diagrams for (size_t ii=0; ii<2; ++ii) me[ii] += std::norm(diag[ii]); // full matrix element diag[0] += diag[1]; output += std::norm(diag[0]); // storage of the matrix element for spin correlations me_(ihel1,ihel2,2*ohel1,2*ohel2) = diag[0]; } } } } // store diagram info, etc. DVector save(3); for (size_t i = 0; i < 3; ++i) save[i] = 0.25 * me[i]; meInfo(save); // spin and colour factors output *= 0.125/3./norm(FFPvertex_->norm()); } return output; } double MEPP2GammaGammaPowheg::loGammaqME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 sh = (momenta[0]+momenta[1]).m2(); Energy2 th = (momenta[0]-momenta[2]).m2(); Energy2 uh = (momenta[0]-momenta[3]).m2(); output = -1./3./sh/th*(sh*sh+th*th+2.*uh*(sh+th+uh))* 4.*Constants::pi*SM().alphaEM(ZERO)* sqr(particles[0]->iCharge()/3.); } // HE result else { vector fin; vector gin; vector fout; vector vout; SpinorWaveFunction qin (momenta[0],particles[0],incoming); VectorWaveFunction glin(momenta[1],particles[1],incoming); VectorWaveFunction wout(momenta[2],particles[2],outgoing); SpinorBarWaveFunction qout(momenta[3],particles[3],outgoing); // polarization states for the particles for(unsigned int ix=0;ix<2;++ix) { qin.reset(ix) ; fin.push_back(qin); qout.reset(ix); fout.push_back(qout); glin.reset(2*ix); gin.push_back(glin); wout.reset(2*ix); vout.push_back(wout); } me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, PDT::Spin1,PDT::Spin1Half)); // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams interb= FFGvertex_->evaluate(scale(),5,particles[3], fout[ohel1],gin[ihel2]); inters= FFGvertex_->evaluate(scale(),5,particles[0], fin[ihel1],gin[ihel2]); for(unsigned int vhel=0;vhel<2;++vhel) { diag[0] = FFPvertex_->evaluate(ZERO,fin[ihel1],interb,vout[vhel]); diag[1] = FFPvertex_->evaluate(ZERO,inters,fout[ohel1],vout[vhel]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); me_(ihel1,2*ihel2,2*vhel,ohel1) = diag[0]; } } } } // results // initial state spin and colour average double colspin = 1./24./4.; // and C_F N_c from matrix element colspin *= 4.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); output = me[0]/norm(FFGvertex_->norm()); } return output; } double MEPP2GammaGammaPowheg::loGammaqbarME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 sh = (momenta[0]+momenta[1]).m2(); Energy2 uh = (momenta[0]-momenta[2]).m2(); Energy2 th = (momenta[0]-momenta[3]).m2(); output = -1./3./sh/th*(sh*sh+th*th+2.*uh*(sh+th+uh))* 4.*Constants::pi*SM().alphaEM()* sqr(particles[1]->iCharge()/3.); } // HE result else { vector ain; vector gin; vector aout; vector vout; VectorWaveFunction glin (momenta[0],particles[0],incoming); SpinorBarWaveFunction qbin (momenta[1],particles[1],incoming); VectorWaveFunction wout (momenta[2],particles[2],outgoing); SpinorWaveFunction qbout(momenta[3],particles[3],outgoing); // polarization states for the particles for(unsigned int ix=0;ix<2;++ix) { qbin .reset(ix ); ain .push_back(qbin ); qbout.reset(ix ); aout.push_back(qbout); glin.reset(2*ix); gin.push_back(glin); wout.reset(2*ix); vout.push_back(wout); } // if calculation spin corrections construct the me me_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1Half, PDT::Spin1,PDT::Spin1Half)); // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams inters= FFGvertex_->evaluate(scale(),5,particles[3], aout[ohel1],gin[ihel1]); interb= FFGvertex_->evaluate(scale(),5,particles[1], ain[ihel2],gin[ihel1]); for(unsigned int vhel=0;vhel<2;++vhel) { diag[0]= FFPvertex_->evaluate(ZERO,inters,ain[ihel2],vout[vhel]); diag[1]= FFPvertex_->evaluate(ZERO,aout[ohel1],interb,vout[vhel]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); me_(2*ihel1,ihel2,2*vhel,ohel1) = diag[0]; } } } } // results // initial state spin and colour average double colspin = 1./24./4.; // and C_F N_c from matrix element colspin *= 4.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); output = me[0]/norm(FFGvertex_->norm()); } return output; } double MEPP2GammaGammaPowheg::loGammagME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 uh = (momenta[0]-momenta[2]).m2(); Energy2 th = (momenta[0]-momenta[3]).m2(); output = 8./9.*double((th*th+uh*uh)/uh/th)* 4.*Constants::pi*SM().alphaEM(ZERO)* sqr(particles[0]->iCharge()/3.); } else { vector fin; vector ain; vector gout; vector vout; SpinorWaveFunction qin (momenta[0],particles[0],incoming); SpinorBarWaveFunction qbin(momenta[1],particles[1],incoming); VectorWaveFunction wout(momenta[2],particles[2],outgoing); VectorWaveFunction glout(momenta[3],particles[3],outgoing); // polarization states for the particles for(unsigned int ix=0;ix<2;++ix) { qin.reset(ix) ; fin.push_back(qin); qbin.reset(ix) ; ain.push_back(qbin); glout.reset(2*ix); gout.push_back(glout); wout.reset(2*ix); vout.push_back(wout); } // if calculation spin corrections construct the me if(first) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1,PDT::Spin1)); // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams inters= FFGvertex_->evaluate(scale(),5,particles[0], fin[ihel1],gout[ohel1]); interb= FFGvertex_->evaluate(scale(),5,particles[1], ain[ihel2],gout[ohel1]); for(unsigned int vhel=0;vhel<2;++vhel) { diag[0]= FFPvertex_->evaluate(ZERO,fin[ihel1],interb,vout[vhel]); diag[1]= FFPvertex_->evaluate(ZERO,inters,ain[ihel2],vout[vhel]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); if(first) me_(ihel1,ihel2,vhel,2*ohel1) = diag[0]; } } } } // results // initial state spin and colour average double colspin = 1./9./4.; // and C_F N_c from matrix element colspin *= 4.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); output = me[0]/norm(FFGvertex_->norm()); } return output; } InvEnergy2 MEPP2GammaGammaPowheg:: realGammaGammagME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool ) const { // matrix element double sum = realME(particles,momenta); // loop over the QCD and QCD dipoles InvEnergy2 dipoles[2]; pair supress[2]; // compute the two dipole terms unsigned int iemit = 4, ihard = 3; double x = (momenta[0]*momenta[1]-momenta[iemit]*momenta[1]- momenta[iemit]*momenta[0])/(momenta[0]*momenta[1]); Lorentz5Momentum Kt = momenta[0]+momenta[1]-momenta[iemit]; vector pa(4),pb(4); // momenta for q -> q g/gamma emission pa[0] = x*momenta[0]; pa[1] = momenta[1]; Lorentz5Momentum K = pa[0]+pa[1]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); pa[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pa[2].setMass(momenta[2].mass()); pa[3] = momenta[ihard] -2.*Ksum*(Ksum*momenta[ihard])/Ksum2+2*K*(Kt*momenta[ihard])/K2; pa[3].setMass(ZERO); cPDVector part(particles.begin(),--particles.end()); part[3] = particles[ihard]; // first leading-order matrix element double lo1 = loGammaGammaME(part,pa); // first dipole dipoles[0] = 1./(momenta[0]*momenta[iemit])/x*(2./(1.-x)-(1.+x))*lo1; supress[0] = supressionFunction(momenta[iemit].perp(),pa[3].perp()); // momenta for qbar -> qbar g/gamma emission pb[0] = momenta[0]; pb[1] = x*momenta[1]; K = pb[0]+pb[1]; Ksum = K+Kt; K2 = K.m2(); Ksum2 = Ksum.m2(); pb[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pb[2].setMass(momenta[2].mass()); pb[3] = momenta[ihard] -2.*Ksum*(Ksum*momenta[ihard])/Ksum2+2*K*(Kt*momenta[ihard])/K2; pb[3].setMass(ZERO); // second LO matrix element double lo2 = loGammaGammaME(part,pb); // second dipole dipoles[1] = 1./(momenta[1]*momenta[iemit])/x*(2./(1.-x)-(1.+x))*lo2; supress[1] = supressionFunction(momenta[iemit].perp(),pb[3].perp()); for(unsigned int ix=0;ix<2;++ix) dipoles[ix] *= 4./3.; // denominator for the matrix element InvEnergy2 denom = abs(dipoles[0]) + abs(dipoles[1]); // contribution if( denom==ZERO || dipoles[(dipole-1)/2]==ZERO ) return ZERO; sum *= abs(dipoles[(dipole-1)/2])/denom; // final coupling factors InvEnergy2 output; if(rad==Subtraction) { output = alphaS_*alphaEM_* (sum*UnitRemoval::InvE2*supress[(dipole-1)/2].first - dipoles[(dipole-1)/2]); } else { output = alphaS_*alphaEM_*sum*UnitRemoval::InvE2; if(rad==Hard) output *=supress[(dipole-1)/2].second; else if(rad==Shower) output *=supress[(dipole-1)/2].first ; } return output; } InvEnergy2 MEPP2GammaGammaPowheg::realGammaGammaqME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool ) const { double sum = realME(particles,momenta); // initial-state QCD dipole double x = (momenta[0]*momenta[1]-momenta[4]*momenta[1]- momenta[4]*momenta[0])/(momenta[0]*momenta[1]); Lorentz5Momentum Kt = momenta[0]+momenta[1]-momenta[4]; vector pa(4); pa[0] = momenta[0]; pa[1] = x*momenta[1]; Lorentz5Momentum K = pa[0]+pa[1]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); pa[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pa[2].setMass(momenta[2].mass()); pa[3] = momenta[3] -2.*Ksum*(Ksum*momenta[3])/Ksum2+2*K*(Kt*momenta[3])/K2; pa[3].setMass(ZERO); cPDVector part(particles.begin(),--particles.end()); part[1] = particles[4]->CC(); double lo1 = loGammaGammaME(part,pa); InvEnergy2 D1 = 0.5/(momenta[1]*momenta[4])/x*(1.-2.*x*(1.-x))*lo1; // initial-final QED dipole vector pb(4); x = 1.-(momenta[3]*momenta[4])/(momenta[4]*momenta[0]+momenta[0]*momenta[3]); pb[3] = momenta[4]+momenta[3]-(1.-x)*momenta[0]; pb[0] = x*momenta[0]; pb[1] = momenta[1]; pb[2] = momenta[2]; double z = momenta[0]*momenta[3]/(momenta[0]*momenta[3]+momenta[0]*momenta[4]); part[1] = particles[1]; part[3] = particles[4]; double lo2 = loGammaqME(part,pb); Energy pT = sqrt(-(pb[0]-pb[3]).m2()*(1.-x)*(1.-z)*z/x); InvEnergy2 DF = 1./(momenta[4]*momenta[3])/x*(1./(1.-x+z)-2.+z)*lo2; InvEnergy2 DI = 1./(momenta[0]*momenta[3])/x*(1./(1.-x+z)-1.-x)*lo2; DI *= sqr(double(particles[0]->iCharge())/3.); DF *= sqr(double(particles[0]->iCharge())/3.); InvEnergy2 denom = abs(D1)+abs(DI)+abs(DF); pair supress; InvEnergy2 term; if ( dipole == IFQED1 ) { term = DI; supress = supressionFunction(pT,pb[3].perp()); } else if( dipole == FIQED1 ) { term = DF; supress = supressionFunction(pT,pb[3].perp()); } else { term = D1; supress = supressionFunction(momenta[4].perp(),pa[3].perp()); } if( denom==ZERO || term == ZERO ) return ZERO; sum *= abs(term)/denom; // final coupling factors InvEnergy2 output; if(rad==Subtraction) { output = alphaS_*alphaEM_* (sum*UnitRemoval::InvE2*supress.first - term); } else { output = alphaS_*alphaEM_*sum*UnitRemoval::InvE2; if(rad==Hard) output *= supress.second; else if(rad==Shower) output *= supress.first ; } // final coupling factors return output; } InvEnergy2 MEPP2GammaGammaPowheg:: realGammaGammaqbarME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool) const { double sum = realME(particles,momenta); // initial-state QCD dipole double x = (momenta[0]*momenta[1]-momenta[4]*momenta[1]-momenta[4]*momenta[0])/ (momenta[0]*momenta[1]); Lorentz5Momentum Kt = momenta[0]+momenta[1]-momenta[4]; vector pa(4); pa[0] = x*momenta[0]; pa[1] = momenta[1]; Lorentz5Momentum K = pa[0]+pa[1]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); pa[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pa[2].setMass(momenta[2].mass()); pa[3] = momenta[3] -2.*Ksum*(Ksum*momenta[3])/Ksum2+2*K*(Kt*momenta[3])/K2; pa[3].setMass(ZERO); cPDVector part(particles.begin(),--particles.end()); part[0] = particles[4]->CC(); double lo1 = loGammaGammaME(part,pa); InvEnergy2 D1 = 0.5/(momenta[0]*momenta[4])/x*(1.-2.*x*(1.-x))*lo1; // initial-final QED dipole vector pb(4); x = 1.-(momenta[3]*momenta[4])/(momenta[4]*momenta[1]+momenta[1]*momenta[3]); pb[3] = momenta[4]+momenta[3]-(1.-x)*momenta[1]; pb[0] = momenta[0]; pb[1] = x*momenta[1]; pb[2] = momenta[2]; double z = momenta[1]*momenta[3]/(momenta[1]*momenta[3]+momenta[1]*momenta[4]); part[0] = particles[0]; part[3] = particles[4]; double lo2 = loGammaqbarME(part,pb); Energy pT = sqrt(-(pb[1]-pb[3]).m2()*(1.-x)*(1.-z)*z/x); InvEnergy2 DF = 1./(momenta[4]*momenta[3])/x*(2./(1.-x+z)-2.+z)*lo2; InvEnergy2 DI = 1./(momenta[0]*momenta[3])/x*(2./(1.-x+z)-1.-x)*lo2; InvEnergy2 term; DI *= sqr(double(particles[1]->iCharge())/3.); DF *= sqr(double(particles[1]->iCharge())/3.); InvEnergy2 denom = abs(D1)+abs(DI)+abs(DF); pair supress; if ( dipole == IFQED2 ) { term = DI; supress = supressionFunction(pT,pb[3].perp()); } else if( dipole == FIQED2 ) { term = DF; supress = supressionFunction(pT,pb[3].perp()); } else { term = D1; supress = supressionFunction(momenta[4].perp(),pa[3].perp()); } if( denom==ZERO || dipole==ZERO ) return ZERO; sum *= abs(term)/denom; // final coupling factors InvEnergy2 output; if(rad==Subtraction) { output = alphaS_*alphaEM_* (sum*UnitRemoval::InvE2*supress.first - term); } else { output = alphaS_*alphaEM_*sum*UnitRemoval::InvE2; if(rad==Hard) output *= supress.second; else if(rad==Shower) output *= supress.first ; } // final coupling factors return output; } double MEPP2GammaGammaPowheg:: realME(const cPDVector & particles, const vector & momenta) const { vector qin; vector qbarin; vector wout,pout,gout; SpinorWaveFunction q_in; SpinorBarWaveFunction qbar_in; VectorWaveFunction g_out; VectorWaveFunction v_out (momenta[2],particles[2],outgoing); VectorWaveFunction p_out (momenta[3],particles[3],outgoing); // q qbar -> gamma gamma g if(particles[4]->id()==ParticleID::g) { q_in = SpinorWaveFunction (momenta[0],particles[0],incoming); qbar_in = SpinorBarWaveFunction (momenta[1],particles[1],incoming); g_out = VectorWaveFunction (momenta[4],particles[4],outgoing); } // q g -> gamma gamma q else if(particles[4]->id()>0) { q_in = SpinorWaveFunction (momenta[0],particles[0],incoming); qbar_in = SpinorBarWaveFunction (momenta[4],particles[4],outgoing); g_out = VectorWaveFunction (momenta[1],particles[1],incoming); } else if(particles[4]->id()<0) { q_in = SpinorWaveFunction (momenta[4],particles[4],outgoing); qbar_in = SpinorBarWaveFunction (momenta[1],particles[1],incoming); g_out = VectorWaveFunction (momenta[0],particles[0],incoming); } else assert(false); for(unsigned int ix=0;ix<2;++ix) { q_in.reset(ix); qin.push_back(q_in); qbar_in.reset(ix); qbarin.push_back(qbar_in); g_out.reset(2*ix); gout.push_back(g_out); p_out.reset(2*ix); pout.push_back(p_out); v_out.reset(2*ix); wout.push_back(v_out); } vector diag(6 , 0.); Energy2 mu2 = scale(); double sum(0.); for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int whel=0;whel<2;++whel) { for(unsigned int phel=0;phel<2;++phel) { for(unsigned int ghel=0;ghel<2;++ghel) { // first diagram SpinorWaveFunction inters1 = FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle(),qin[ihel1],pout[phel]); SpinorBarWaveFunction inters2 = FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle()->CC(), qbarin[ihel2],wout[whel]); diag[0] = FFGvertex_->evaluate(mu2,inters1,inters2,gout[ghel]); // second diagram SpinorWaveFunction inters3 = FFGvertex_->evaluate(mu2,5,qin[ihel1].particle(),qin[ihel1],gout[ghel]); SpinorBarWaveFunction inters4 = FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle(), qbarin[ihel2],pout[phel]); diag[1] = FFPvertex_->evaluate(ZERO,inters3,inters4,wout[whel]); // fourth diagram diag[2] = FFPvertex_->evaluate(ZERO,inters3,inters2,pout[phel]); // fifth diagram SpinorBarWaveFunction inters5 = FFGvertex_->evaluate(mu2,5,qbarin[ihel2].particle(), qbarin[ihel2],gout[ghel]); diag[3] = FFPvertex_->evaluate(ZERO,inters1,inters5,wout[whel]); // sixth diagram SpinorWaveFunction inters6 = FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle()->CC(), qin[ihel1],wout[whel]); diag[4] = FFGvertex_->evaluate(mu2,inters6,inters4,gout[ghel]); // eighth diagram diag[5] = FFPvertex_->evaluate(ZERO,inters6,inters5,pout[phel]); // sum Complex dsum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); sum += norm(dsum); } } } } } // divide out the em and strong couplings sum /= norm(FFGvertex_->norm()*FFPvertex_->norm()); // final spin and colour factors spin = 1/4 colour = 4/9 if(particles[4]->id()==ParticleID::g) sum /= 9.; // final spin and colour factors spin = 1/4 colour = 4/(3*8) else sum /= 24.; // finally identical particle factor return 0.5*sum; } double MEPP2GammaGammaPowheg::subtractedVirtual() const { double v = 1+tHat()/sHat(); double born = (1-v)/v+v/(1-v); double finite_term = born* (2./3.*sqr(Constants::pi)-3.+sqr(log(v))+sqr(log(1-v))+3.*log(1-v))+ 2.+2.*log(v)+2.*log(1-v)+3.*(1-v)/v*(log(v)-log(1-v))+ (2.+v/(1-v))*sqr(log(v))+(2.+(1-v)/v)*sqr(log(1-v)); double virt = ((6.-(2./3.)*sqr(Constants::pi))* born-2.+finite_term); return virt/born; } double MEPP2GammaGammaPowheg::subtractedReal(pair x, double z, double zJac, double oldqPDF, double newqPDF, double newgPDF,bool order) const { double vt = vTilde_*(1.-z); double vJac = 1.-z; Energy pT = sqrt(sHat()*vt*(1.-vt-z)/z); // rapidities double rapidity; if(order) { rapidity = -log(x.second*sqrt(lastS())/pT*vt); } else { rapidity = log(x.first *sqrt(lastS())/pT*vt); } // CMS system Energy rs=sqrt(lastS()); Lorentz5Momentum pcmf = Lorentz5Momentum(ZERO,ZERO,0.5*rs*(x.first-x.second), 0.5*rs*(x.first+x.second)); pcmf.rescaleMass(); Boost blab(pcmf.boostVector()); // emission from the quark radiation vector pnew(5); if(order) { pnew [0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first/z, 0.5*rs*x.first/z,ZERO); pnew [1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second, 0.5*rs*x.second,ZERO) ; } else { pnew[0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first, 0.5*rs*x.first,ZERO); pnew[1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second/z, 0.5*rs*x.second/z,ZERO) ; } pnew [2] = meMomenta()[2]; pnew [3] = meMomenta()[3]; pnew [4] = Lorentz5Momentum(pT*cos(phi_),pT*sin(phi_), pT*sinh(rapidity), pT*cosh(rapidity), ZERO); Lorentz5Momentum K = pnew [0]+pnew [1]-pnew [4]; Lorentz5Momentum Kt = pcmf; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); for(unsigned int ix=2;ix<4;++ix) { pnew [ix].boost(blab); pnew [ix] = pnew [ix] - 2.*Ksum*(Ksum*pnew [ix])/Ksum2 +2*K*(Kt*pnew [ix])/K2; } // phase-space prefactors double phase = zJac*vJac/z; // real emission q qbar vector output(4,0.); double realQQ(0.),realGQ(0.); if(!(zTilde_<1e-7 || vt<1e-7 || 1.-z-vt < 1e-7 )) { cPDVector particles(mePartonData()); particles.push_back(gluon_); // calculate the full 2->3 matrix element realQQ = sHat()*phase*newqPDF/oldqPDF* realGammaGammagME(particles,pnew,order ? IIQCD1 : IIQCD2,Subtraction,false); if(order) { particles[0] = gluon_; particles[4] = mePartonData()[0]->CC(); realGQ = sHat()*phase*newgPDF/oldqPDF* realGammaGammaqbarME(particles,pnew,IIQCD2,Subtraction,false); } else { particles[1] = gluon_; particles[4] = mePartonData()[1]->CC(); realGQ = sHat()*phase*newgPDF/oldqPDF* realGammaGammaqME (particles,pnew,IIQCD1,Subtraction,false); } } // return the answer return realQQ+realGQ; } double MEPP2GammaGammaPowheg::collinearQuark(double x, Energy2 mu2, double jac, double z, double oldPDF, double newPDF) const { if(1.-z < 1.e-8) return 0.; return CFfact_*( // this bit is multiplied by LO PDF sqr(Constants::pi)/3.-5.+2.*sqr(log(1.-x )) +(1.5+2.*log(1.-x ))*log(sHat()/mu2) // NLO PDF bit +jac /z * newPDF /oldPDF * (1.-z -(1.+z )*log(sqr(1.-z )/z ) -(1.+z )*log(sHat()/mu2)-2.*log(z )/(1.-z )) // + function bit +jac /z *(newPDF /oldPDF -z )* 2./(1.-z )*log(sHat()*sqr(1.-z )/mu2)); } double MEPP2GammaGammaPowheg::collinearGluon(Energy2 mu2, double jac, double z, double oldPDF, double newPDF) const { if(1.-z < 1.e-8) return 0.; return TRfact_*jac/z*newPDF/oldPDF* ((sqr(z)+sqr(1.-z))*log(sqr(1.-z)*sHat()/z/mu2) +2.*z*(1.-z)); } void MEPP2GammaGammaPowheg::doinit() { HwMEBase::doinit(); vector mopt(2,1); massOption(mopt); // get the vertices we need // get a pointer to the standard model object in the run static const tcHwSMPtr hwsm = dynamic_ptr_cast(standardModel()); if (!hwsm) throw InitException() << "hwsm pointer is null in" << " MEPP2GammaGamma::doinit()" << Exception::abortnow; // get pointers to all required Vertex objects FFPvertex_ = hwsm->vertexFFP(); FFGvertex_ = hwsm->vertexFFG(); gluon_ = getParticleData(ParticleID::g); // sampling factors prefactor_.push_back(preQCDqqbarq_); prefactor_.push_back(preQCDqqbarqbar_); prefactor_.push_back(preQCDqg_); prefactor_.push_back(preQCDgqbar_); prefactor_.push_back(preQEDqqbarq_); prefactor_.push_back(preQEDqqbarqbar_); prefactor_.push_back(preQEDqgq_); prefactor_.push_back(preQEDgqbarqbar_); } HardTreePtr MEPP2GammaGammaPowheg:: generateHardest(ShowerTreePtr tree, vector interactions) { beams_.clear(); partons_.clear(); bool QCDAllowed(false),QEDAllowed(false); for(unsigned int ix=0;ix::const_iterator cit; vector particlesToShower; //progenitor particles are produced in z direction. for( cit = tree->incomingLines().begin(); cit != tree->incomingLines().end(); ++cit ) { incoming.push_back( cit->first->progenitor() ); beams_.push_back( cit->first->beam() ); partons_.push_back( cit->first->progenitor()->dataPtr() ); particlesToShower.push_back( cit->first ); } // find the parton which should be first if( ( particlesToShower[1]->progenitor()->id() > 0 && particlesToShower[0]->progenitor()->id() < 0 ) || ( particlesToShower[0]->progenitor()->id() == ParticleID::g && particlesToShower[1]->progenitor()->id() < 6 && particlesToShower[1]->progenitor()->id() > 0 ) ) swap(particlesToShower[0],particlesToShower[1]); // check that quark is along +ve z direction quarkplus_ = particlesToShower[0]->progenitor()->momentum().z() > ZERO; if( partons_[0]->id() < 0 || (partons_[0]->id()==ParticleID::g && partons_[1]->id()>0)) { swap(partons_[0],partons_[1]); swap(beams_ [0],beams_ [1]); } // outgoing partons for( map::const_iterator cjt= tree->outgoingLines().begin(); cjt != tree->outgoingLines().end();++cjt ) { particlesToShower.push_back( cjt->first ); } if(particlesToShower.size()!=4) return HardTreePtr(); if(particlesToShower[2]->id()!=ParticleID::gamma) swap(particlesToShower[2],particlesToShower[3]); if(particlesToShower[3]->progenitor()->id()==ParticleID::gamma) { if(QCDAllowed) return hardQCDEmission(particlesToShower); } else { if(QEDAllowed) return hardQEDEmission(particlesToShower); } return HardTreePtr(); } HardTreePtr MEPP2GammaGammaPowheg:: hardQCDEmission(vector particlesToShower) { Energy rootS = sqrt(lastS()); // limits on the rapidity of the jet double minyj = -8.0,maxyj = 8.0; // generate the hard emission pair x = make_pair(particlesToShower[0]->progenitor()->x(), particlesToShower[1]->progenitor()->x()); vector pT; Energy pTmax(-GeV); cPDVector selectedParticles; vector selectedMomenta; int iemit(-1); for(unsigned int ix=0;ix<4;++ix) { pT.push_back(0.5*generator()->maximumCMEnergy()); double a = alphaQCD_->overestimateValue()/Constants::twopi* prefactor_[ix]*(maxyj-minyj); cPDVector particles; for(unsigned int iy=0;iyprogenitor()->dataPtr()); if(ix<2) particles.push_back(gluon_); else if(ix==2) { particles.push_back(particles[0]->CC()); particles[0] = gluon_; } else { particles.push_back(particles[1]->CC()); particles[1] = gluon_; } vector momenta(5); do { pT[ix] *= pow(UseRandom::rnd(),1./a); double y = UseRandom::rnd()*(maxyj-minyj)+ minyj; double vt,z; if(ix%2==0) { vt = pT[ix]*exp(-y)/rootS/x.second; z = (1.-pT[ix]*exp(-y)/rootS/x.second)/(1.+pT[ix]*exp( y)/rootS/x.first ); if(z>1.||z1.||z1.-z || vt<0.) continue; if(ix%2==0) { momenta[0] = particlesToShower[0]->progenitor()->momentum()/z; momenta[1] = particlesToShower[1]->progenitor()->momentum(); } else { momenta[0] = particlesToShower[0]->progenitor()->momentum(); momenta[1] = particlesToShower[1]->progenitor()->momentum()/z; } double phi = Constants::twopi*UseRandom::rnd(); momenta[2] = particlesToShower[2]->progenitor()->momentum(); momenta[3] = particlesToShower[3]->progenitor()->momentum(); if(!quarkplus_) y *= -1.; momenta[4] = Lorentz5Momentum(pT[ix]*cos(phi),pT[ix]*sin(phi), pT[ix]*sinh(y),pT[ix]*cosh(y), ZERO); Lorentz5Momentum K = momenta[0] + momenta[1] - momenta[4]; Lorentz5Momentum Kt = momenta[2]+momenta[3]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(), Ksum2 = Ksum.m2(); for(unsigned int iy=2;iy<4;++iy) { momenta [iy] = momenta [iy] - 2.*Ksum*(Ksum*momenta [iy])/Ksum2 +2*K*(Kt*momenta [iy])/K2; } // matrix element piece double wgt = alphaQCD_->ratio(sqr(pT[ix]))*z/(1.-vt)/prefactor_[ix]/loME_; if(ix==0) wgt *= sqr(pT[ix])*realGammaGammagME(particles,momenta,IIQCD1,Shower,false); else if(ix==1) wgt *= sqr(pT[ix])*realGammaGammagME(particles,momenta,IIQCD2,Shower,false); else if(ix==2) wgt *= sqr(pT[ix])*realGammaGammaqbarME(particles,momenta,IIQCD1,Shower,false); else if(ix==3) wgt *= sqr(pT[ix])*realGammaGammaqME(particles,momenta,IIQCD2,Shower,false); wgt *= 4.*Constants::pi/alphaS_; // pdf piece double pdf[2]; if(ix%2==0) { pdf[0] = beams_[0]->pdf()->xfx(beams_[0],partons_ [0], scale(), x.first ) /x.first; pdf[1] = beams_[0]->pdf()->xfx(beams_[0],particles[0], scale()+sqr(pT[ix]),x.first /z)*z/x.first; } else { pdf[0] = beams_[1]->pdf()->xfx(beams_[1],partons_ [1], scale() ,x.second ) /x.second; pdf[1] = beams_[1]->pdf()->xfx(beams_[1],particles[1], scale()+sqr(pT[ix]),x.second/z)*z/x.second; } if(pdf[0]<=0.||pdf[1]<=0.) continue; wgt *= pdf[1]/pdf[0]; if(wgt>1.) generator()->log() << "Weight greater than one in " << "MEPP2GammaGammaPowheg::hardQCDEmission() " << "for channel " << ix << " Weight = " << wgt << "\n"; if(UseRandom::rnd()minpT_); if(pT[ix]>minpT_ && pT[ix]>pTmax) { pTmax = pT[ix]; selectedParticles = particles; selectedMomenta = momenta; iemit=ix; } } // if no emission if(pTmaxmaximumpT(minpT_,ShowerInteraction::QCD); return HardTreePtr(); } // construct the HardTree object needed to perform the showers // create the partons ShowerParticleVector newparticles; newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[0],false))); newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[1],false))); newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[4], true))); // set the momenta for(unsigned int ix=0;ix<2;++ix) newparticles[ix]->set5Momentum(selectedMomenta[ix]); newparticles[2]->set5Momentum(selectedMomenta[4]); // create the off-shell particle Lorentz5Momentum poff = selectedMomenta[iemit%2] - selectedMomenta[4]; poff.rescaleMass(); newparticles.push_back(new_ptr(ShowerParticle(partons_[iemit%2],false))); newparticles.back()->set5Momentum(poff); for(unsigned int ix=2;ix progenitor()->dataPtr(),true))); newparticles.back()->set5Momentum(selectedMomenta[ix]); } vector inBranch,hardBranch; // create the branchings for the incoming particles inBranch.push_back(new_ptr(HardBranching(newparticles[0],SudakovPtr(), HardBranchingPtr(),HardBranching::Incoming))); inBranch.push_back(new_ptr(HardBranching(newparticles[1],SudakovPtr(), HardBranchingPtr(),HardBranching::Incoming))); // intermediate IS particle hardBranch.push_back(new_ptr(HardBranching(newparticles[3],SudakovPtr(), inBranch[iemit%2],HardBranching::Incoming))); inBranch[iemit%2]->addChild(hardBranch.back()); if(newparticles[3]->id()>0) inBranch[iemit%2]->type(ShowerPartnerType::QCDColourLine ); else inBranch[iemit%2]->type(ShowerPartnerType::QCDAntiColourLine); // create the branching for the emitted jet inBranch[iemit%2]->addChild(new_ptr(HardBranching(newparticles[2],SudakovPtr(), inBranch[iemit%2], HardBranching::Outgoing))); // set the colour partners hardBranch.back()->colourPartner(inBranch[iemit%2==0 ? 1 : 0]); inBranch[iemit%2==0 ? 1 : 0]->colourPartner(hardBranch.back()); // add other particle hardBranch.push_back(inBranch[iemit%2==0 ? 1 : 0]); // outgoing particles for(unsigned int ix=4;ix hard=hardtree->branchings(); for(unsigned int ix=0;ixmaximumpT(pTmax,ShowerInteraction::QCD); for(set::const_iterator mit=hard.begin(); mit!=hard.end();++mit) { if(particlesToShower[ix]->progenitor()->id()==(*mit)->branchingParticle()->id()&& (( particlesToShower[ix]->progenitor()->isFinalState()&& (**mit).status()==HardBranching::Outgoing)|| (!particlesToShower[ix]->progenitor()->isFinalState()&& (**mit).status()==HardBranching::Incoming))) { hardtree->connect(particlesToShower[ix]->progenitor(),*mit); if((**mit).status()==HardBranching::Incoming) { (*mit)->beam(particlesToShower[ix]->original()->parents()[0]); } HardBranchingPtr parent=(*mit)->parent(); while(parent) { parent->beam(particlesToShower[ix]->original()->parents()[0]); parent=parent->parent(); }; } } } ColinePtr newline=new_ptr(ColourLine()); for(set::const_iterator cit=hardtree->branchings().begin(); cit!=hardtree->branchings().end();++cit) { if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3) newline->addColoured((**cit).branchingParticle()); else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar) newline->addAntiColoured((**cit).branchingParticle()); } // return the tree return hardtree; } HardTreePtr MEPP2GammaGammaPowheg:: hardQEDEmission(vector particlesToShower) { // return if not emission from quark if(particlesToShower[0]->progenitor()->id()!=ParticleID::g && particlesToShower[1]->progenitor()->id()!=ParticleID::g ) return HardTreePtr(); // generate the hard emission pair x = make_pair(particlesToShower[0]->progenitor()->x(), particlesToShower[1]->progenitor()->x()); vector pT; Energy pTmax(-GeV); cPDVector selectedParticles; vector selectedMomenta; int iemit(-1); pair mewgt(make_pair(0.,0.)); for(unsigned int ix=0;ixprogenitor()->dataPtr()); selectedMomenta.push_back(particlesToShower[ix]->progenitor()->momentum()); } selectedParticles.push_back(getParticleData(ParticleID::gamma)); swap(selectedParticles[3],selectedParticles[4]); selectedMomenta.push_back(Lorentz5Momentum()); swap(selectedMomenta[3],selectedMomenta[4]); Lorentz5Momentum pin,pout; double xB; unsigned int iloc; if(particlesToShower[0]->progenitor()->dataPtr()->charged()) { pin = particlesToShower[0]->progenitor()->momentum(); xB = x.first; iloc = 6; } else { pin = particlesToShower[1]->progenitor()->momentum(); xB = x.second; iloc = 7; } pout = particlesToShower[3]->progenitor()->momentum(); Lorentz5Momentum q = pout-pin; Axis axis(q.vect().unit()); LorentzRotation rot; double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); rot = LorentzRotation(); if(axis.perp2()>1e-20) { rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot.rotateX(Constants::pi); } if(abs(1.-q.e()/q.vect().mag())>1e-6) rot.boostZ(q.e()/q.vect().mag()); Lorentz5Momentum ptemp = rot*pin; if(ptemp.perp2()/GeV2>1e-20) { Boost trans = -1./ptemp.e()*ptemp.vect(); trans.setZ(0.); rot.boost(trans); } rot.invert(); Energy Q = sqrt(-q.m2()); double xT = sqrt((1.-xB)/xB); double xTMin = 2.*minpT_/Q; double wgt(0.); double a = alphaQED_->overestimateValue()*prefactor_[iloc]/Constants::twopi; Lorentz5Momentum p1,p2,p3; do { wgt = 0.; // intergration variables dxT/xT^3 xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT)); // dz double zp = UseRandom::rnd(); double xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp)); if(xT1.) continue; // phase-space piece of the weight wgt = 4.*sqr(1.-xp)*(1.-zp)*zp/prefactor_[iloc]/loME_; // coupling Energy2 pT2 = 0.25*sqr(Q*xT); wgt *= alphaQED_->ratio(pT2); // matrix element wgt *= 4.*Constants::pi/alphaEM_; // PDF double pdf[2]; if(iloc==6) { pdf[0] = beams_[0]->pdf()-> xfx(beams_[0],partons_[0],scale() ,x.first ); pdf[1] = beams_[0]->pdf()-> xfx(beams_[0],partons_[0],scale()+pT2,x.first /xp); } else { pdf[0] = beams_[1]->pdf()-> xfx(beams_[1],partons_[1],scale() ,x.second ); pdf[1] = beams_[1]->pdf()-> xfx(beams_[1],partons_[1],scale()+pT2,x.second/xp); } if(pdf[0]<=0.||pdf[1]<=0.) { wgt = 0.; continue; } wgt *= pdf[1]/pdf[0]; // matrix element piece double phi = Constants::twopi*UseRandom::rnd(); double x2 = 1.-(1.-zp)/xp; double x3 = 2.-1./xp-x2; p1=Lorentz5Momentum(ZERO,ZERO,0.5*Q/xp,0.5*Q/xp,ZERO); p2=Lorentz5Momentum( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2,0.5*Q*sqrt(sqr(xT)+sqr(x2))); p3=Lorentz5Momentum(-0.5*Q*xT*cos(phi),-0.5*Q*xT*sin(phi), -0.5*Q*x3,0.5*Q*sqrt(sqr(xT)+sqr(x3))); selectedMomenta[iloc-6] = rot*p1; selectedMomenta[3] = rot*p3; selectedMomenta[4] = rot*p2; if(iloc==6) { mewgt.first = sqr(Q)*realGammaGammaqME(selectedParticles,selectedMomenta,IFQED1,Shower,false); mewgt.second = sqr(Q)*realGammaGammaqME(selectedParticles,selectedMomenta,FIQED1,Shower,false); wgt *= mewgt.first+mewgt.second; } else { mewgt.first = sqr(Q)*realGammaGammaqbarME(selectedParticles,selectedMomenta,IFQED2,Shower,false); mewgt.second = sqr(Q)*realGammaGammaqbarME(selectedParticles,selectedMomenta,FIQED2,Shower,false); wgt *= mewgt.first+mewgt.second; } if(wgt>1.) generator()->log() << "Weight greater than one in " << "MEPP2GammaGammaPowheg::hardQEDEmission() " << "for IF channel " << " Weight = " << wgt << "\n"; } while(xT>xTMin&&UseRandom::rnd()>wgt); // if no emission if(xTmaximumpT(minpT_,ShowerInteraction::QED); return HardTreePtr(); } pTmax = 0.5*xT*Q; iemit = mewgt.first>mewgt.second ? 2 : 3; // construct the HardTree object needed to perform the showers // create the partons ShowerParticleVector newparticles; newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[0],false))); newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[1],false))); newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[3], true))); // set the momenta for(unsigned int ix=0;ix<2;++ix) newparticles[ix]->set5Momentum(selectedMomenta[ix]); newparticles[2]->set5Momentum(selectedMomenta[3]); // create the off-shell particle if(iemit==2) { if(particlesToShower[0]->progenitor()->dataPtr()->charged()) { Lorentz5Momentum poff = selectedMomenta[0] - selectedMomenta[3]; poff.rescaleMass(); newparticles.push_back(new_ptr(ShowerParticle(partons_[0],false))); newparticles.back()->set5Momentum(poff); } else { Lorentz5Momentum poff = selectedMomenta[1] - selectedMomenta[3]; poff.rescaleMass(); newparticles.push_back(new_ptr(ShowerParticle(partons_[1],false))); newparticles.back()->set5Momentum(poff); } } else if(iemit==3) { Lorentz5Momentum poff = selectedMomenta[3]+selectedMomenta[4]; poff.rescaleMass(); newparticles.push_back(new_ptr(ShowerParticle(particlesToShower[3] ->progenitor()->dataPtr(),true))); newparticles.back()->set5Momentum(poff); } else assert(false); for(unsigned int ix=2;ix progenitor()->dataPtr(),true))); newparticles.back()->set5Momentum(selectedMomenta[ix==2 ? 2 : 4 ]); } vector inBranch,hardBranch; // create the branchings for the incoming particles inBranch.push_back(new_ptr(HardBranching(newparticles[0],SudakovPtr(), HardBranchingPtr(),HardBranching::Incoming))); inBranch.push_back(new_ptr(HardBranching(newparticles[1],SudakovPtr(), HardBranchingPtr(),HardBranching::Incoming))); if(iemit<3) { int icharged = iemit; if(icharged==2) icharged = particlesToShower[0]->progenitor()-> dataPtr()->charged() ? 0 : 1; // intermediate IS particle hardBranch.push_back(new_ptr(HardBranching(newparticles[3],SudakovPtr(), inBranch[icharged],HardBranching::Incoming))); inBranch[icharged]->addChild(hardBranch.back()); inBranch[icharged]->type(ShowerPartnerType::QED); // create the branching for the emitted jet inBranch[icharged]->addChild(new_ptr(HardBranching(newparticles[2],SudakovPtr(), inBranch[icharged], HardBranching::Outgoing))); // set the colour partners if(iemit<2) { hardBranch.back()->colourPartner(inBranch[icharged==0 ? 1 : 0]); inBranch[icharged==0 ? 1 : 0]->colourPartner(hardBranch.back()); } // add other particle hardBranch.push_back(inBranch[icharged == 0 ? 1 : 0]); // outgoing particles for(unsigned int ix=4;ixcolourPartner(hardBranch[0]); hardBranch[0]->colourPartner(hardBranch.back()); } } else { for(unsigned int ix=0;ix<2;++ix) hardBranch.push_back(inBranch[ix]); hardBranch.push_back(new_ptr(HardBranching(newparticles[4],SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); hardBranch.push_back(new_ptr(HardBranching(newparticles[3],SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); hardBranch.back()->type(ShowerPartnerType::QED); hardBranch.back()->addChild(new_ptr(HardBranching(newparticles[5],SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); hardBranch.back()->addChild(new_ptr(HardBranching(newparticles[2],SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); if(hardBranch[0]->branchingParticle()->dataPtr()->charged()) { hardBranch.back()->colourPartner(hardBranch[0]); hardBranch[0]->colourPartner(hardBranch.back()); } else { hardBranch.back()->colourPartner(hardBranch[1]); hardBranch[1]->colourPartner(hardBranch.back()); } } // make the tree HardTreePtr hardtree=new_ptr(HardTree(hardBranch,inBranch,ShowerInteraction::QED)); // connect the ShowerParticles with the branchings // and set the maximum pt for the radiation set hard=hardtree->branchings(); for(unsigned int ix=0;ixmaximumpT(pTmax,ShowerInteraction::QED); for(set::const_iterator mit=hard.begin(); mit!=hard.end();++mit) { if(particlesToShower[ix]->progenitor()->id()==(*mit)->branchingParticle()->id()&& (( particlesToShower[ix]->progenitor()->isFinalState()&& (**mit).status()==HardBranching::Outgoing)|| (!particlesToShower[ix]->progenitor()->isFinalState()&& (**mit).status()==HardBranching::Incoming))) { hardtree->connect(particlesToShower[ix]->progenitor(),*mit); if((**mit).status()==HardBranching::Incoming) { (*mit)->beam(particlesToShower[ix]->original()->parents()[0]); } HardBranchingPtr parent=(*mit)->parent(); while(parent) { parent->beam(particlesToShower[ix]->original()->parents()[0]); parent=parent->parent(); }; } } } ColinePtr newline1 = new_ptr(ColourLine()); ColinePtr newline2 = new_ptr(ColourLine()); HardBranchingPtr gluon,quark,antiQuark; for(set::const_iterator cit=hardtree->branchings().begin(); cit!=hardtree->branchings().end();++cit) { if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour8) { gluon = *cit; if((**cit).status()==HardBranching::Incoming) { newline1->addColoured ((**cit).branchingParticle()); newline2->addAntiColoured((**cit).branchingParticle()); } else { newline2->addColoured ((**cit).branchingParticle()); newline1->addAntiColoured((**cit).branchingParticle()); } } else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3) { if((**cit).status()==HardBranching::Incoming) { antiQuark = *cit; newline2->addColoured((**cit).branchingParticle()); } else { quark = *cit; newline1->addColoured((**cit).branchingParticle()); } } else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar) { if((**cit).status()==HardBranching::Incoming) { quark = *cit; newline1->addAntiColoured((**cit).branchingParticle()); } else { antiQuark = *cit; newline2->addAntiColoured((**cit).branchingParticle()); } } } assert(quark&&antiQuark&&gluon); gluon->colourPartner(UseRandom::rndbool() ? quark : antiQuark); // return the tree return hardtree; } diff --git a/Shower/Base/Evolver.cc b/Shower/Base/Evolver.cc --- a/Shower/Base/Evolver.cc +++ b/Shower/Base/Evolver.cc @@ -1,3630 +1,3629 @@ // -*- C++ -*- // // Evolver.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2011 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the Evolver class. // #include "Evolver.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Shower/Base/ShowerParticle.h" #include "ThePEG/Utilities/EnumIO.h" #include "ShowerKinematics.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Handlers/EventHandler.h" #include "ThePEG/Utilities/Throw.h" #include "ShowerTree.h" #include "ShowerProgenitor.h" #include "KinematicsReconstructor.h" #include "PartnerFinder.h" #include "ThePEG/Handlers/StandardXComb.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Shower/ShowerHandler.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ShowerVertex.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h" #include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" #include "ThePEG/Handlers/StandardXComb.h" using namespace Herwig; namespace { /** * A struct to order the particles in the same way as in the DecayMode's */ struct ParticleOrdering { /** * Operator for the ordering * @param p1 The first ParticleData object * @param p2 The second ParticleData object */ bool operator() (tcPDPtr p1, tcPDPtr p2) { return abs(p1->id()) > abs(p2->id()) || ( abs(p1->id()) == abs(p2->id()) && p1->id() > p2->id() ) || ( p1->id() == p2->id() && p1->fullName() > p2->fullName() ); } }; typedef multiset OrderedParticles; /** * Cached lookup of decay modes. * Generator::findDecayMode() is not efficient. */ tDMPtr findDecayMode(const string & tag) { static map cache; map::const_iterator pos = cache.find(tag); if ( pos != cache.end() ) return pos->second; tDMPtr dm = CurrentGenerator::current().findDecayMode(tag); cache[tag] = dm; return dm; } } DescribeClass describeEvolver ("Herwig::Evolver","HwShower.so"); bool Evolver::_hardEmissionModeWarn = true; bool Evolver::_missingTruncWarn = true; IBPtr Evolver::clone() const { return new_ptr(*this); } IBPtr Evolver::fullclone() const { return new_ptr(*this); } void Evolver::persistentOutput(PersistentOStream & os) const { os << _model << _splittingGenerator << _maxtry << _meCorrMode << _hardVetoMode << _hardVetoRead << _hardVetoReadOption << _limitEmissions << _spinOpt << _softOpt << _hardPOWHEG << ounit(_iptrms,GeV) << _beta << ounit(_gamma,GeV) << ounit(_iptmax,GeV) << _vetoes << _trunc_Mode << _hardEmissionMode << _reconOpt << isMCatNLOSEvent << isMCatNLOHEvent << isPowhegSEvent << isPowhegHEvent << theFactorizationScaleFactor << theRenormalizationScaleFactor << ounit(muPt,GeV) << interaction_ << _maxTryFSR << _maxFailFSR << _fracFSR << interactions_.size(); for(unsigned int ix=0;ix> _model >> _splittingGenerator >> _maxtry >> _meCorrMode >> _hardVetoMode >> _hardVetoRead >> _hardVetoReadOption >> _limitEmissions >> _spinOpt >> _softOpt >> _hardPOWHEG >> iunit(_iptrms,GeV) >> _beta >> iunit(_gamma,GeV) >> iunit(_iptmax,GeV) >> _vetoes >> _trunc_Mode >> _hardEmissionMode >> _reconOpt >> isMCatNLOSEvent >> isMCatNLOHEvent >> isPowhegSEvent >> isPowhegHEvent >> theFactorizationScaleFactor >> theRenormalizationScaleFactor >> iunit(muPt,GeV) >> interaction_ >> _maxTryFSR >> _maxFailFSR >> _fracFSR >> isize; interactions_.resize(isize); for(unsigned int ix=0;ix> ienum(interactions_[ix]); } void Evolver::doinit() { Interfaced::doinit(); // interactions may have been changed through a setup file so we // clear it up here interactions_.clear(); if(interaction_==0) { interactions_.push_back(ShowerInteraction::QCD); interactions_.push_back(ShowerInteraction::QED); } else if(interaction_==1) { interactions_.push_back(ShowerInteraction::QCD); } else if(interaction_==2) { interactions_.push_back(ShowerInteraction::QED); interactions_.push_back(ShowerInteraction::QCD); } else if(interaction_==3) { interactions_.push_back(ShowerInteraction::QED); } else if(interaction_==4) { - interactions_.push_back(ShowerInteraction::Both); + interactions_.push_back(ShowerInteraction::QEDQCD); } // calculate max no of FSR vetos _maxFailFSR = max(int(_maxFailFSR), int(_fracFSR*double(generator()->N()))); } void Evolver::Init() { static ClassDocumentation documentation ("This class is responsible for carrying out the showering,", "including the kinematics reconstruction, in a given scale range," "including the option of the POWHEG approach to simulated next-to-leading order" " radiation\\cite{Nason:2004rx}.", "%\\cite{Nason:2004rx}\n" "\\bibitem{Nason:2004rx}\n" " P.~Nason,\n" " ``A new method for combining NLO QCD with shower Monte Carlo algorithms,''\n" " JHEP {\\bf 0411} (2004) 040\n" " [arXiv:hep-ph/0409146].\n" " %%CITATION = JHEPA,0411,040;%%\n"); static Reference interfaceSplitGen("SplittingGenerator", "A reference to the SplittingGenerator object", &Herwig::Evolver::_splittingGenerator, false, false, true, false); static Reference interfaceShowerModel ("ShowerModel", "The pointer to the object which defines the shower evolution model.", &Evolver::_model, false, false, true, false, false); static Parameter interfaceMaxTry ("MaxTry", "The maximum number of attempts to generate the shower from a" " particular ShowerTree", &Evolver::_maxtry, 100, 1, 1000, false, false, Interface::limited); static Switch ifaceMECorrMode ("MECorrMode", "Choice of the ME Correction Mode", &Evolver::_meCorrMode, 1, false, false); static SwitchOption off (ifaceMECorrMode,"No","MECorrections off", 0); static SwitchOption on (ifaceMECorrMode,"Yes","hard+soft on", 1); static SwitchOption hard (ifaceMECorrMode,"Hard","only hard on", 2); static SwitchOption soft (ifaceMECorrMode,"Soft","only soft on", 3); static Switch ifaceHardVetoMode ("HardVetoMode", "Choice of the Hard Veto Mode", &Evolver::_hardVetoMode, 1, false, false); static SwitchOption HVoff (ifaceHardVetoMode,"No","hard vetos off", 0); static SwitchOption HVon (ifaceHardVetoMode,"Yes","hard vetos on", 1); static SwitchOption HVIS (ifaceHardVetoMode,"Initial", "only IS emissions vetoed", 2); static SwitchOption HVFS (ifaceHardVetoMode,"Final","only FS emissions vetoed", 3); static Switch ifaceHardVetoRead ("HardVetoScaleSource", "If hard veto scale is to be read", &Evolver::_hardVetoRead, 0, false, false); static SwitchOption HVRcalc (ifaceHardVetoRead,"Calculate","Calculate from hard process", 0); static SwitchOption HVRread (ifaceHardVetoRead,"Read","Read from XComb->lastScale", 1); static Switch ifaceHardVetoReadOption ("HardVetoReadOption", "Apply read-in scale veto to all collisions or just the primary one?", &Evolver::_hardVetoReadOption, false, false, false); static SwitchOption AllCollisions (ifaceHardVetoReadOption, "AllCollisions", "Read-in pT veto applied to primary and secondary collisions.", false); static SwitchOption PrimaryCollision (ifaceHardVetoReadOption, "PrimaryCollision", "Read-in pT veto applied to primary but not secondary collisions.", true); static Parameter ifaceiptrms ("IntrinsicPtGaussian", "RMS of intrinsic pT of Gaussian distribution:\n" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &Evolver::_iptrms, GeV, ZERO, ZERO, 1000000.0*GeV, false, false, Interface::limited); static Parameter ifacebeta ("IntrinsicPtBeta", "Proportion of inverse quadratic distribution in generating intrinsic pT.\n" "(1-Beta) is the proportion of Gaussian distribution", &Evolver::_beta, 0, 0, 1, false, false, Interface::limited); static Parameter ifacegamma ("IntrinsicPtGamma", "Parameter for inverse quadratic:\n" "2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))", &Evolver::_gamma,GeV, ZERO, ZERO, 100000.0*GeV, false, false, Interface::limited); static Parameter ifaceiptmax ("IntrinsicPtIptmax", "Upper bound on intrinsic pT for inverse quadratic", &Evolver::_iptmax,GeV, ZERO, ZERO, 100000.0*GeV, false, false, Interface::limited); static RefVector ifaceVetoes ("Vetoes", "The vetoes to be checked during showering", &Evolver::_vetoes, -1, false,false,true,true,false); static Switch interfaceLimitEmissions ("LimitEmissions", "Limit the number and type of emissions for testing", &Evolver::_limitEmissions, 0, false, false); static SwitchOption interfaceLimitEmissionsNoLimit (interfaceLimitEmissions, "NoLimit", "Allow an arbitrary number of emissions", 0); static SwitchOption interfaceLimitEmissionsOneInitialStateEmission (interfaceLimitEmissions, "OneInitialStateEmission", "Allow one emission in the initial state and none in the final state", 1); static SwitchOption interfaceLimitEmissionsOneFinalStateEmission (interfaceLimitEmissions, "OneFinalStateEmission", "Allow one emission in the final state and none in the initial state", 2); static SwitchOption interfaceLimitEmissionsHardOnly (interfaceLimitEmissions, "HardOnly", "Only allow radiation from the hard ME correction", 3); static SwitchOption interfaceLimitEmissionsOneEmission (interfaceLimitEmissions, "OneEmission", "Allow one emission in either the final state or initial state, but not both", 4); static Switch interfaceTruncMode ("TruncatedShower", "Include the truncated shower?", &Evolver::_trunc_Mode, 1, false, false); static SwitchOption interfaceTruncMode0 (interfaceTruncMode,"No","Truncated Shower is OFF", 0); static SwitchOption interfaceTruncMode1 (interfaceTruncMode,"Yes","Truncated Shower is ON", 1); static Switch interfaceHardEmissionMode ("HardEmissionMode", "Whether to use ME corrections or POWHEG for the hardest emission", &Evolver::_hardEmissionMode, 0, false, false); static SwitchOption interfaceHardEmissionModeDecayMECorrection (interfaceHardEmissionMode, "DecayMECorrection", "Old fashioned ME correction for decays only", -1); static SwitchOption interfaceHardEmissionModeMECorrection (interfaceHardEmissionMode, "MECorrection", "Old fashioned ME correction", 0); static SwitchOption interfaceHardEmissionModePOWHEG (interfaceHardEmissionMode, "POWHEG", "Powheg style hard emission using internal matrix elements", 1); static SwitchOption interfaceHardEmissionModeMatchboxPOWHEG (interfaceHardEmissionMode, "MatchboxPOWHEG", "Powheg style emission for the hard process using Matchbox", 2); static SwitchOption interfaceHardEmissionModeFullPOWHEG (interfaceHardEmissionMode, "FullPOWHEG", "Powheg style emission for the hard process using Matchbox " "and decays using internal matrix elements", 3); static Switch interfaceInteractions ("Interactions", "The interactions to be used in the shower", &Evolver::interaction_, 1, false, false); static SwitchOption interfaceInteractionsQCDFirst (interfaceInteractions, "QCDFirst", "QCD first then QED", 0); static SwitchOption interfaceInteractionsQCDOnly (interfaceInteractions, "QCDOnly", "Only QCD", 1); static SwitchOption interfaceInteractionsQEDFirst (interfaceInteractions, "QEDFirst", "QED first then QCD", 2); static SwitchOption interfaceInteractionsQEDOnly (interfaceInteractions, "QEDOnly", "Only QED", 3); static SwitchOption interfaceInteractionsBothAtOnce (interfaceInteractions, "BothAtOnce", "Generate both at the same time", 4); static Switch interfaceReconstructionOption ("ReconstructionOption", "Treatment of the reconstruction of the transverse momentum of " "a branching from the evolution scale.", &Evolver::_reconOpt, 0, false, false); static SwitchOption interfaceReconstructionOptionCutOff (interfaceReconstructionOption, "CutOff", "Use the cut-off masses in the calculation", 0); static SwitchOption interfaceReconstructionOptionOffShell (interfaceReconstructionOption, "OffShell", "Use the off-shell masses in the calculation veto the emission of the parent," " no veto in generation of emissions from children", 1); static SwitchOption interfaceReconstructionOptionOffShell2 (interfaceReconstructionOption, "OffShell2", "Use the off-shell masses in the calculation veto the emissions from the children." " no veto in generation of emissions from children", 2); static SwitchOption interfaceReconstructionOptionOffShell3 (interfaceReconstructionOption, "OffShell3", "Use the off-shell masses in the calculation veto the emissions from the children." " veto in generation of emissions from children using cut-off for second parton", 3); static Switch interfaceSpinCorrelations ("SpinCorrelations", "Treatment of spin correlations in the parton shower", &Evolver::_spinOpt, 1, false, false); static SwitchOption interfaceSpinCorrelationsOff (interfaceSpinCorrelations, "No", "No spin correlations", 0); static SwitchOption interfaceSpinCorrelationsSpin (interfaceSpinCorrelations, "Yes", "Include the azimuthal spin correlations only", 1); static Switch interfaceSoftCorrelations ("SoftCorrelations", "Option for the treatment of soft correlations in the parton shower", &Evolver::_softOpt, 2, false, false); static SwitchOption interfaceSoftCorrelationsNone (interfaceSoftCorrelations, "No", "No soft correlations", 0); static SwitchOption interfaceSoftCorrelationsFull (interfaceSoftCorrelations, "Full", "Use the full eikonal", 1); static SwitchOption interfaceSoftCorrelationsSingular (interfaceSoftCorrelations, "Singular", "Use original Webber-Marchisini form", 2); static Switch interfaceHardPOWHEG ("HardPOWHEG", "Treatment of powheg emissions which are too hard to have a shower interpretation", &Evolver::_hardPOWHEG, false, false, false); static SwitchOption interfaceHardPOWHEGAsShower (interfaceHardPOWHEG, "AsShower", "Still interpret as shower emissions", false); static SwitchOption interfaceHardPOWHEGRealEmission (interfaceHardPOWHEG, "RealEmission", "Generate shower from the real emmission configuration", true); static Parameter interfaceMaxTryFSR ("MaxTryFSR", "The maximum number of attempted FSR emissions in" " the generation of the FSR", &Evolver::_maxTryFSR, 100000, 10, 100000000, false, false, Interface::limited); static Parameter interfaceMaxFailFSR ("MaxFailFSR", "Maximum number of failures generating the FSR", &Evolver::_maxFailFSR, 100, 1, 100000000, false, false, Interface::limited); static Parameter interfaceFSRFailureFraction ("FSRFailureFraction", "Maximum fraction of events allowed to fail due to too many FSR emissions", &Evolver::_fracFSR, 0.001, 1e-10, 1, false, false, Interface::limited); } void Evolver::generateIntrinsicpT(vector particlesToShower) { _intrinsic.clear(); if ( !ipTon() || !isISRadiationON() ) return; // don't do anything for the moment for secondary scatters if( !ShowerHandler::currentHandler()->firstInteraction() ) return; // generate intrinsic pT for(unsigned int ix=0;ixprogenitor()->isFinalState()) continue; if(!particlesToShower[ix]->progenitor()->dataPtr()->coloured()) continue; Energy ipt; if(UseRandom::rnd() > _beta) { ipt=_iptrms*sqrt(-log(UseRandom::rnd())); } else { ipt=_gamma*sqrt(pow(1.+sqr(_iptmax/_gamma), UseRandom::rnd())-1.); } pair pt = make_pair(ipt,UseRandom::rnd(Constants::twopi)); _intrinsic[particlesToShower[ix]] = pt; } } void Evolver::setupMaximumScales(const vector & p, XCPtr xcomb) { // let POWHEG events radiate freely if(_hardEmissionMode>0&&hardTree()) { vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(Constants::MaxEnergy); return; } // return if no vetos if (!hardVetoOn()) return; // find out if hard partonic subprocess. bool isPartonic(false); map::const_iterator cit = _currenttree->incomingLines().begin(); Lorentz5Momentum pcm; for(; cit!=currentTree()->incomingLines().end(); ++cit) { pcm += cit->first->progenitor()->momentum(); isPartonic |= cit->first->progenitor()->coloured(); } // find minimum pt from hard process, the maximum pt from all outgoing // coloured lines (this is simpler and more general than // 2stu/(s^2+t^2+u^2)). Maximum scale for scattering processes will // be transverse mass. Energy ptmax = generator()->maximumCMEnergy(); // general case calculate the scale if (!hardVetoXComb()|| (hardVetoReadOption()&& !ShowerHandler::currentHandler()->firstInteraction())) { // scattering process if(currentTree()->isHard()) { assert(xcomb); // coloured incoming particles if (isPartonic) { map::const_iterator cjt = currentTree()->outgoingLines().begin(); for(; cjt!=currentTree()->outgoingLines().end(); ++cjt) { if (cjt->first->progenitor()->coloured()) ptmax = min(ptmax,cjt->first->progenitor()->momentum().mt()); } } if (ptmax == generator()->maximumCMEnergy() ) ptmax = pcm.m(); if(hardVetoXComb()&&hardVetoReadOption()&& !ShowerHandler::currentHandler()->firstInteraction()) { ptmax=min(ptmax,sqrt(xcomb->lastShowerScale())); } } // decay, incoming() is the decaying particle. else { ptmax = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } } // hepeup.SCALUP is written into the lastXComb by the // LesHouchesReader itself - use this by user's choice. // Can be more general than this. else { if(currentTree()->isHard()) { assert(xcomb); ptmax = sqrt( xcomb->lastShowerScale() ); } else { ptmax = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } } ptmax *= ShowerHandler::currentHandler()->hardScaleFactor(); // set maxHardPt for all progenitors. For partonic processes this // is now the max pt in the FS, for non-partonic processes or // processes with no coloured FS the invariant mass of the IS vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(ptmax); } void Evolver::setupHardScales(const vector & p, XCPtr xcomb) { if ( hardVetoXComb() && (!hardVetoReadOption() || ShowerHandler::currentHandler()->firstInteraction()) ) { Energy hardScale = ZERO; if(currentTree()->isHard()) { assert(xcomb); hardScale = sqrt( xcomb->lastShowerScale() ); } else { hardScale = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } hardScale *= ShowerHandler::currentHandler()->hardScaleFactor(); vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->hardScale(hardScale); muPt = hardScale; } } void Evolver::showerHardProcess(ShowerTreePtr hard, XCPtr xcomb) { isMCatNLOSEvent = false; isMCatNLOHEvent = false; isPowhegSEvent = false; isPowhegHEvent = false; Ptr::tptr subme; Ptr::tptr me; Ptr::tptr dipme; Ptr::ptr sxc = dynamic_ptr_cast::ptr>(xcomb); if ( sxc ) { subme = dynamic_ptr_cast::tptr>(sxc->matrixElement()); me = dynamic_ptr_cast::tptr>(sxc->matrixElement()); dipme = dynamic_ptr_cast::tptr>(sxc->matrixElement()); } if ( subme ) { if ( subme->showerApproximation() ) { theShowerApproximation = subme->showerApproximation(); // separate MCatNLO and POWHEG-type corrections if ( !subme->showerApproximation()->needsSplittingGenerator() ) { if ( subme->realShowerSubtraction() ) isMCatNLOHEvent = true; else if ( subme->virtualShowerSubtraction() ) isMCatNLOSEvent = true; } else { if ( subme->realShowerSubtraction() ) isPowhegHEvent = true; else if ( subme->virtualShowerSubtraction() || subme->loopSimSubtraction() ) isPowhegSEvent = true; } } } else if ( me ) { if ( me->factory()->showerApproximation() ) { theShowerApproximation = me->factory()->showerApproximation(); if ( !me->factory()->showerApproximation()->needsSplittingGenerator() ) isMCatNLOSEvent = true; else isPowhegSEvent = true; } } string error = "Inconsistent hard emission set-up in Evolver::showerHardProcess(). "; if ( ( isMCatNLOSEvent || isMCatNLOHEvent ) ){ if (_hardEmissionMode > 1) throw Exception() << error << "Cannot generate POWHEG matching with MC@NLO shower " << "approximation. Add 'set Evolver:HardEmissionMode 0' to input file." << Exception::runerror; if ( ShowerHandler::currentHandler()->canHandleMatchboxTrunc()) throw Exception() << error << "Cannot use truncated qtilde shower with MC@NLO shower " << "approximation. Set LHCGenerator:EventHandler" << ":CascadeHandler to '/Herwig/Shower/ShowerHandler' or " << "'/Herwig/DipoleShower/DipoleShowerHandler'." << Exception::runerror; } else if ( ((isPowhegSEvent || isPowhegHEvent) || dipme) && _hardEmissionMode < 2){ if ( ShowerHandler::currentHandler()->canHandleMatchboxTrunc()) throw Exception() << error << "Unmatched events requested for POWHEG shower " << "approximation. Set Evolver:HardEmissionMode to " << "'MatchboxPOWHEG' or 'FullPOWHEG'." << Exception::runerror; else if (_hardEmissionModeWarn){ _hardEmissionModeWarn = false; _hardEmissionMode+=2; throw Exception() << error << "Unmatched events requested for POWHEG shower " << "approximation. Changing Evolver:HardEmissionMode from " << _hardEmissionMode-2 << " to " << _hardEmissionMode << Exception::warning; } } if ( isPowhegSEvent || isPowhegHEvent) { if (theShowerApproximation->needsTruncatedShower() && !ShowerHandler::currentHandler()->canHandleMatchboxTrunc() ) throw Exception() << error << "Current shower handler cannot generate truncated shower. " << "Set Generator:EventHandler:CascadeHandler to " << "'/Herwig/Shower/PowhegShowerHandler'." << Exception::runerror; } else if ( dipme && _missingTruncWarn){ _missingTruncWarn=false; throw Exception() << "Warning: POWHEG shower approximation used without " << "truncated shower. Set Generator:EventHandler:" << "CascadeHandler to '/Herwig/Shower/PowhegShowerHandler' and " << "'MEMatching:TruncatedShower Yes'." << Exception::warning; } else if ( !dipme && _hardEmissionMode > 1 && ShowerHandler::currentHandler()->firstInteraction()) throw Exception() << error << "POWHEG matching requested for LO events. Include " << "'set Factory:ShowerApproximation MEMatching' in input file." << Exception::runerror; _hardme = HwMEBasePtr(); // extract the matrix element tStdXCombPtr lastXC = dynamic_ptr_cast(xcomb); if(lastXC) { _hardme = dynamic_ptr_cast(lastXC->matrixElement()); } _decayme = HwDecayerBasePtr(); // set the current tree currentTree(hard); hardTree(HardTreePtr()); // number of attempts if more than one interaction switched on unsigned int interactionTry=0; do { try { // generate the showering doShowering(true,xcomb); // if no vetos return return; } catch (InteractionVeto) { currentTree()->clear(); ++interactionTry; } } while(interactionTry<=5); throw Exception() << "Too many tries for shower in " << "Evolver::showerHardProcess()" << Exception::eventerror; } void Evolver::hardMatrixElementCorrection(bool hard) { // set the initial enhancement factors for the soft correction _initialenhance = 1.; _finalenhance = 1.; // if hard matrix element switched off return if(!MECOn(hard)) return; // see if we can get the correction from the matrix element // or decayer if(hard) { if(_hardme&&_hardme->hasMECorrection()) { _hardme->initializeMECorrection(_currenttree, _initialenhance,_finalenhance); if(hardMEC(hard)) _hardme->applyHardMatrixElementCorrection(_currenttree); } } else { if(_decayme&&_decayme->hasMECorrection()) { _decayme->initializeMECorrection(_currenttree, _initialenhance,_finalenhance); if(hardMEC(hard)) _decayme->applyHardMatrixElementCorrection(_currenttree); } } } ShowerParticleVector Evolver::createTimeLikeChildren(tShowerParticlePtr particle, IdList ids) { // Create the ShowerParticle objects for the two children of // the emitting particle; set the parent/child relationship // if same as definition create particles, otherwise create cc tcPDPtr pdata[2]; for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(ids[ix+1]); if(particle->id()!=ids[0]) { for(unsigned int ix=0;ix<2;++ix) { tPDPtr cc(pdata[ix]->CC()); if(cc) pdata[ix]=cc; } } ShowerParticleVector children; for(unsigned int ix=0;ix<2;++ix) { children.push_back(new_ptr(ShowerParticle(pdata[ix],true))); if(children[ix]->id()==_progenitor->id()&&!pdata[ix]->stable()) children[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass())); else children[ix]->set5Momentum(Lorentz5Momentum(pdata[ix]->mass())); } return children; } bool Evolver::timeLikeShower(tShowerParticlePtr particle, ShowerInteraction::Type type, Branching fb, bool first) { // don't do anything if not needed if(_limitEmissions == 1 || hardOnly() || ( _limitEmissions == 2 && _nfs != 0) || ( _limitEmissions == 4 && _nfs + _nis != 0) ) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } // too many tries if(_nFSR>=_maxTryFSR) { ++_nFailedFSR; // too many failed events if(_nFailedFSR>=_maxFailFSR) throw Exception() << "Too many events have failed due to too many shower emissions, in\n" << "Evolver::timeLikeShower(). Terminating run\n" << Exception::runerror; throw Exception() << "Too many attempted emissions in Evolver::timeLikeShower()\n" << Exception::eventerror; } // generate the emission ShowerParticleVector children; int ntry=0; // generate the emission if(!fb.kinematics) fb = selectTimeLikeBranching(particle,type,HardBranchingPtr()); // no emission, return if(!fb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } Branching fc[2]; bool setupChildren = true; while (ntry<50) { fc[0] = Branching(); fc[1] = Branching(); ++ntry; assert(fb.kinematics); // has emitted // Assign the shower kinematics to the emitting particle. if(setupChildren) { ++_nFSR; particle->showerKinematics(fb.kinematics); // generate phi fb.kinematics->phi(fb.sudakov->generatePhiForward(*particle,fb.ids,fb.kinematics)); // check highest pT if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the children children = createTimeLikeChildren(particle,fb.ids); // update the children particle->showerKinematics()-> updateChildren(particle, children,fb.type,_reconOpt>=3); // update number of emissions ++_nfs; if(_limitEmissions!=0) { if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } setupChildren = false; } // select branchings for children fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); // old default if(_reconOpt==0) { // shower the first particle if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false); if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); break; } // Herwig default else if(_reconOpt==1) { // shower the first particle if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false); if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); // clean up the vetoed emission if(particle->virtualMass()==ZERO) { particle->showerKinematics(ShoKinPtr()); for(unsigned int ix=0;ixabandonChild(children[ix]); children.clear(); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); particle->vetoEmission(fb.type,fb.kinematics->scale()); // generate the new emission fb = selectTimeLikeBranching(particle,type,HardBranchingPtr()); // no emission, return if(!fb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } setupChildren = true; continue; } else break; } // veto children else if(_reconOpt>=2) { // cut-off masses for the branching const vector & virtualMasses = fb.sudakov->virtualMasses(fb.ids); // compute the masses of the children Energy masses[3]; for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].kinematics) { const vector & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids); Energy2 q2 = fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale()); if(fc[ix].ids[0]!=ParticleID::g) q2 += sqr(vm[0]); masses[ix+1] = sqrt(q2); } else { masses[ix+1] = virtualMasses[ix+1]; } } masses[0] = fb.ids[0]!=ParticleID::g ? virtualMasses[0] : ZERO; double z = fb.kinematics->z(); Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0])) - sqr(masses[1])*(1.-z) - sqr(masses[2])*z; if(pt2>=ZERO) { break; } else { // reset the scales for the children for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].kinematics) children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); else children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); children[ix]->virtualMass(ZERO); } } } }; if(_reconOpt>=2) { // shower the first particle if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false); if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); } if(first&&!children.empty()) particle->showerKinematics()->resetChildren(particle,children); if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } bool Evolver::spaceLikeShower(tShowerParticlePtr particle, PPtr beam, ShowerInteraction::Type type) { //using the pdf's associated with the ShowerHandler assures, that //modified pdf's are used for the secondary interactions via //CascadeHandler::resetPDFs(...) tcPDFPtr pdf; if(ShowerHandler::currentHandler()->firstPDF().particle() == _beam) pdf = ShowerHandler::currentHandler()->firstPDF().pdf(); if(ShowerHandler::currentHandler()->secondPDF().particle() == _beam) pdf = ShowerHandler::currentHandler()->secondPDF().pdf(); Energy freeze = ShowerHandler::currentHandler()->pdfFreezingScale(); // don't do anything if not needed if(_limitEmissions == 2 || hardOnly() || ( _limitEmissions == 1 && _nis != 0 ) || ( _limitEmissions == 4 && _nis + _nfs != 0 ) ) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } Branching bb; // generate branching while (true) { bb=_splittingGenerator->chooseBackwardBranching(*particle,beam, _initialenhance, _beam,type, pdf,freeze); // return if no emission if(!bb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } // if not vetoed break if(!spaceLikeVetoed(bb,particle)) break; // otherwise reset scale and continue particle->vetoEmission(bb.type,bb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); } // assign the splitting function and shower kinematics particle->showerKinematics(bb.kinematics); if(bb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(bb.kinematics->pT()); // For the time being we are considering only 1->2 branching // particles as in Sudakov form factor tcPDPtr part[2]={getParticleData(bb.ids[0]), getParticleData(bb.ids[2])}; if(particle->id()!=bb.ids[1]) { if(part[0]->CC()) part[0]=part[0]->CC(); if(part[1]->CC()) part[1]=part[1]->CC(); } // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent=new_ptr(ShowerParticle(part[0],false)); ShowerParticlePtr otherChild = new_ptr(ShowerParticle(part[1],true,true)); ShowerParticleVector theChildren; theChildren.push_back(particle); theChildren.push_back(otherChild); //this updates the evolution scale particle->showerKinematics()-> updateParent(newParent, theChildren,bb.type); // update the history if needed _currenttree->updateInitialStateShowerProduct(_progenitor,newParent); _currenttree->addInitialStateBranching(particle,newParent,otherChild); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower ++_nis; bool emitted = _limitEmissions==0 ? spaceLikeShower(newParent,beam,type) : false; if(newParent->spinInfo()) newParent->spinInfo()->develop(); // now reconstruct the momentum if(!emitted) { if(_intrinsic.find(_progenitor)==_intrinsic.end()) { bb.kinematics->updateLast(newParent,ZERO,ZERO); } else { pair kt=_intrinsic[_progenitor]; bb.kinematics->updateLast(newParent, kt.first*cos(kt.second), kt.first*sin(kt.second)); } } particle->showerKinematics()-> updateChildren(newParent, theChildren,bb.type,false); if(_limitEmissions!=0) { if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } // perform the shower of the final-state particle timeLikeShower(otherChild,type,Branching(),true); updateHistory(otherChild); if(theChildren[1]->spinInfo()) theChildren[1]->spinInfo()->develop(); // return the emitted if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } void Evolver::showerDecay(ShowerTreePtr decay) { _decayme = HwDecayerBasePtr(); _hardme = HwMEBasePtr(); // find the decayer // try the normal way if possible tDMPtr dm = decay->incomingLines().begin()->first->original() ->decayMode(); if(!dm) dm = decay->incomingLines().begin()->first->copy() ->decayMode(); if(!dm) dm = decay->incomingLines().begin()->first->progenitor()->decayMode(); // otherwise make a string and look it up if(!dm) { string tag = decay->incomingLines().begin()->first->original()->dataPtr()->name() + "->"; OrderedParticles outgoing; for(map::const_iterator it=decay->outgoingLines().begin();it!=decay->outgoingLines().end();++it) { if(abs(decay->incomingLines().begin()->first->original()->id()) == ParticleID::t && abs(it->first->original()->id())==ParticleID::Wplus && decay->treelinks().size() == 1) { ShowerTreePtr Wtree = decay->treelinks().begin()->first; for(map::const_iterator it2=Wtree->outgoingLines().begin();it2!=Wtree->outgoingLines().end();++it2) { outgoing.insert(it2->first->original()->dataPtr()); } } else { outgoing.insert(it->first->original()->dataPtr()); } } for(OrderedParticles::const_iterator it=outgoing.begin(); it!=outgoing.end();++it) { if(it!=outgoing.begin()) tag += ","; tag +=(**it).name(); } tag += ";"; dm = findDecayMode(tag); } if(dm) _decayme = dynamic_ptr_cast(dm->decayer()); // set the ShowerTree to be showered currentTree(decay); decay->applyTransforms(); hardTree(HardTreePtr()); unsigned int interactionTry=0; do { try { // generate the showering doShowering(false,XCPtr()); // if no vetos // force calculation of spin correlations SpinPtr spInfo = decay->incomingLines().begin()->first->progenitor()->spinInfo(); if(spInfo) { if(!spInfo->developed()) spInfo->needsUpdate(); spInfo->develop(); } // and then return return; } catch (InteractionVeto) { currentTree()->clear(); ++interactionTry; } } while(interactionTry<=5); throw Exception() << "Too many tries for QED shower in Evolver::showerDecay()" << Exception::eventerror; } bool Evolver::spaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction::Type type, Branching fb) { // too many tries if(_nFSR>=_maxTryFSR) { ++_nFailedFSR; // too many failed events if(_nFailedFSR>=_maxFailFSR) throw Exception() << "Too many events have failed due to too many shower emissions, in\n" << "Evolver::timeLikeShower(). Terminating run\n" << Exception::runerror; throw Exception() << "Too many attempted emissions in Evolver::timeLikeShower()\n" << Exception::eventerror; } // generate the emission ShowerParticleVector children; int ntry=0; // generate the emission if(!fb.kinematics) fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type, HardBranchingPtr()); // no emission, return if(!fb.kinematics) return false; Branching fc[2]; bool setupChildren = true; while (ntry<50) { if(particle->virtualMass()==ZERO) particle->virtualMass(_progenitor->progenitor()->mass()); fc[0] = Branching(); fc[1] = Branching(); ++ntry; assert(fb.kinematics); // has emitted // Assign the shower kinematics to the emitting particle. if(setupChildren) { ++_nFSR; // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the ShowerParticle objects for the two children children = createTimeLikeChildren(particle,fb.ids); // updateChildren the children particle->showerKinematics()-> updateChildren(particle, children, fb.type,_reconOpt>=3); setupChildren = false; } // select branchings for children fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass, type,HardBranchingPtr()); fc[1] = selectTimeLikeBranching (children[1],type,HardBranchingPtr()); // old default if(_reconOpt==0) { // shower the first particle _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); _currenttree->addInitialStateBranching(particle,children[0],children[1]); if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); updateHistory(children[1]); // branching has happened break; } // Herwig default else if(_reconOpt==1) { // shower the first particle _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); _currenttree->addInitialStateBranching(particle,children[0],children[1]); if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); updateHistory(children[1]); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); // clean up the vetoed emission if(particle->virtualMass()==ZERO) { particle->showerKinematics(ShoKinPtr()); for(unsigned int ix=0;ixabandonChild(children[ix]); children.clear(); particle->vetoEmission(fb.type,fb.kinematics->scale()); // generate the new emission fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type, HardBranchingPtr()); // no emission, return if(!fb.kinematics) { return false; } setupChildren = true; continue; } else break; } else if(_reconOpt>=2) { // cut-off masses for the branching const vector & virtualMasses = fb.sudakov->virtualMasses(fb.ids); // compute the masses of the children Energy masses[3]; // space-like children masses[1] = children[0]->virtualMass(); // time-like child if(fc[1].kinematics) { const vector & vm = fc[1].sudakov->virtualMasses(fc[1].ids); Energy2 q2 = fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale()); if(fc[1].ids[0]!=ParticleID::g) q2 += sqr(vm[0]); masses[2] = sqrt(q2); } else { masses[2] = virtualMasses[2]; } masses[0]=particle->virtualMass(); double z = fb.kinematics->z(); Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2])); if(pt2>=ZERO) { break; } else { // reset the scales for the children for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].kinematics) children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); else { if(ix==0) children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy); else children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); } } children[0]->virtualMass(_progenitor->progenitor()->mass()); children[1]->virtualMass(ZERO); } } }; if(_reconOpt>=2) { // In the case of splittings which involves coloured particles, // set properly the colour flow of the branching. // update the history if needed _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); _currenttree->addInitialStateBranching(particle,children[0],children[1]); // shower the first particle if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); updateHistory(children[1]); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); } // branching has happened return true; } vector Evolver::setupShower(bool hard) { // generate POWHEG hard emission if needed if(_hardEmissionMode>0) hardestEmission(hard); ShowerInteraction::Type inter = interactions_[0]; - if(_hardtree&&inter!=ShowerInteraction::Both) { + if(_hardtree&&inter!=ShowerInteraction::QEDQCD && inter!=ShowerInteraction::ALL) { inter = _hardtree->interaction(); } // set the initial colour partners setEvolutionPartners(hard,inter,false); // generate hard me if needed if(_hardEmissionMode==0 || (!hard && _hardEmissionMode==-1)) hardMatrixElementCorrection(hard); // get the particles to be showered vector particlesToShower = currentTree()->extractProgenitors(); // remake the colour partners if needed if(_currenttree->hardMatrixElementCorrection()) { setEvolutionPartners(hard,interactions_[0],true); _currenttree->resetShowerProducts(); } // return the answer return particlesToShower; } void Evolver::setEvolutionPartners(bool hard,ShowerInteraction::Type type, bool clear) { // match the particles in the ShowerTree and hardTree if(hardTree() && !hardTree()->connect(currentTree())) throw Exception() << "Can't match trees in " << "Evolver::setEvolutionPartners()" << Exception::eventerror; // extract the progenitors vector particles = currentTree()->extractProgenitorParticles(); // clear the partners if needed if(clear) { for(unsigned int ix=0;ixpartner(ShowerParticlePtr()); particles[ix]->clearPartners(); } } // sort out the colour partners if(hardTree()) { // find the partner for(unsigned int ix=0;ixparticles()[particles[ix]]->colourPartner(); if(!partner) continue; for(map::const_iterator it=hardTree()->particles().begin(); it!=hardTree()->particles().end();++it) { if(it->second==partner) particles[ix]->partner(it->first); } if(!particles[ix]->partner()) throw Exception() << "Can't match partners in " << "Evolver::setEvolutionPartners()" << Exception::eventerror; } } // Set the initial evolution scales showerModel()->partnerFinder()-> setInitialEvolutionScales(particles,!hard,type,!_hardtree); if(hardTree() && _hardPOWHEG) { bool tooHard=false; map::const_iterator eit=hardTree()->particles().end(); for(unsigned int ix=0;ix::const_iterator mit = hardTree()->particles().find(particles[ix]); Energy hardScale(ZERO); ShowerPartnerType::Type type(ShowerPartnerType::Undefined); // final-state if(particles[ix]->isFinalState()) { if(mit!= eit && !mit->second->children().empty()) { hardScale = mit->second->scale(); type = mit->second->type(); } } // initial-state else { if(mit!= eit && mit->second->parent()) { hardScale = mit->second->parent()->scale(); type = mit->second->parent()->type(); } } if(type!=ShowerPartnerType::Undefined) { if(type==ShowerPartnerType::QED) { tooHard |= particles[ix]->scales().QED_noAOscales().QCD_c_noAOscales().QCD_ac_noAOscales().EWchildren().empty()) { ShowerParticleVector theChildren; for(unsigned int ix=0;ixchildren().size();++ix) { ShowerParticlePtr part = dynamic_ptr_cast (particle->children()[ix]); theChildren.push_back(part); } // update the history if needed if(particle==_currenttree->getFinalStateShowerProduct(_progenitor)) _currenttree->updateFinalStateShowerProduct(_progenitor, particle,theChildren); _currenttree->addFinalStateBranching(particle,theChildren); for(unsigned int ix=0;ix::const_iterator eit=hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && !mit->second->children().empty() ) { bool output=truncatedTimeLikeShower(progenitor()->progenitor(), mit->second ,type,Branching(),true); if(output) updateHistory(progenitor()->progenitor()); return output; } } bool output = hardOnly() ? false : timeLikeShower(progenitor()->progenitor() ,type,Branching(),true) ; if(output) updateHistory(progenitor()->progenitor()); return output; } bool Evolver::startSpaceLikeShower(PPtr parent, ShowerInteraction::Type type) { if(hardTree()) { map::const_iterator eit =hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && mit->second->parent() ) { return truncatedSpaceLikeShower( progenitor()->progenitor(), parent, mit->second->parent(), type ); } } return hardOnly() ? false : spaceLikeShower(progenitor()->progenitor(),parent,type); } bool Evolver:: startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction::Type type) { _nFSR = 0; if(hardTree()) { map::const_iterator eit =hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && mit->second->parent() ) { HardBranchingPtr branch=mit->second; while(branch->parent()) branch=branch->parent(); return truncatedSpaceLikeDecayShower(progenitor()->progenitor(),maxScales, minimumMass, branch ,type, Branching()); } } return hardOnly() ? false : spaceLikeDecayShower(progenitor()->progenitor(),maxScales,minimumMass,type,Branching()); } bool Evolver::timeLikeVetoed(const Branching & fb, ShowerParticlePtr particle) { // work out type of interaction - ShowerInteraction::Type type = fb.type==ShowerPartnerType::QED ? - ShowerInteraction::QED : ShowerInteraction::QCD; + ShowerInteraction::Type type = convertInteraction(fb.type); // check whether emission was harder than largest pt of hard subprocess if ( hardVetoFS() && fb.kinematics->pT() > _progenitor->maxHardPt() ) return true; // soft matrix element correction veto if( softMEC()) { if(_hardme && _hardme->hasMECorrection()) { if(_hardme->softMatrixElementVeto(_progenitor,particle,fb)) return true; } else if(_decayme && _decayme->hasMECorrection()) { if(_decayme->softMatrixElementVeto(_progenitor,particle,fb)) return true; } } // veto on maximum pt if(fb.kinematics->pT()>_progenitor->maximumpT(type)) return true; // general vetos if (fb.kinematics && !_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoTimeLike(_progenitor,particle,fb); switch((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } } if(vetoed) return true; } if ( ShowerHandler::currentHandler()->firstInteraction() && ShowerHandler::currentHandler()->profileScales() ) { double weight = ShowerHandler::currentHandler()->profileScales()-> hardScaleProfile(_progenitor->hardScale(),fb.kinematics->pT()); if ( UseRandom::rnd() > weight ) return true; } return false; } bool Evolver::spaceLikeVetoed(const Branching & bb, ShowerParticlePtr particle) { // work out type of interaction - ShowerInteraction::Type type = bb.type==ShowerPartnerType::QED ? - ShowerInteraction::QED : ShowerInteraction::QCD; + ShowerInteraction::Type type = convertInteraction(bb.type); // check whether emission was harder than largest pt of hard subprocess if (hardVetoIS() && bb.kinematics->pT() > _progenitor->maxHardPt()) return true; // apply the soft correction if( softMEC() && _hardme && _hardme->hasMECorrection() ) { if(_hardme->softMatrixElementVeto(_progenitor,particle,bb)) return true; } // the more general vetos // check vs max pt for the shower if(bb.kinematics->pT()>_progenitor->maximumpT(type)) return true; if (!_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoSpaceLike(_progenitor,particle,bb); switch ((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } } if (vetoed) return true; } if ( ShowerHandler::currentHandler()->firstInteraction() && ShowerHandler::currentHandler()->profileScales() ) { double weight = ShowerHandler::currentHandler()->profileScales()-> hardScaleProfile(_progenitor->hardScale(),bb.kinematics->pT()); if ( UseRandom::rnd() > weight ) return true; } return false; } bool Evolver::spaceLikeDecayVetoed( const Branching & fb, ShowerParticlePtr particle) { // work out type of interaction - ShowerInteraction::Type type = fb.type==ShowerPartnerType::QED ? - ShowerInteraction::QED : ShowerInteraction::QCD; + ShowerInteraction::Type type = convertInteraction(fb.type); // apply the soft correction if( softMEC() && _decayme && _decayme->hasMECorrection() ) { if(_decayme->softMatrixElementVeto(_progenitor,particle,fb)) return true; } // veto on hardest pt in the shower if(fb.kinematics->pT()> _progenitor->maximumpT(type)) return true; // general vetos if (!_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoSpaceLike(_progenitor,particle,fb); switch((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } if (vetoed) return true; } } return false; } void Evolver::hardestEmission(bool hard) { HardTreePtr ISRTree; if( ( _hardme && _hardme->hasPOWHEGCorrection()!=0 && _hardEmissionMode< 2) || ( _decayme && _decayme->hasPOWHEGCorrection()!=0 && _hardEmissionMode!=2) ) { if(_hardme) { assert(hard); if(interaction_==4) { vector inter(2); inter[0] = ShowerInteraction::QCD; inter[1] = ShowerInteraction::QED; _hardtree = _hardme->generateHardest( currentTree(),inter ); } else { _hardtree = _hardme->generateHardest( currentTree(),interactions_ ); } } else { assert(!hard); _hardtree = _decayme->generateHardest( currentTree() ); } // store initial state POWHEG radiation if(_hardtree && _hardme && _hardme->hasPOWHEGCorrection()==1) ISRTree=_hardtree; } else if (_hardEmissionMode>1 && hard) { // Get minimum pT cutoff used in shower approximation Energy maxpt = 1.*GeV; int colouredIn = 0; int colouredOut = 0; for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if( it->second->coloured() ) colouredOut+=1; } for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it = currentTree()->incomingLines().begin(); it != currentTree()->incomingLines().end(); ++it ) { if( ! it->second->coloured() ) colouredIn+=1; } if ( theShowerApproximation ){ if ( theShowerApproximation->ffPtCut() == theShowerApproximation->fiPtCut() && theShowerApproximation->ffPtCut() == theShowerApproximation->iiPtCut() ) maxpt = theShowerApproximation->ffPtCut(); else if ( colouredIn == 2 && colouredOut == 0 ) maxpt = theShowerApproximation->iiPtCut(); else if ( colouredIn == 0 && colouredOut > 1 ) maxpt = theShowerApproximation->ffPtCut(); else if ( colouredIn == 2 && colouredOut == 1 ) maxpt = min(theShowerApproximation->iiPtCut(), theShowerApproximation->fiPtCut()); else if ( colouredIn == 1 && colouredOut > 1 ) maxpt = min(theShowerApproximation->ffPtCut(), theShowerApproximation->fiPtCut()); else maxpt = min(min(theShowerApproximation->iiPtCut(), theShowerApproximation->fiPtCut()), theShowerApproximation->ffPtCut()); } // Generate hardtree from born and real emission subprocesses _hardtree = ShowerHandler::currentHandler()->generateCKKW(currentTree()); // Find transverse momentum of hardest emission if (_hardtree){ for(set::iterator it=_hardtree->branchings().begin(); it!=_hardtree->branchings().end();++it) { if ((*it)->parent() && (*it)->status()==HardBranching::Incoming) maxpt=(*it)->branchingParticle()->momentum().perp(); if ((*it)->children().size()==2 && (*it)->status()==HardBranching::Outgoing){ if ((*it)->branchingParticle()->id()!=21 && abs((*it)->branchingParticle()->id())>5 ){ if ((*it)->children()[0]->branchingParticle()->id()==21 || abs((*it)->children()[0]->branchingParticle()->id())<6) maxpt=(*it)->children()[0]->branchingParticle()->momentum().perp(); else if ((*it)->children()[1]->branchingParticle()->id()==21 || abs((*it)->children()[1]->branchingParticle()->id())<6) maxpt=(*it)->children()[1]->branchingParticle()->momentum().perp(); } else { if ( abs((*it)->branchingParticle()->id())<6){ if (abs((*it)->children()[0]->branchingParticle()->id())<6) maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp(); else maxpt = (*it)->children()[0]->branchingParticle()->momentum().perp(); } else maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp(); } } } } // Hardest (pt) emission should be the first powheg emission. maxpt=min(sqrt(ShowerHandler::currentHandler()->lastXCombPtr()->lastShowerScale()),maxpt); // Set maxpt to pT of emission when showering POWHEG real-emission subprocesses if (!isPowhegSEvent && !isPowhegHEvent){ vector outGluon; vector outQuark; map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it; for( it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if ( abs(it->second->id())< 6) outQuark.push_back(it->second->id()); if ( it->second->id()==21 ) outGluon.push_back(it->second->id()); } if (outGluon.size() + outQuark.size() == 1){ for( it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if ( abs(it->second->id())< 6 || it->second->id()==21 ) maxpt = it->second->momentum().perp(); } } else if (outGluon.size() + outQuark.size() > 1){ // assume qqbar pair from a Z/gamma if (outGluon.size()==1 && outQuark.size() == 2 && outQuark[0]==-outQuark[1]){ for( it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if ( it->second->id()==21 ) maxpt = it->second->momentum().perp(); } } // otherwise take the lowest pT avoiding born DY events else { maxpt = generator()->maximumCMEnergy(); for( it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if ( abs(it->second->id())< 6 || it->second->id()==21 ) maxpt = min(maxpt,it->second->momentum().perp()); } } } } // set maximum pT for subsequent emissions from S events if ( isPowhegSEvent || (!isPowhegSEvent && !isPowhegHEvent)){ for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT(maxpt, ShowerInteraction::QCD ); } for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it = currentTree()->incomingLines().begin(); it != currentTree()->incomingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT(maxpt, ShowerInteraction::QCD ); } } } else _hardtree = ShowerHandler::currentHandler()->generateCKKW(currentTree()); // if hard me doesn't have a FSR powheg // correction use decay powheg correction if (_hardme && _hardme->hasPOWHEGCorrection()<2) { // check for intermediate colour singlet resonance const ParticleVector inter = _hardme->subProcess()->intermediates(); if (inter.size()!=1 || inter[0]->momentum().m2()/GeV2 < 0 || inter[0]->dataPtr()->iColour()!=PDT::Colour0){ if(_hardtree) connectTrees(currentTree(),_hardtree,hard); return; } map out = currentTree()->outgoingLines(); // ignore cases where outgoing particles are not coloured if (out.size()!=2 || out. begin()->second->dataPtr()->iColour()==PDT::Colour0 || out.rbegin()->second->dataPtr()->iColour()==PDT::Colour0) { if(_hardtree) connectTrees(currentTree(),_hardtree,hard); return; } // look up decay mode tDMPtr dm; string tag; string inParticle = inter[0]->dataPtr()->name() + "->"; vector outParticles; outParticles.push_back(out.begin ()->first->progenitor()->dataPtr()->name()); outParticles.push_back(out.rbegin()->first->progenitor()->dataPtr()->name()); for (int it=0; it<2; ++it){ tag = inParticle + outParticles[it] + "," + outParticles[(it+1)%2] + ";"; dm = generator()->findDecayMode(tag); if(dm) break; } // get the decayer HwDecayerBasePtr decayer; if(dm) decayer = dynamic_ptr_cast(dm->decayer()); // check if decayer has a FSR POWHEG correction if (!decayer || decayer->hasPOWHEGCorrection()<2){ if(_hardtree) connectTrees(currentTree(),_hardtree,hard); return; } // generate the hardest emission ShowerDecayMap decay; PPtr in = new_ptr(*inter[0]); ShowerTreePtr decayTree = new_ptr(ShowerTree(in, decay)); HardTreePtr FSRTree = decayer->generateHardest(decayTree); if (!FSRTree) { if(_hardtree) connectTrees(currentTree(),_hardtree,hard); return; } // if there is no ISRTree make _hardtree from FSRTree if (!ISRTree){ vector inBranch,hardBranch; for(map::const_iterator cit =currentTree()->incomingLines().begin(); cit!=currentTree()->incomingLines().end();++cit ) { inBranch.push_back(new_ptr(HardBranching(cit->second,SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); inBranch.back()->beam(cit->first->original()->parents()[0]); hardBranch.push_back(inBranch.back()); } if(inBranch[0]->branchingParticle()->dataPtr()->coloured()) { inBranch[0]->colourPartner(inBranch[1]); inBranch[1]->colourPartner(inBranch[0]); } for(set::iterator it=FSRTree->branchings().begin(); it!=FSRTree->branchings().end();++it) { if((**it).branchingParticle()->id()!=in->id()) hardBranch.push_back(*it); } hardBranch[2]->colourPartner(hardBranch[3]); hardBranch[3]->colourPartner(hardBranch[2]); HardTreePtr newTree = new_ptr(HardTree(hardBranch,inBranch, ShowerInteraction::QCD)); _hardtree = newTree; } // Otherwise modify the ISRTree to include the emission in FSRTree else { vector FSROut, ISROut; set::iterator itFSR, itISR; // get outgoing particles for(itFSR =FSRTree->branchings().begin(); itFSR!=FSRTree->branchings().end();++itFSR){ if ((**itFSR).status()==HardBranching::Outgoing) FSROut.push_back((*itFSR)->branchingParticle()); } for(itISR =ISRTree->branchings().begin(); itISR!=ISRTree->branchings().end();++itISR){ if ((**itISR).status()==HardBranching::Outgoing) ISROut.push_back((*itISR)->branchingParticle()); } // find COM frame formed by outgoing particles LorentzRotation eventFrameFSR, eventFrameISR; eventFrameFSR = ((FSROut[0]->momentum()+FSROut[1]->momentum()).findBoostToCM()); eventFrameISR = ((ISROut[0]->momentum()+ISROut[1]->momentum()).findBoostToCM()); // find rotation between ISR and FSR frames int j=0; if (ISROut[0]->id()!=FSROut[0]->id()) j=1; eventFrameISR.rotateZ( (eventFrameFSR*FSROut[0]->momentum()).phi()- (eventFrameISR*ISROut[j]->momentum()).phi() ); eventFrameISR.rotateY( (eventFrameFSR*FSROut[0]->momentum()).theta()- (eventFrameISR*ISROut[j]->momentum()).theta() ); eventFrameISR.invert(); for (itFSR=FSRTree->branchings().begin(); itFSR!=FSRTree->branchings().end();++itFSR){ if ((**itFSR).branchingParticle()->id()==in->id()) continue; for (itISR =ISRTree->branchings().begin(); itISR!=ISRTree->branchings().end();++itISR){ if ((**itISR).status()==HardBranching::Incoming) continue; if ((**itFSR).branchingParticle()->id()== (**itISR).branchingParticle()->id()){ // rotate FSRTree particle to ISRTree event frame (**itISR).branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).branchingParticle()->momentum()); (**itISR).branchingParticle()->rescaleMass(); // add the children of the FSRTree particles to the ISRTree if(!(**itFSR).children().empty()){ (**itISR).addChild((**itFSR).children()[0]); (**itISR).addChild((**itFSR).children()[1]); // rotate momenta to ISRTree event frame (**itISR).children()[0]->branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).children()[0]->branchingParticle()->momentum()); (**itISR).children()[1]->branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).children()[1]->branchingParticle()->momentum()); } } } } _hardtree = ISRTree; } } if(_hardtree){ connectTrees(currentTree(),_hardtree,hard); } } bool Evolver::truncatedTimeLikeShower(tShowerParticlePtr particle, HardBranchingPtr branch, ShowerInteraction::Type type, Branching fb, bool first) { // select a branching if we don't have one if(!fb.kinematics) fb = selectTimeLikeBranching(particle,type,branch); // must be an emission, the forced one it not a truncated one assert(fb.kinematics); ShowerParticleVector children; int ntry=0; Branching fc[2]; bool setupChildren = true; while (ntry<50) { if(!fc[0].hard) fc[0] = Branching(); if(!fc[1].hard) fc[1] = Branching(); ++ntry; // Assign the shower kinematics to the emitting particle. if(setupChildren) { ++_nFSR; // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // if not hard generate phi if(!fb.hard) fb.kinematics->phi(fb.sudakov->generatePhiForward(*particle,fb.ids,fb.kinematics)); // create the children children = createTimeLikeChildren(particle,fb.ids); // update the children particle->showerKinematics()-> updateChildren(particle, children,fb.type,_reconOpt>=3); setupChildren = false; } // select branchings for children if(!fc[0].kinematics) { // select branching for first particle if(!fb.hard && fb.iout ==1 ) fc[0] = selectTimeLikeBranching(children[0],type,branch); else if(fb.hard && !branch->children()[0]->children().empty() ) fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); else fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); } // select branching for the second particle if(!fc[1].kinematics) { // select branching for first particle if(!fb.hard && fb.iout ==2 ) fc[1] = selectTimeLikeBranching(children[1],type,branch); else if(fb.hard && !branch->children()[1]->children().empty() ) fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); else fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); } // old default if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) { // shower the first particle if(fc[0].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 1) truncatedTimeLikeShower(children[0],branch,type,fc[0],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 2) truncatedTimeLikeShower(children[1],branch,type,fc[1],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[1]->children().empty() ) truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false); else timeLikeShower(children[1],type,fc[1],false); } if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); break; } // H7 default else if(_reconOpt==1) { // shower the first particle if(fc[0].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 1) truncatedTimeLikeShower(children[0],branch,type,fc[0],false); else timeLikeShower(children[0],type,fc[0],false); } if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 2) truncatedTimeLikeShower(children[1],branch,type,fc[1],false); else timeLikeShower(children[1],type,fc[1],false); } if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); // clean up the vetoed emission if(particle->virtualMass()==ZERO) { particle->showerKinematics(ShoKinPtr()); for(unsigned int ix=0;ixabandonChild(children[ix]); children.clear(); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); particle->vetoEmission(fb.type,fb.kinematics->scale()); // generate the new emission fb = selectTimeLikeBranching(particle,type,branch); // must be at least hard emission assert(fb.kinematics); setupChildren = true; continue; } else break; } else if(_reconOpt>=2) { // cut-off masses for the branching const vector & virtualMasses = fb.sudakov->virtualMasses(fb.ids); // compute the masses of the children Energy masses[3]; for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].kinematics) { const vector & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids); Energy2 q2 = fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale()); if(fc[ix].ids[0]!=ParticleID::g) q2 += sqr(vm[0]); masses[ix+1] = sqrt(q2); } else { masses[ix+1] = virtualMasses[ix+1]; } } masses[0] = fb.ids[0]!=ParticleID::g ? virtualMasses[0] : ZERO; double z = fb.kinematics->z(); Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0])) - sqr(masses[1])*(1.-z) - sqr(masses[2])*z; if(pt2>=ZERO) { break; } // if only the hard emission have to accept it else if ((fc[0].hard && !fc[1].kinematics) || (fc[1].hard && !fc[0].kinematics) ) { break; } else { // reset the scales for the children for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].hard) continue; if(fc[ix].kinematics && ! fc[ix].hard ) children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); else children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); children[ix]->virtualMass(ZERO); } } } }; if(_reconOpt>=2) { // shower the first particle if(fc[0].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 1) truncatedTimeLikeShower(children[0],branch,type,fc[0],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 2) truncatedTimeLikeShower(children[1],branch,type,fc[1],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[1]->children().empty() ) truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false); else timeLikeShower(children[1],type,fc[1],false); } if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); } if(first&&!children.empty()) particle->showerKinematics()->resetChildren(particle,children); if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } bool Evolver::truncatedSpaceLikeShower(tShowerParticlePtr particle, PPtr beam, HardBranchingPtr branch, ShowerInteraction::Type type) { tcPDFPtr pdf; if(ShowerHandler::currentHandler()->firstPDF().particle() == beamParticle()) pdf = ShowerHandler::currentHandler()->firstPDF().pdf(); if(ShowerHandler::currentHandler()->secondPDF().particle() == beamParticle()) pdf = ShowerHandler::currentHandler()->secondPDF().pdf(); Energy freeze = ShowerHandler::currentHandler()->pdfFreezingScale(); Branching bb; // parameters of the force branching double z(0.); HardBranchingPtr timelike; for( unsigned int ix = 0; ix < branch->children().size(); ++ix ) { if( branch->children()[ix]->status() ==HardBranching::Outgoing) { timelike = branch->children()[ix]; } if( branch->children()[ix]->status() ==HardBranching::Incoming ) z = branch->children()[ix]->z(); } // generate truncated branching tcPDPtr part[2]; if(z>=0.&&z<=1.) { while (true) { if( !isTruncatedShowerON() || hardOnly() ) break; bb = splittingGenerator()->chooseBackwardBranching( *particle, beam, 1., beamParticle(), type , pdf,freeze); if( !bb.kinematics || bb.kinematics->scale() < branch->scale() ) { bb = Branching(); break; } // particles as in Sudakov form factor part[0] = getParticleData( bb.ids[0] ); part[1] = getParticleData( bb.ids[2] ); //is emitter anti-particle if( particle->id() != bb.ids[1]) { if( part[0]->CC() ) part[0] = part[0]->CC(); if( part[1]->CC() ) part[1] = part[1]->CC(); } double zsplit = bb.kinematics->z(); // apply the vetos for the truncated shower // if doesn't carry most of momentum - ShowerInteraction::Type type2 = bb.type==ShowerPartnerType::QED ? - ShowerInteraction::QED : ShowerInteraction::QCD; + ShowerInteraction::Type type2 = convertInteraction(bb.type); if(type2==branch->sudakov()->interactionType() && zsplit < 0.5) { particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } // others if( part[0]->id() != particle->id() || // if particle changes type bb.kinematics->pT() > progenitor()->maximumpT(type2) || // pt veto bb.kinematics->scale() < branch->scale()) { // angular ordering veto particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } // and those from the base class if(spaceLikeVetoed(bb,particle)) { particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } break; } } if( !bb.kinematics ) { //do the hard emission ShoKinPtr kinematics = branch->sudakov()->createInitialStateBranching( branch->scale(), z, branch->phi(), branch->children()[0]->pT() ); kinematics->initialize( *particle, beam ); // assign the splitting function and shower kinematics particle->showerKinematics( kinematics ); if(kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(kinematics->pT()); // For the time being we are considering only 1->2 branching // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr( ShowerParticle( branch->branchingParticle()->dataPtr(), false ) ); ShowerParticlePtr otherChild = new_ptr( ShowerParticle( timelike->branchingParticle()->dataPtr(), true, true ) ); ShowerParticleVector theChildren; theChildren.push_back( particle ); theChildren.push_back( otherChild ); particle->showerKinematics()-> updateParent( newParent, theChildren, branch->type()); // update the history if needed currentTree()->updateInitialStateShowerProduct( progenitor(), newParent ); currentTree()->addInitialStateBranching( particle, newParent, otherChild ); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower bool emitted=false; if(!hardOnly()) { if( branch->parent() ) { emitted = truncatedSpaceLikeShower( newParent, beam, branch->parent() , type); } else { emitted = spaceLikeShower( newParent, beam , type); } } if( !emitted ) { if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) { kinematics->updateLast( newParent, ZERO, ZERO ); } else { pair kt = intrinsicpT()[progenitor()]; kinematics->updateLast( newParent, kt.first*cos( kt.second ), kt.first*sin( kt.second ) ); } } particle->showerKinematics()-> updateChildren( newParent, theChildren,bb.type,false); if(hardOnly()) return true; // perform the shower of the final-state particle if( timelike->children().empty() ) { timeLikeShower( otherChild , type,Branching(),true); } else { truncatedTimeLikeShower( otherChild, timelike , type,Branching(), true); } updateHistory(otherChild); // return the emitted return true; } // assign the splitting function and shower kinematics particle->showerKinematics( bb.kinematics ); if(bb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(bb.kinematics->pT()); // For the time being we are considering only 1->2 branching // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr( ShowerParticle( part[0], false ) ); ShowerParticlePtr otherChild = new_ptr( ShowerParticle( part[1], true, true ) ); ShowerParticleVector theChildren; theChildren.push_back( particle ); theChildren.push_back( otherChild ); particle->showerKinematics()-> updateParent( newParent, theChildren, bb.type); // update the history if needed currentTree()->updateInitialStateShowerProduct( progenitor(), newParent ); currentTree()->addInitialStateBranching( particle, newParent, otherChild ); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower bool emitted = truncatedSpaceLikeShower( newParent, beam, branch,type); // now reconstruct the momentum if( !emitted ) { if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) { bb.kinematics->updateLast( newParent, ZERO, ZERO ); } else { pair kt = intrinsicpT()[ progenitor() ]; bb.kinematics->updateLast( newParent, kt.first*cos( kt.second ), kt.first*sin( kt.second ) ); } } particle->showerKinematics()-> updateChildren( newParent, theChildren, bb.type,false); // perform the shower of the final-state particle timeLikeShower( otherChild , type,Branching(),true); updateHistory(otherChild); // return the emitted return true; } bool Evolver:: truncatedSpaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass, HardBranchingPtr branch, ShowerInteraction::Type type, Branching fb) { // select a branching if we don't have one if(!fb.kinematics) fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch); // must be an emission, the forced one it not a truncated one assert(fb.kinematics); ShowerParticleVector children; int ntry=0; Branching fc[2]; bool setupChildren = true; while (ntry<50) { if(!fc[0].hard) fc[0] = Branching(); if(!fc[1].hard) fc[1] = Branching(); ++ntry; if(setupChildren) { ++_nFSR; // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the ShowerParticle objects for the two children children = createTimeLikeChildren(particle,fb.ids); // updateChildren the children particle->showerKinematics()-> updateChildren(particle, children, fb.type,_reconOpt>=3); setupChildren = false; } // select branchings for children if(!fc[0].kinematics) { if(children[0]->id()==particle->id()) { // select branching for first particle if(!fb.hard) fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,branch); else if(fb.hard && ! branch->children()[0]->children().empty() ) fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, branch->children()[0]); else fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, HardBranchingPtr()); } else { // select branching for first particle if(fb.hard && !branch->children()[0]->children().empty() ) fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); else fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); } } // select branching for the second particle if(!fc[1].kinematics) { if(children[1]->id()==particle->id()) { // select branching for first particle if(!fb.hard) fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,branch); else if(fb.hard && ! branch->children()[1]->children().empty() ) fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, branch->children()[1]); else fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, HardBranchingPtr()); } else { if(fb.hard && !branch->children()[1]->children().empty() ) fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); else fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); } } // old default if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) { // update the history if needed currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); currentTree()->addInitialStateBranching(particle,children[0],children[1]); // shower the first particle if(fc[0].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[0]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[0]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } } // shower the second particle if(fc[1].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[1]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[1]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); // normal shower else timeLikeShower(children[0],type,fc[1],false); } } updateHistory(children[1]); // branching has happened break; } // H7 default else if(_reconOpt==1) { // update the history if needed currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); currentTree()->addInitialStateBranching(particle,children[0],children[1]); // shower the first particle if(fc[0].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[0]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[0]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } } // shower the second particle if(fc[1].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[1]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[1]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); // normal shower else timeLikeShower(children[0],type,fc[1],false); } } // clean up the vetoed emission if(particle->virtualMass()==ZERO) { particle->showerKinematics(ShoKinPtr()); for(unsigned int ix=0;ixabandonChild(children[ix]); children.clear(); particle->vetoEmission(fb.type,fb.kinematics->scale()); // generate the new emission fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch); // must be at least hard emission assert(fb.kinematics); setupChildren = true; continue; } else { updateHistory(children[1]); break; } } else if(_reconOpt>=2) { // cut-off masses for the branching const vector & virtualMasses = fb.sudakov->virtualMasses(fb.ids); // compute the masses of the children Energy masses[3]; // space-like children masses[1] = children[0]->virtualMass(); // time-like child if(fc[1].kinematics) { const vector & vm = fc[1].sudakov->virtualMasses(fc[1].ids); Energy2 q2 = fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale()); if(fc[1].ids[0]!=ParticleID::g) q2 += sqr(vm[0]); masses[2] = sqrt(q2); } else { masses[2] = virtualMasses[2]; } masses[0]=particle->virtualMass(); double z = fb.kinematics->z(); Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2])); if(pt2>=ZERO) { break; } else { // reset the scales for the children for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].kinematics) children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); else { if(ix==0) children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy); else children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); } } children[0]->virtualMass(_progenitor->progenitor()->mass()); children[1]->virtualMass(ZERO); } } }; if(_reconOpt>=2) { // update the history if needed currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); currentTree()->addInitialStateBranching(particle,children[0],children[1]); // shower the first particle if(fc[0].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[0]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[0]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } } // shower the second particle if(fc[1].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[1]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[1]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); // normal shower else timeLikeShower(children[0],type,fc[1],false); } } updateHistory(children[1]); } return true; } bool Evolver::constructDecayTree(vector & particlesToShower, ShowerInteraction::Type inter) { Energy ptmax(-GeV); // get the maximum pt is all ready a hard tree if(hardTree()) { for(unsigned int ix=0;ixmaximumpT(inter)>ptmax&& particlesToShower[ix]->progenitor()->isFinalState()) ptmax = particlesToShower[ix]->maximumpT(inter); } } vector spaceBranchings,allBranchings; for(unsigned int ix=0;ixprogenitor()->isFinalState()) { HardBranchingPtr newBranch; if(particlesToShower[ix]->hasEmitted()) { newBranch = new_ptr(HardBranching(particlesToShower[ix]->progenitor(), particlesToShower[ix]->progenitor()-> showerKinematics()->SudakovFormFactor(), HardBranchingPtr(),HardBranching::Outgoing)); constructTimeLikeLine(newBranch,particlesToShower[ix]->progenitor()); } else { newBranch = new_ptr(HardBranching(particlesToShower[ix]->progenitor(), SudakovPtr(),HardBranchingPtr(), HardBranching::Outgoing)); } allBranchings.push_back(newBranch); } else { HardBranchingPtr newBranch; if(particlesToShower[ix]->hasEmitted()) { newBranch = new_ptr(HardBranching(particlesToShower[ix]->progenitor(), particlesToShower[ix]->progenitor()-> showerKinematics()->SudakovFormFactor(), HardBranchingPtr(),HardBranching::Decay)); constructTimeLikeLine(newBranch,particlesToShower[ix]->progenitor()); HardBranchingPtr last=newBranch; do { for(unsigned int ix=0;ixchildren().size();++ix) { if(last->children()[ix]->branchingParticle()->id()== particlesToShower[ix]->id()) { last = last->children()[ix]; continue; } } } while(!last->children().empty()); last->status(HardBranching::Incoming); spaceBranchings.push_back(newBranch); allBranchings .push_back(last); } else { newBranch = new_ptr(HardBranching(particlesToShower[ix]->progenitor(), SudakovPtr(),HardBranchingPtr(), HardBranching::Incoming)); spaceBranchings.push_back(newBranch); allBranchings .push_back(newBranch); } } } HardTreePtr QCDTree = new_ptr(HardTree(allBranchings,spaceBranchings,inter)); // set the charge partners ShowerParticleVector particles; particles.push_back(spaceBranchings.back()->branchingParticle()); for(set::iterator cit=QCDTree->branchings().begin(); cit!=QCDTree->branchings().end();++cit) { if((*cit)->status()==HardBranching::Outgoing) particles.push_back((*cit)->branchingParticle()); } // get the partners showerModel()->partnerFinder()->setInitialEvolutionScales(particles,true,inter,true); // do the inverse recon if(!showerModel()->kinematicsReconstructor()-> deconstructDecayJets(QCDTree,this,inter)) { return false; } // clear the old shower currentTree()->clear(); // set the hard tree hardTree(QCDTree); // set the charge partners setEvolutionPartners(false,inter,false); // get the particles to be showered map::const_iterator cit; map::const_iterator cjt; particlesToShower.clear(); // incoming particles for(cit=currentTree()->incomingLines().begin(); cit!=currentTree()->incomingLines().end();++cit) particlesToShower.push_back(((*cit).first)); assert(particlesToShower.size()==1); // outgoing particles for(cjt=currentTree()->outgoingLines().begin(); cjt!=currentTree()->outgoingLines().end();++cjt) { particlesToShower.push_back(((*cjt).first)); if(ptmax>ZERO) particlesToShower.back()->maximumpT(ptmax,inter); } for(unsigned int ix=0;ix::const_iterator eit=hardTree()->particles().end(), mit = hardTree()->particles().find(particlesToShower[ix]->progenitor()); if( mit != eit) { if(mit->second->status()==HardBranching::Outgoing) particlesToShower[ix]->progenitor()->set5Momentum(mit->second->pVector()); } } return true; } bool Evolver::constructHardTree(vector & particlesToShower, ShowerInteraction::Type inter) { bool noEmission = true; vector spaceBranchings,allBranchings; for(unsigned int ix=0;ixprogenitor()->isFinalState()) { HardBranchingPtr newBranch; if(particlesToShower[ix]->hasEmitted()) { noEmission = false; newBranch = new_ptr(HardBranching(particlesToShower[ix]->progenitor(), particlesToShower[ix]->progenitor()-> showerKinematics()->SudakovFormFactor(), HardBranchingPtr(),HardBranching::Outgoing)); constructTimeLikeLine(newBranch,particlesToShower[ix]->progenitor()); } else { newBranch = new_ptr(HardBranching(particlesToShower[ix]->progenitor(), SudakovPtr(),HardBranchingPtr(), HardBranching::Outgoing)); } allBranchings.push_back(newBranch); } else { HardBranchingPtr first,last; if(!particlesToShower[ix]->progenitor()->parents().empty()) { noEmission = false; constructSpaceLikeLine(particlesToShower[ix]->progenitor(), first,last,SudakovPtr(), particlesToShower[ix]->original()->parents()[0]); } else { first = new_ptr(HardBranching(particlesToShower[ix]->progenitor(), SudakovPtr(),HardBranchingPtr(), HardBranching::Incoming)); if(particlesToShower[ix]->original()->parents().empty()) first->beam(particlesToShower[ix]->original()); else first->beam(particlesToShower[ix]->original()->parents()[0]); last = first; } spaceBranchings.push_back(first); allBranchings.push_back(last); } } if(!noEmission) { HardTreePtr QCDTree = new_ptr(HardTree(allBranchings,spaceBranchings, inter)); // set the charge partners ShowerParticleVector particles; for(set::iterator cit=QCDTree->branchings().begin(); cit!=QCDTree->branchings().end();++cit) { particles.push_back((*cit)->branchingParticle()); } // get the partners showerModel()->partnerFinder()->setInitialEvolutionScales(particles,false, inter,true); // do the inverse recon if(!showerModel()->kinematicsReconstructor()-> deconstructHardJets(QCDTree,this,inter)) throw Exception() << "Can't to shower deconstruction for QED shower in" << "QEDEvolver::showerHard" << Exception::eventerror; // set the hard tree hardTree(QCDTree); } // clear the old shower currentTree()->clear(); // set the charge partners setEvolutionPartners(true,inter,false); // get the particles to be showered particlesToShower = currentTree()->extractProgenitors(); // reset momenta if(hardTree()) { for(unsigned int ix=0;ix::const_iterator eit=hardTree()->particles().end(), mit = hardTree()->particles().find(particlesToShower[ix]->progenitor()); if( mit != eit) { particlesToShower[ix]->progenitor()->set5Momentum(mit->second->showerMomentum()); } } } return true; } void Evolver::constructTimeLikeLine(tHardBranchingPtr branch, - tShowerParticlePtr particle) { + tShowerParticlePtr particle) { for(unsigned int ix=0;ixchildren().size();++ix) { HardBranching::Status status = branch->status(); tShowerParticlePtr child = dynamic_ptr_cast(particle->children()[ix]); if(child->children().empty()) { HardBranchingPtr newBranch = new_ptr(HardBranching(child,SudakovPtr(),branch,status)); branch->addChild(newBranch); } else { HardBranchingPtr newBranch = new_ptr(HardBranching(child,child->showerKinematics()->SudakovFormFactor(), branch,status)); constructTimeLikeLine(newBranch,child); branch->addChild(newBranch); } } + // \todo add EW // sort out the type of interaction if(!branch->children().empty()) { if(branch->branchingParticle()->id()==ParticleID::gamma || branch->children()[0]->branchingParticle()->id()==ParticleID::gamma || branch->children()[1]->branchingParticle()->id()==ParticleID::gamma) branch->type(ShowerPartnerType::QED); else { if(branch->branchingParticle()->id()== branch->children()[0]->branchingParticle()->id()) { if(branch->branchingParticle()->dataPtr()->iColour()==PDT::Colour8) { tShowerParticlePtr emittor = branch->branchingParticle()->showerKinematics()->z()>0.5 ? branch->children()[0]->branchingParticle() : branch->children()[1]->branchingParticle(); if(branch->branchingParticle()->colourLine()==emittor->colourLine()) branch->type(ShowerPartnerType::QCDAntiColourLine); else if(branch->branchingParticle()->antiColourLine()==emittor->antiColourLine()) branch->type(ShowerPartnerType::QCDColourLine); else assert(false); } else if(branch->branchingParticle()->colourLine()) { branch->type(ShowerPartnerType::QCDColourLine); } else if(branch->branchingParticle()->antiColourLine()) { branch->type(ShowerPartnerType::QCDAntiColourLine); } else assert(false); } else if(branch->branchingParticle()->id()==ParticleID::g && branch->children()[0]->branchingParticle()->id()== -branch->children()[1]->branchingParticle()->id()) { if(branch->branchingParticle()->showerKinematics()->z()>0.5) branch->type(ShowerPartnerType::QCDAntiColourLine); else branch->type(ShowerPartnerType::QCDColourLine); } else assert(false); } } } void Evolver::constructSpaceLikeLine(tShowerParticlePtr particle, HardBranchingPtr & first, HardBranchingPtr & last, SudakovPtr sud,PPtr beam) { if(!particle) return; if(!particle->parents().empty()) { tShowerParticlePtr parent = dynamic_ptr_cast(particle->parents()[0]); SudakovPtr newSud=particle->showerKinematics()->SudakovFormFactor(); constructSpaceLikeLine(parent,first,last,newSud,beam); } HardBranchingPtr newBranch = new_ptr(HardBranching(particle,sud,last,HardBranching::Incoming)); newBranch->beam(beam); if(!first) { first=newBranch; last =newBranch; return; } last->addChild(newBranch); tShowerParticlePtr timeChild = dynamic_ptr_cast(particle->parents()[0]->children()[1]); HardBranchingPtr timeBranch; if(!timeChild->children().empty()) { timeBranch = new_ptr(HardBranching(timeChild, timeChild->showerKinematics()->SudakovFormFactor(), last,HardBranching::Outgoing)); constructTimeLikeLine(timeBranch,timeChild); } else { timeBranch = new_ptr(HardBranching(timeChild,SudakovPtr(),last,HardBranching::Outgoing)); } last->addChild(timeBranch); + // \todo add EW // sort out the type if(last->branchingParticle() ->id() == ParticleID::gamma || newBranch->branchingParticle() ->id() == ParticleID::gamma || timeBranch->branchingParticle()->id() == ParticleID::gamma) { last->type(ShowerPartnerType::QED); } else if(last->branchingParticle()->id()==newBranch->branchingParticle()->id()) { if(last->branchingParticle()->id()==ParticleID::g) { if(last->branchingParticle()->colourLine()== newBranch->branchingParticle()->colourLine()) { last->type(ShowerPartnerType::QCDAntiColourLine); } else { last->type(ShowerPartnerType::QCDColourLine); } } else if(last->branchingParticle()->hasColour()) { last->type(ShowerPartnerType::QCDColourLine); } else if(last->branchingParticle()->hasAntiColour()) { last->type(ShowerPartnerType::QCDAntiColourLine); } else assert(false); } else if(newBranch->branchingParticle()->id()==ParticleID::g) { if(last->branchingParticle()->hasColour()) { last->type(ShowerPartnerType::QCDAntiColourLine); } else if(last->branchingParticle()->hasAntiColour()) { last->type(ShowerPartnerType::QCDColourLine); } else assert(false); } else if(newBranch->branchingParticle()->hasColour()) { last->type(ShowerPartnerType::QCDColourLine); } else if(newBranch->branchingParticle()->hasAntiColour()) { last->type(ShowerPartnerType::QCDAntiColourLine); } else { assert(false); } last=newBranch; } void Evolver::connectTrees(ShowerTreePtr showerTree, HardTreePtr hardTree, bool hard ) { ShowerParticleVector particles; // find the Sudakovs for(set::iterator cit=hardTree->branchings().begin(); cit!=hardTree->branchings().end();++cit) { // Sudakovs for ISR if((**cit).parent()&&(**cit).status()==HardBranching::Incoming) { ++_nis; IdList br(3); br[0] = (**cit).parent()->branchingParticle()->id(); br[1] = (**cit). branchingParticle()->id(); br[2] = (**cit).parent()->children()[0]==*cit ? (**cit).parent()->children()[1]->branchingParticle()->id() : (**cit).parent()->children()[0]->branchingParticle()->id(); BranchingList branchings = splittingGenerator()->initialStateBranchings(); if(br[1]<0&&br[0]==br[1]) { br[0] = abs(br[0]); br[1] = abs(br[1]); } else if(br[1]<0) { br[1] = -br[1]; br[2] = -br[2]; } long index = abs(br[1]); SudakovPtr sudakov; for(BranchingList::const_iterator cjt = branchings.lower_bound(index); cjt != branchings.upper_bound(index); ++cjt ) { IdList ids = cjt->second.second; if(ids[0]==br[0]&&ids[1]==br[1]&&ids[2]==br[2]) { sudakov=cjt->second.first; break; } } if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in " << "Evolver::connectTrees() for ISR" << Exception::runerror; (**cit).parent()->sudakov(sudakov); } // Sudakovs for FSR else if(!(**cit).children().empty()) { ++_nfs; IdList br(3); br[0] = (**cit) .branchingParticle()->id(); br[1] = (**cit).children()[0]->branchingParticle()->id(); br[2] = (**cit).children()[1]->branchingParticle()->id(); BranchingList branchings = splittingGenerator()->finalStateBranchings(); if(br[0]<0) { br[0] = abs(br[0]); br[1] = abs(br[1]); br[2] = abs(br[2]); } long index = br[0]; SudakovPtr sudakov; for(BranchingList::const_iterator cjt = branchings.lower_bound(index); cjt != branchings.upper_bound(index); ++cjt ) { IdList ids = cjt->second.second; if(ids[0]==br[0]&&ids[1]==br[1]&&ids[2]==br[2]) { sudakov=cjt->second.first; break; } } if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in " << "Evolver::connectTrees()" << Exception::runerror; (**cit).sudakov(sudakov); } } // calculate the evolution scale for(set::iterator cit=hardTree->branchings().begin(); cit!=hardTree->branchings().end();++cit) { particles.push_back((*cit)->branchingParticle()); } showerModel()->partnerFinder()-> setInitialEvolutionScales(particles,!hard,hardTree->interaction(), !hardTree->partnersSet()); hardTree->partnersSet(true); // inverse reconstruction if(hard) { showerModel()->kinematicsReconstructor()-> deconstructHardJets(hardTree,ShowerHandler::currentHandler()->evolver(), hardTree->interaction()); } else showerModel()->kinematicsReconstructor()-> deconstructDecayJets(hardTree,ShowerHandler::currentHandler()->evolver(), hardTree->interaction()); // now reset the momenta of the showering particles vector particlesToShower; for(map::const_iterator cit=showerTree->incomingLines().begin(); cit!=showerTree->incomingLines().end();++cit ) particlesToShower.push_back(cit->first); // extract the showering particles for(map::const_iterator cit=showerTree->outgoingLines().begin(); cit!=showerTree->outgoingLines().end();++cit ) particlesToShower.push_back(cit->first); // match them map partners; for(set::const_iterator bit=hardTree->branchings().begin(); bit!=hardTree->branchings().end();++bit) { Energy2 dmin( 1e30*GeV2 ); ShowerProgenitorPtr partner; for(vector::const_iterator pit=particlesToShower.begin(); pit!=particlesToShower.end();++pit) { if(partners.find(*pit)!=partners.end()) continue; if( (**bit).branchingParticle()->id() != (**pit).progenitor()->id() ) continue; if( (**bit).branchingParticle()->isFinalState() != (**pit).progenitor()->isFinalState() ) continue; if( (**pit).progenitor()->isFinalState() ) { Energy2 dtest = sqr( (**pit).progenitor()->momentum().x() - (**bit).showerMomentum().x() ) + sqr( (**pit).progenitor()->momentum().y() - (**bit).showerMomentum().y() ) + sqr( (**pit).progenitor()->momentum().z() - (**bit).showerMomentum().z() ) + sqr( (**pit).progenitor()->momentum().t() - (**bit).showerMomentum().t() ); // add mass difference for identical particles (e.g. Z0 Z0 production) dtest += 1e10*sqr((**pit).progenitor()->momentum().m()-(**bit).showerMomentum().m()); if( dtest < dmin ) { partner = *pit; dmin = dtest; } } else { // ensure directions are right if((**pit).progenitor()->momentum().z()/(**bit).showerMomentum().z()>ZERO) { partner = *pit; break; } } } if(!partner) throw Exception() << "Failed to match shower and hard trees in Evolver::hardestEmission" << Exception::eventerror; partners[partner] = *bit; } for(vector::const_iterator pit=particlesToShower.begin(); pit!=particlesToShower.end();++pit) { HardBranchingPtr partner = partners[*pit]; if((**pit).progenitor()->dataPtr()->stable()) { (**pit).progenitor()->set5Momentum(partner->showerMomentum()); (**pit).copy()->set5Momentum(partner->showerMomentum()); } else { Lorentz5Momentum oldMomentum = (**pit).progenitor()->momentum(); Lorentz5Momentum newMomentum = partner->showerMomentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); (**pit).progenitor()->transform(boost); (**pit).copy() ->transform(boost); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); (**pit).progenitor()->transform(boost); (**pit).copy() ->transform(boost); } } // correction boosts for daughter trees for(map >::const_iterator tit = showerTree->treelinks().begin(); tit != showerTree->treelinks().end();++tit) { ShowerTreePtr decayTree = tit->first; map::const_iterator cit = decayTree->incomingLines().begin(); // reset the momentum of the decay particle Lorentz5Momentum oldMomentum = cit->first->progenitor()->momentum(); Lorentz5Momentum newMomentum = tit->second.second->momentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); decayTree->transform(boost,true); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); decayTree->transform(boost,true); } } void Evolver::doShowering(bool hard,XCPtr xcomb) { // order of the interactions bool showerOrder(true); // zero number of emissions _nis = _nfs = 0; // if MC@NLO H event and limited emissions // indicate both final and initial state emission if ( isMCatNLOHEvent && _limitEmissions != 0 ) { _nis = _nfs = 1; } // extract particles to shower vector particlesToShower(setupShower(hard)); // setup the maximum scales for the shower if (hardVetoOn()) setupMaximumScales(particlesToShower,xcomb); // set the hard scales for the profiles setupHardScales(particlesToShower,xcomb); // specific stuff for hard processes and decays Energy minmass(ZERO), mIn(ZERO); // hard process generate the intrinsic p_T once and for all if(hard) { generateIntrinsicpT(particlesToShower); } // decay compute the minimum mass of the final-state else { for(unsigned int ix=0;ixprogenitor()->isFinalState()) { if(particlesToShower[ix]->progenitor()->dataPtr()->stable()) minmass += particlesToShower[ix]->progenitor()->dataPtr()->constituentMass(); else minmass += particlesToShower[ix]->progenitor()->mass(); } else { mIn = particlesToShower[ix]->progenitor()->mass(); } } // throw exception if decay can't happen if ( minmass > mIn ) { throw Exception() << "Evolver.cc: Mass of decaying particle is " << "below constituent masses of decay products." << Exception::eventerror; } } // check if interactions in right order if(hardTree() && interaction_!=4 && hardTree()->interaction()!=interactions_[0]) { assert(interactions_.size()==2); showerOrder = false; swap(interactions_[0],interactions_[1]); } // loop over possible interactions for(unsigned int inter=0;inter tmp; unsigned int nColouredIncoming = 0; while(particlesToShower.size()>0){ unsigned int xx=UseRandom::irnd(particlesToShower.size()); tmp.push_back(particlesToShower[xx]); particlesToShower.erase(particlesToShower.begin()+xx); } particlesToShower=tmp; for(unsigned int ix=0;ixprogenitor()->isFinalState() && particlesToShower[ix]->progenitor()->coloured()) ++nColouredIncoming; } bool switchRecon = hard && nColouredIncoming !=1; // main shower loop unsigned int ntry(0); bool reconstructed = false; do { // clear results of last attempt if needed if(ntry!=0) { currentTree()->clear(); setEvolutionPartners(hard,interactions_[inter],true); _nis = _nfs = 0; // if MC@NLO H event and limited emissions // indicate both final and initial state emission if ( isMCatNLOHEvent && _limitEmissions != 0 ) { _nis = _nfs = 1; } for(unsigned int ix=0; ixprogenitor()->spinInfo(); if(spin && spin->decayVertex() && dynamic_ptr_cast(spin->decayVertex())) { spin->decayVertex(VertexPtr()); } } } // loop over particles for(unsigned int ix=0;ixprogenitor()->isFinalState()) { if(!isFSRadiationON()) continue; // perform shower progenitor()->hasEmitted(startTimeLikeShower(interactions_[inter])); } // initial-state radiation else { if(!isISRadiationON()) continue; // hard process if(hard) { // get the PDF setBeamParticle(_progenitor->beam()); assert(beamParticle()); // perform the shower // set the beam particle tPPtr beamparticle=progenitor()->original(); if(!beamparticle->parents().empty()) beamparticle=beamparticle->parents()[0]; // generate the shower progenitor()->hasEmitted(startSpaceLikeShower(beamparticle, interactions_[inter])); } // decay else { // skip colour and electrically neutral particles if(!progenitor()->progenitor()->dataPtr()->coloured() && !progenitor()->progenitor()->dataPtr()->charged()) { progenitor()->hasEmitted(false); continue; } // perform shower // set the scales correctly. The current scale is the maximum scale for // emission not the starting scale ShowerParticle::EvolutionScales maxScales(progenitor()->progenitor()->scales()); progenitor()->progenitor()->scales() = ShowerParticle::EvolutionScales(); if(progenitor()->progenitor()->dataPtr()->charged()) { progenitor()->progenitor()->scales().QED = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QED_noAO = progenitor()->progenitor()->mass(); } if(progenitor()->progenitor()->hasColour()) { progenitor()->progenitor()->scales().QCD_c = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QCD_c_noAO = progenitor()->progenitor()->mass(); } if(progenitor()->progenitor()->hasAntiColour()) { progenitor()->progenitor()->scales().QCD_ac = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QCD_ac_noAO = progenitor()->progenitor()->mass(); } // perform the shower progenitor()->hasEmitted(startSpaceLikeDecayShower(maxScales,minmass, interactions_[inter])); } } } // do the kinematic reconstruction, checking if it worked reconstructed = hard ? showerModel()->kinematicsReconstructor()-> reconstructHardJets (currentTree(),intrinsicpT(),interactions_[inter], switchRecon && ntry>maximumTries()/2) : showerModel()->kinematicsReconstructor()-> reconstructDecayJets(currentTree(),interactions_[inter]); } while(!reconstructed&&maximumTries()>++ntry); // check if failed to generate the shower if(ntry==maximumTries()) { if(hard) throw ShowerHandler::ShowerTriesVeto(ntry); else throw Exception() << "Failed to generate the shower after " << ntry << " attempts in Evolver::showerDecay()" << Exception::eventerror; } } // tree has now showered _currenttree->hasShowered(true); if(!showerOrder) swap(interactions_[0],interactions_[1]); hardTree(HardTreePtr()); } void Evolver:: convertHardTree(bool hard,ShowerInteraction::Type type) { map cmap; // incoming particles for(map::const_iterator cit=currentTree()->incomingLines().begin();cit!=currentTree()->incomingLines().end();++cit) { map::const_iterator mit = hardTree()->particles().find(cit->first->progenitor()); // put the colour lines in the map ShowerParticlePtr oldParticle = cit->first->progenitor(); ShowerParticlePtr newParticle = mit->second->branchingParticle(); ColinePtr cLine = oldParticle-> colourLine(); ColinePtr aLine = oldParticle->antiColourLine(); if(newParticle->colourLine() && cmap.find(newParticle-> colourLine())==cmap.end()) cmap[newParticle-> colourLine()] = cLine; if(newParticle->antiColourLine() && cmap.find(newParticle->antiColourLine())==cmap.end()) cmap[newParticle->antiColourLine()] = aLine; // check whether or not particle emits bool emission = mit->second->parent(); if(emission) { if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); } if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); } newParticle = mit->second->parent()->branchingParticle(); } // get the new colour lines ColinePtr newCLine,newALine; // sort out colour lines if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newCLine = cmap[ctemp]; } else { newCLine = new_ptr(ColourLine()); cmap[ctemp] = newCLine; } } // and anticolour lines if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newALine = cmap[ctemp]; } else { newALine = new_ptr(ColourLine()); cmap[ctemp] = newALine; } } // remove colour lines from old particle if(aLine) { aLine->removeAntiColoured(cit->first->copy()); aLine->removeAntiColoured(cit->first->progenitor()); } if(cLine) { cLine->removeColoured(cit->first->copy()); cLine->removeColoured(cit->first->progenitor()); } // add particle to colour lines if(newCLine) newCLine->addColoured (newParticle); if(newALine) newALine->addAntiColoured(newParticle); // insert new particles cit->first->copy(newParticle); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,false))); cit->first->progenitor(sp); currentTree()->incomingLines()[cit->first]=sp; cit->first->perturbative(!emission); // and the emitted particle if needed if(emission) { ShowerParticlePtr newOut = mit->second->parent()->children()[1]->branchingParticle(); if(newOut->colourLine()) { ColinePtr ctemp = newOut-> colourLine(); ctemp->removeColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addColoured (newOut); } if(newOut->antiColourLine()) { ColinePtr ctemp = newOut->antiColourLine(); ctemp->removeAntiColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addAntiColoured(newOut); } ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout)); out->perturbative(false); currentTree()->outgoingLines().insert(make_pair(out,sout)); } if(hard) { // sort out the value of x if(mit->second->beam()->momentum().z()>ZERO) { sp->x(newParticle->momentum(). plus()/mit->second->beam()->momentum(). plus()); } else { sp->x(newParticle->momentum().minus()/mit->second->beam()->momentum().minus()); } } } // outgoing particles for(map::const_iterator cit=currentTree()->outgoingLines().begin();cit!=currentTree()->outgoingLines().end();++cit) { map >::const_iterator tit; for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==cit->first->progenitor()) break; } map::const_iterator mit = hardTree()->particles().find(cit->first->progenitor()); if(mit==hardTree()->particles().end()) continue; // put the colour lines in the map ShowerParticlePtr oldParticle = cit->first->progenitor(); ShowerParticlePtr newParticle = mit->second->branchingParticle(); ShowerParticlePtr newOut; ColinePtr cLine = oldParticle-> colourLine(); ColinePtr aLine = oldParticle->antiColourLine(); if(newParticle->colourLine() && cmap.find(newParticle-> colourLine())==cmap.end()) cmap[newParticle-> colourLine()] = cLine; if(newParticle->antiColourLine() && cmap.find(newParticle->antiColourLine())==cmap.end()) cmap[newParticle->antiColourLine()] = aLine; // check whether or not particle emits bool emission = !mit->second->children().empty(); if(emission) { if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); } if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); } newParticle = mit->second->children()[0]->branchingParticle(); newOut = mit->second->children()[1]->branchingParticle(); if(newParticle->id()!=oldParticle->id()&&newParticle->id()==newOut->id()) swap(newParticle,newOut); } // get the new colour lines ColinePtr newCLine,newALine; // sort out colour lines if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newCLine = cmap[ctemp]; } else { newCLine = new_ptr(ColourLine()); cmap[ctemp] = newCLine; } } // and anticolour lines if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newALine = cmap[ctemp]; } else { newALine = new_ptr(ColourLine()); cmap[ctemp] = newALine; } } // remove colour lines from old particle if(aLine) { aLine->removeAntiColoured(cit->first->copy()); aLine->removeAntiColoured(cit->first->progenitor()); } if(cLine) { cLine->removeColoured(cit->first->copy()); cLine->removeColoured(cit->first->progenitor()); } // special for unstable particles if(newParticle->id()==oldParticle->id() && (tit!=currentTree()->treelinks().end()||!oldParticle->dataPtr()->stable())) { Lorentz5Momentum oldMomentum = oldParticle->momentum(); Lorentz5Momentum newMomentum = newParticle->momentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false); oldParticle->transform(boost); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); oldParticle->transform(boost); if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false); newParticle=oldParticle; } // add particle to colour lines if(newCLine) newCLine->addColoured (newParticle); if(newALine) newALine->addAntiColoured(newParticle); // insert new particles cit->first->copy(newParticle); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,true))); cit->first->progenitor(sp); currentTree()->outgoingLines()[cit->first]=sp; cit->first->perturbative(!emission); // and the emitted particle if needed if(emission) { if(newOut->colourLine()) { ColinePtr ctemp = newOut-> colourLine(); ctemp->removeColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addColoured (newOut); } if(newOut->antiColourLine()) { ColinePtr ctemp = newOut->antiColourLine(); ctemp->removeAntiColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addAntiColoured(newOut); } ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout)); out->perturbative(false); currentTree()->outgoingLines().insert(make_pair(out,sout)); } // update any decay products if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(cit->first,sp)); } // reset the tree currentTree()->resetShowerProducts(); // reextract the particles and set the colour partners vector particles = currentTree()->extractProgenitorParticles(); // clear the partners for(unsigned int ix=0;ixpartner(ShowerParticlePtr()); particles[ix]->clearPartners(); } // clear the tree hardTree(HardTreePtr()); // Set the initial evolution scales showerModel()->partnerFinder()-> setInitialEvolutionScales(particles,!hard,type,!_hardtree); } Branching Evolver::selectTimeLikeBranching(tShowerParticlePtr particle, ShowerInteraction::Type type, HardBranchingPtr branch) { Branching fb; unsigned int iout=0; tcPDPtr pdata[2]; while (true) { // break if doing truncated shower and no truncated shower needed if(branch && (!isTruncatedShowerON()||hardOnly())) break; fb=_splittingGenerator->chooseForwardBranching(*particle,_finalenhance,type); // no emission break if(!fb.kinematics) break; // special for truncated shower if(branch) { // check haven't evolved too far if(fb.kinematics->scale() < branch->scale()) { fb=Branching(); break; } // get the particle data objects for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(fb.ids[ix+1]); if(particle->id()!=fb.ids[0]) { for(unsigned int ix=0;ix<2;++ix) { tPDPtr cc(pdata[ix]->CC()); if(cc) pdata[ix]=cc; } } // find the truncated line iout=0; if(pdata[0]->id()!=pdata[1]->id()) { if(pdata[0]->id()==particle->id()) iout=1; else if (pdata[1]->id()==particle->id()) iout=2; } else if(pdata[0]->id()==particle->id()) { if(fb.kinematics->z()>0.5) iout=1; else iout=2; } // apply the vetos for the truncated shower // no flavour changing branchings if(iout==0) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z(); // only if same interaction for forced branching - ShowerInteraction::Type type2 = fb.type==ShowerPartnerType::QED ? - ShowerInteraction::QED : ShowerInteraction::QCD; + ShowerInteraction::Type type2 = convertInteraction(fb.type); // and evolution if(type2==branch->sudakov()->interactionType()) { if(zsplit < 0.5 || // hardest line veto fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // pt veto if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // standard vetos for all emissions if(timeLikeVetoed(fb,particle)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); continue; } break; } // normal case if(!branch) { if(fb.kinematics) fb.hard = false; return fb; } // truncated emission if(fb.kinematics) { fb.hard = false; fb.iout = iout; return fb; } // otherwise need to return the hard emission // construct the kinematics for the hard emission ShoKinPtr showerKin= branch->sudakov()->createFinalStateBranching(branch->scale(), branch->children()[0]->z(), branch->phi(), branch->children()[0]->pT()); showerKin->initialize( *particle,PPtr() ); IdList idlist(3); idlist[0] = particle->id(); idlist[1] = branch->children()[0]->branchingParticle()->id(); idlist[2] = branch->children()[1]->branchingParticle()->id(); fb = Branching( showerKin, idlist, branch->sudakov(),branch->type() ); fb.hard = true; fb.iout=0; // return it return fb; } Branching Evolver::selectSpaceLikeDecayBranching(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction::Type type, HardBranchingPtr branch) { Branching fb; unsigned int iout=0; tcPDPtr pdata[2]; while (true) { // break if doing truncated shower and no truncated shower needed if(branch && (!isTruncatedShowerON()||hardOnly())) break; // select branching fb=_splittingGenerator->chooseDecayBranching(*particle,maxScales,minmass, _initialenhance,type); // return if no radiation if(!fb.kinematics) break; // special for truncated shower if(branch) { // check haven't evolved too far if(fb.kinematics->scale() < branch->scale()) { fb=Branching(); break; } // get the particle data objects for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(fb.ids[ix+1]); if(particle->id()!=fb.ids[0]) { for(unsigned int ix=0;ix<2;++ix) { tPDPtr cc(pdata[ix]->CC()); if(cc) pdata[ix]=cc; } } // find the truncated line iout=0; if(pdata[0]->id()!=pdata[1]->id()) { if(pdata[0]->id()==particle->id()) iout=1; else if (pdata[1]->id()==particle->id()) iout=2; } else if(pdata[0]->id()==particle->id()) { if(fb.kinematics->z()>0.5) iout=1; else iout=2; } // apply the vetos for the truncated shower // no flavour changing branchings if(iout==0) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } - ShowerInteraction::Type type2 = fb.type==ShowerPartnerType::QED ? - ShowerInteraction::QED : ShowerInteraction::QCD; + ShowerInteraction::Type type2 = convertInteraction(fb.type); double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z(); if(type2==branch->sudakov()->interactionType()) { if(zsplit < 0.5 || // hardest line veto fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // pt veto if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // if not vetoed break if(spaceLikeDecayVetoed(fb,particle)) { // otherwise reset scale and continue particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } break; } // normal case if(!branch) { if(fb.kinematics) fb.hard = false; return fb; } // truncated emission if(fb.kinematics) { fb.hard = false; fb.iout = iout; return fb; } // otherwise need to return the hard emission // construct the kinematics for the hard emission ShoKinPtr showerKin= branch->sudakov()->createDecayBranching(branch->scale(), branch->children()[0]->z(), branch->phi(), branch->children()[0]->pT()); showerKin->initialize( *particle,PPtr() ); IdList idlist(3); idlist[0] = particle->id(); idlist[1] = branch->children()[0]->branchingParticle()->id(); idlist[2] = branch->children()[1]->branchingParticle()->id(); // create the branching fb = Branching( showerKin, idlist, branch->sudakov(),ShowerPartnerType::QCDColourLine ); fb.hard=true; fb.iout=0; // return it return fb; } diff --git a/Shower/Base/PartnerFinder.cc b/Shower/Base/PartnerFinder.cc --- a/Shower/Base/PartnerFinder.cc +++ b/Shower/Base/PartnerFinder.cc @@ -1,527 +1,528 @@ // -*- C++ -*- // // PartnerFinder.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2011 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the PartnerFinder class. // #include "PartnerFinder.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ShowerParticle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Utilities/Debug.h" #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; DescribeAbstractClass describePartnerFinder ("Herwig::PartnerFinder","HwShower.so"); // some useful functions to avoid using #define namespace { // return bool if final-state particle inline bool FS(const tShowerParticlePtr a) { return a->isFinalState(); } // return colour line pointer inline Ptr::transient_pointer CL(const tShowerParticlePtr a, unsigned int index=0) { return a->colourInfo()->colourLines().empty() ? ThePEG::tColinePtr() : const_ptr_cast(a->colourInfo()->colourLines()[index]); } // return colour line size inline unsigned int CLSIZE(const tShowerParticlePtr a) { return a->colourInfo()->colourLines().size(); } inline Ptr::transient_pointer ACL(const tShowerParticlePtr a, unsigned int index=0) { return a->colourInfo()->antiColourLines().empty() ? ThePEG::tColinePtr() : const_ptr_cast(a->colourInfo()->antiColourLines()[index]); } inline unsigned int ACLSIZE(const tShowerParticlePtr a) { return a->colourInfo()->antiColourLines().size(); } } void PartnerFinder::persistentOutput(PersistentOStream & os) const { os << partnerMethod_ << QEDPartner_ << scaleChoice_; } void PartnerFinder::persistentInput(PersistentIStream & is, int) { is >> partnerMethod_ >> QEDPartner_ >> scaleChoice_; } void PartnerFinder::Init() { static ClassDocumentation documentation ("This class is responsible for finding the partners for each interaction types ", "and within the evolution scale range specified by the ShowerVariables ", "then to determine the initial evolution scales for each pair of partners."); static Switch interfacePartnerMethod ("PartnerMethod", "Choice of partner finding method for gluon evolution.", &PartnerFinder::partnerMethod_, 0, false, false); static SwitchOption interfacePartnerMethodRandom (interfacePartnerMethod, "Random", "Choose partners of a gluon randomly.", 0); static SwitchOption interfacePartnerMethodMaximum (interfacePartnerMethod, "Maximum", "Choose partner of gluon with largest angle.", 1); static Switch interfaceQEDPartner ("QEDPartner", "Control of which particles to use as the partner for QED radiation", &PartnerFinder::QEDPartner_, 0, false, false); static SwitchOption interfaceQEDPartnerAll (interfaceQEDPartner, "All", "Consider all possible choices which give a positive contribution" " in the soft limit.", 0); static SwitchOption interfaceQEDPartnerIIandFF (interfaceQEDPartner, "IIandFF", "Only allow initial-initial or final-final combinations", 1); static SwitchOption interfaceQEDPartnerIF (interfaceQEDPartner, "IF", "Only allow initial-final combinations", 2); static Switch interfaceScaleChoice ("ScaleChoice", "The choice of the evolution scales", &PartnerFinder::scaleChoice_, 0, false, false); static SwitchOption interfaceScaleChoicePartner (interfaceScaleChoice, "Partner", "Scale of all interactions is that of the evolution partner", 0); static SwitchOption interfaceScaleChoiceDifferent (interfaceScaleChoice, "Different", "Allow each interaction to have different scales", 1); } void PartnerFinder::setInitialEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, ShowerInteraction::Type type, const bool setPartners) { // clear the existing partners for(ShowerParticleVector::const_iterator cit = particles.begin(); cit != particles.end(); ++cit) (*cit)->clearPartners(); // set them if(type==ShowerInteraction::QCD) { setInitialQCDEvolutionScales(particles,isDecayCase,setPartners); } else if(type==ShowerInteraction::QED) { setInitialQEDEvolutionScales(particles,isDecayCase,setPartners); } else { setInitialQCDEvolutionScales(particles,isDecayCase,setPartners); setInitialQEDEvolutionScales(particles,isDecayCase,false); } + // \todo EW scales here // print out for debugging if(Debug::level>=10) { for(ShowerParticleVector::const_iterator cit = particles.begin(); cit != particles.end(); ++cit) { generator()->log() << "Particle: " << **cit << "\n"; if(!(**cit).partner()) continue; generator()->log() << "Primary partner: " << *(**cit).partner() << "\n"; for(vector::const_iterator it= (**cit).partners().begin(); it!=(**cit).partners().end();++it) { generator()->log() << it->type << " " << it->weight << " " << it->scale/GeV << " " << *(it->partner) << "\n"; } } generator()->log() << flush; } } void PartnerFinder::setInitialQCDEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, const bool setPartners) { // set the partners and the scales if(setPartners) { // Loop over particles and consider only coloured particles which don't // have already their colour partner fixed and that don't have children // (the latter requirement is relaxed in the case isDecayCase is true). // Build a map which has as key one of these particles (i.e. a pointer // to a ShowerParticle object) and as a corresponding value the vector // of all its possible *normal* candidate colour partners, defined as follows: // --- have colour, and no children (this is not required in the case // isDecayCase is true); // --- if both are initial (incoming) state particles, then the (non-null) colourLine() // of one of them must match the (non-null) antiColourLine() of the other. // --- if one is an initial (incoming) state particle and the other is // a final (outgoing) state particle, then both must have the // same (non-null) colourLine() or the same (non-null) antiColourLine(); // Notice that this definition exclude the special case of baryon-violating // processes (as in R-parity Susy), which will show up as particles // without candidate colour partners, and that we will be treated a part later // (this means that no modifications of the following loop is needed!) ShowerParticleVector::const_iterator cit, cjt; for(cit = particles.begin(); cit != particles.end(); ++cit) { // Skip colourless particles if(!(*cit)->data().coloured()) continue; // find the partners vector< pair > partners = findQCDPartners(*cit,particles); // must have a partner if(partners.empty()) { throw Exception() << "`Failed to make colour connections in " << "PartnerFinder::setQCDInitialEvolutionScales" << (**cit) << Exception::eventerror; } // Calculate the evolution scales for all possible pairs of of particles vector > scales; for(unsigned int ix=0;ix< partners.size();++ix) { scales.push_back(calculateInitialEvolutionScales(ShowerPPair(*cit,partners[ix].second), isDecayCase)); } // In the case of more than one candidate colour partners, // there are now two approaches to choosing the partner. The // first method is based on two assumptions: // 1) the choice of which is the colour partner is done // *randomly* between the available candidates. // 2) the choice of which is the colour partner is done // *independently* from each particle: in other words, // if for a particle "i" its selected colour partner is // the particle "j", then the colour partner of "j" // does not have to be necessarily "i". // The second method always chooses the furthest partner // for hard gluons and gluinos. // store the choice int position(-1); // random choice if( partnerMethod_ == 0 ) { // random choice of partner position = UseRandom::irnd(partners.size()); } // take the one with largest angle else if (partnerMethod_ == 1 ) { if ((*cit)->perturbative() == 1 && (*cit)->dataPtr()->iColour()==PDT::Colour8 ) { assert(partners.size()==2); // Determine largest angle double maxAngle(0.); for(unsigned int ix=0;ixmomentum().vect(). angle(partners[ix].second->momentum().vect()); if(angle>maxAngle) { maxAngle = angle; position = ix; } } } else position = UseRandom::irnd(partners.size()); } else assert(false); // set the evolution partner (*cit)->partner(partners[position].second); for(unsigned int ix=0;ixdata().coloured()) continue; // find the partners vector< pair > partners = findQCDPartners(*cit,particles); // must have a partner if(partners.empty()) { throw Exception() << "`Failed to make colour connections in " << "PartnerFinder::setQCDInitialEvolutionScales" << (**cit) << Exception::eventerror; } // Calculate the evolution scales for all possible pairs of of particles vector > scales; int position(-1); for(unsigned int ix=0;ix< partners.size();++ix) { if(partners[ix].second) position = ix; scales.push_back(calculateInitialEvolutionScales(ShowerPPair(*cit,partners[ix].second), isDecayCase)); } assert(position>=0); for(unsigned int ix=0;ixcharged()) continue; // find the potential partners vector > partners = findQEDPartners(*cit,particles,isDecayCase); if(partners.empty()) { throw Exception() << "Failed to partner in " << "PartnerFinder::setQEDInitialEvolutionScales" << (**cit) << Exception::eventerror; } // calculate the probabilities double prob(0.); for(unsigned int ix=0;ixpartner()) { for(unsigned int ix=0;ixpartner()==partners[ix].second) { position = ix; break; } } } // set the partner if(setPartners||!(*cit)->partner()||position<0) { prob = UseRandom::rnd(); for(unsigned int ix=0;ixprob) { position = ix; break; } prob -= partners[ix].first; } if(position>=0&&(setPartners||!(*cit)->partner())) { (*cit)->partner(partners[position].second); } } // must have a partner if(position<0) throw Exception() << "Failed to partner in " << "PartnerFinder::setQEDInitialEvolutionScales" << (**cit) << Exception::eventerror; // Calculate the evolution scales for all possible pairs of of particles vector > scales; for(unsigned int ix=0;ix< partners.size();++ix) { scales.push_back(calculateInitialEvolutionScales(ShowerPPair(*cit,partners[ix].second), isDecayCase)); } // store all the possible partners for(unsigned int ix=0;ix PartnerFinder:: calculateInitialEvolutionScales(const ShowerPPair &particlePair, const bool isDecayCase) { bool FS1=FS(particlePair.first),FS2= FS(particlePair.second); if(FS1 && FS2) return calculateFinalFinalScales(particlePair); else if(FS1 && !FS2) { ShowerPPair a(particlePair.second, particlePair.first); pair rval = calculateInitialFinalScales(a,isDecayCase); return pair(rval.second,rval.first); } else if(!FS1 &&FS2) return calculateInitialFinalScales(particlePair,isDecayCase); else return calculateInitialInitialScales(particlePair); } vector< pair > PartnerFinder::findQCDPartners(tShowerParticlePtr particle, const ShowerParticleVector &particles) { vector< pair > partners; ShowerParticleVector::const_iterator cjt; for(cjt = particles.begin(); cjt != particles.end(); ++cjt) { if(!(*cjt)->data().coloured() || particle==*cjt) continue; // one initial-state and one final-state particle if(FS(particle) != FS(*cjt)) { // loop over all the colours of both particles for(unsigned int ix=0; ixsourceNeighbours().first) { tColinePair cpair = col->sourceNeighbours(); for(cjt=particles.begin();cjt!=particles.end();++cjt) { if(( FS(*cjt) && ( CL(*cjt) == cpair.first || CL(*cjt) == cpair.second))|| (!FS(*cjt) && (ACL(*cjt) == cpair.first || ACL(*cjt) == cpair.second ))) { partners.push_back(make_pair(ShowerPartnerType:: QCDColourLine,*cjt)); } } } else if(col&&col->sinkNeighbours().first) { tColinePair cpair = col->sinkNeighbours(); for(cjt=particles.begin();cjt!=particles.end();++cjt) { if(( FS(*cjt) && (ACL(*cjt) == cpair.first || ACL(*cjt) == cpair.second))|| (!FS(*cjt) && ( CL(*cjt) == cpair.first || CL(*cjt) == cpair.second))) { partners.push_back(make_pair(ShowerPartnerType:: QCDColourLine,*cjt)); } } } col = ACL(particle); if(FS(particle)&&col&&col->sinkNeighbours().first) { tColinePair cpair = col->sinkNeighbours(); for(cjt=particles.begin();cjt!=particles.end();++cjt) { if(( FS(*cjt) && (ACL(*cjt) == cpair.first || ACL(*cjt) == cpair.second))|| (!FS(*cjt) && ( CL(*cjt) == cpair.first || CL(*cjt) == cpair.second ))) { partners.push_back(make_pair(ShowerPartnerType::QCDAntiColourLine,*cjt)); } } } else if(col&&col->sourceNeighbours().first) { tColinePair cpair = col->sourceNeighbours(); for(cjt=particles.begin();cjt!=particles.end();++cjt) { if(( FS(*cjt) && ( CL(*cjt) == cpair.first || CL(*cjt) == cpair.second))|| (!FS(*cjt) && (ACL(*cjt) == cpair.first ||ACL(*cjt) == cpair.second))) { partners.push_back(make_pair(ShowerPartnerType::QCDAntiColourLine,*cjt)); } } } } // return the partners return partners; } vector< pair > PartnerFinder::findQEDPartners(tShowerParticlePtr particle, const ShowerParticleVector &particles, const bool isDecayCase) { vector< pair > partners; ShowerParticleVector::const_iterator cjt; for(cjt = particles.begin(); cjt != particles.end(); ++cjt) { if(!(*cjt)->data().charged() || particle == *cjt) continue; double charge = double(particle->data().iCharge()*(*cjt)->data().iCharge()); if( FS(particle) != FS(*cjt) ) charge *=-1.; if( QEDPartner_ != 0 && !isDecayCase ) { // only include II and FF as requested if( QEDPartner_ == 1 && FS(particle) != FS(*cjt) ) continue; // only include IF is requested else if(QEDPartner_ == 2 && FS(particle) == FS(*cjt) ) continue; } // only keep positive dipoles if(charge<0.) partners.push_back(make_pair(-charge,*cjt)); } return partners; } diff --git a/Shower/Base/ShowerParticle.cc b/Shower/Base/ShowerParticle.cc --- a/Shower/Base/ShowerParticle.cc +++ b/Shower/Base/ShowerParticle.cc @@ -1,44 +1,45 @@ // -*- C++ -*- // // ShowerParticle.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2011 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the ShowerParticle class. // #include "ShowerParticle.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include using namespace Herwig; PPtr ShowerParticle::clone() const { return new_ptr(*this); } PPtr ShowerParticle::fullclone() const { return new_ptr(*this); } ClassDescription ShowerParticle::initShowerParticle; // Definition of the static class description member. void ShowerParticle::vetoEmission(ShowerPartnerType::Type, Energy scale) { scales_.QED = min(scale,scales_.QED ); scales_.QED_noAO = min(scale,scales_.QED_noAO ); scales_.QCD_c = min(scale,scales_.QCD_c ); scales_.QCD_c_noAO = min(scale,scales_.QCD_c_noAO ); scales_.QCD_ac = min(scale,scales_.QCD_ac ); scales_.QCD_ac_noAO = min(scale,scales_.QCD_ac_noAO); + scales_.EW = min(scale,scales_.EW ); } void ShowerParticle::addPartner(EvolutionPartner in ) { partners_.push_back(in); } diff --git a/Shower/Base/ShowerParticle.h b/Shower/Base/ShowerParticle.h --- a/Shower/Base/ShowerParticle.h +++ b/Shower/Base/ShowerParticle.h @@ -1,457 +1,462 @@ // -*- C++ -*- // // ShowerParticle.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2011 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerParticle_H #define HERWIG_ShowerParticle_H // // This is the declaration of the ShowerParticle class. // #include "ThePEG/EventRecord/Particle.h" #include "Herwig/Shower/SplittingFunctions/SplittingFunction.fh" #include "Herwig/Shower/ShowerConfig.h" #include "ShowerKinematics.h" #include "ShowerParticle.fh" #include namespace Herwig { using namespace ThePEG; /** \ingroup Shower * This class represents a particle in the showering process. * It inherits from the Particle class of ThePEG and has some * specifics information useful only during the showering process. * * Notice that: * - for forward evolution, it is clear what is meant by parent/child; * for backward evolution, however, it depends whether we want * to keep a physical picture or a Monte-Carlo effective one. * In the former case, an incoming particle (emitting particle) * splits into an emitted particle and the emitting particle after * the emission: the latter two are then children of the * emitting particle, the parent. In the Monte-Carlo effective * picture, we have that the particle close to the hard subprocess, * with higher (space-like) virtuality, splits into an emitted particle * and the emitting particle at lower virtuality: the latter two are, * in this case, the children of the first one, the parent. However we * choose a more physical picture where the new emitting particle is the * parented of the emitted final-state particle and the original emitting * particle. * - the pointer to a SplitFun object is set only in the case * that the particle has undergone a shower emission. This is similar to * the case of the decay of a normal Particle where * the pointer to a Decayer object is set only in the case * that the particle has undergone to a decay. * In the case of particle connected directly to the hard subprocess, * there is no pointer to the hard subprocess, but there is a method * isFromHardSubprocess() which returns true only in this case. * * @see Particle * @see ShowerConfig * @see ShowerKinematics */ class ShowerParticle: public Particle { public: /** * Struct for all the info on an evolution partner */ struct EvolutionPartner { /** * Constructor */ EvolutionPartner(tShowerParticlePtr p,double w, ShowerPartnerType::Type t, Energy s) : partner(p), weight(w), type(t), scale(s) {} /** * The partner */ tShowerParticlePtr partner; /** * Weight */ double weight; /** * Type */ ShowerPartnerType::Type type; /** * The assoicated evolution scale */ Energy scale; }; /** * Struct to store the evolution scales */ struct EvolutionScales { /** * Constructor */ EvolutionScales() : QED(),QCD_c(),QCD_ac(), - QED_noAO(),QCD_c_noAO(),QCD_ac_noAO(), + QED_noAO(),QCD_c_noAO(),QCD_ac_noAO(),EW(), Max_Q2(Constants::MaxEnergy2) {} /** * QED scale */ Energy QED; /** * QCD colour scale */ Energy QCD_c; /** * QCD anticolour scale */ Energy QCD_ac; /** * QED scale */ Energy QED_noAO; /** * QCD colour scale */ Energy QCD_c_noAO; /** * QCD anticolour scale */ Energy QCD_ac_noAO; /** + * EW scale + */ + Energy EW; + + /** * Maximum allowed virtuality of the particle */ Energy2 Max_Q2; }; /** @name Construction and descruction functions. */ //@{ /** * Standard Constructor. Note that the default constructor is * private - there is no particle without a pointer to a * ParticleData object. * @param x the ParticleData object * @param fs Whether or not the particle is an inital or final-state particle * @param tls Whether or not the particle initiates a time-like shower */ ShowerParticle(tcEventPDPtr x, bool fs, bool tls=false) : Particle(x), _isFinalState(fs), _perturbative(0), _initiatesTLS(tls), _x(1.0), _showerKinematics(), _vMass(ZERO), _thePEGBase() {} /** * Copy constructor from a ThePEG Particle * @param x ThePEG particle * @param pert Where the particle came from * @param fs Whether or not the particle is an inital or final-state particle * @param tls Whether or not the particle initiates a time-like shower */ ShowerParticle(const Particle & x, unsigned int pert, bool fs, bool tls=false) : Particle(x), _isFinalState(fs), _perturbative(pert), _initiatesTLS(tls), _x(1.0), _showerKinematics(), _vMass(ZERO), _thePEGBase(&x) {} //@} public: /** * Access/Set various flags about the state of the particle */ //@{ /** * Access the flag that tells if the particle is final state * or initial state. */ bool isFinalState() const { return _isFinalState; } /** * Access the flag that tells if the particle is initiating a * time like shower when it has been emitted in an initial state shower. */ bool initiatesTLS() const { return _initiatesTLS; } /** * Access the flag which tells us where the particle came from * This is 0 for a particle produced in the shower, 1 if the particle came * from the hard sub-process and 2 is it came from a decay. */ unsigned int perturbative() const { return _perturbative; } //@} /** * Set/Get the momentum fraction for initial-state particles */ //@{ /** * For an initial state particle get the fraction of the beam momentum */ void x(double x) { _x = x; } /** * For an initial state particle set the fraction of the beam momentum */ double x() const { return _x; } //@} /** * Set/Get methods for the ShowerKinematics objects */ //@{ /** * Access/ the ShowerKinematics object. */ const ShoKinPtr & showerKinematics() const { return _showerKinematics; } /** * Set the ShowerKinematics object. */ void showerKinematics(const ShoKinPtr in) { _showerKinematics = in; } //@} /** * Members relating to the initial evolution scale and partner for the particle */ //@{ /** * Veto emission at a given scale */ void vetoEmission(ShowerPartnerType::Type type, Energy scale); /** * Access to the evolution scales */ const EvolutionScales & scales() const {return scales_;} /** * Access to the evolution scales */ EvolutionScales & scales() {return scales_;} /** * Return the virtual mass\f$ */ Energy virtualMass() const { return _vMass; } /** * Set the virtual mass */ void virtualMass(Energy mass) { _vMass = mass; } /** * Return the partner */ tShowerParticlePtr partner() const { return _partner; } /** * Set the partner */ void partner(const tShowerParticlePtr partner) { _partner = partner; } /** * Get the possible partners */ vector & partners() { return partners_; } /** * Add a possible partners */ void addPartner(EvolutionPartner in ); /** * Clear the evolution partners */ void clearPartners() { partners_.clear(); } /** * Return the progenitor of the shower */ tShowerParticlePtr progenitor() const { return _progenitor; } /** * Set the progenitor of the shower */ void progenitor(const tShowerParticlePtr progenitor) { _progenitor = progenitor; } //@} /** * Members to store and provide access to variables for a specific * shower evolution scheme */ //@{ struct Parameters { Parameters() : alpha(1.), beta(), ptx(), pty(), pt() {} double alpha; double beta; Energy ptx; Energy pty; Energy pt; }; /** * Set the vector containing dimensionless variables */ Parameters & showerParameters() { return _parameters; } //@} /** * If this particle came from the hard process get a pointer to ThePEG particle * it came from */ const tcPPtr thePEGBase() const { return _thePEGBase; } protected: /** * Standard clone function. */ virtual PPtr clone() const; /** * Standard clone function. */ virtual PPtr fullclone() const; private: /** * The static object used to initialize the description of this class. * Indicates that this is a concrete class with persistent data. */ static ClassDescription initShowerParticle; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ ShowerParticle & operator=(const ShowerParticle &); private: /** * Whether the particle is in the final or initial state */ bool _isFinalState; /** * Whether the particle came from */ unsigned int _perturbative; /** * Does a particle produced in the backward shower initiate a time-like shower */ bool _initiatesTLS; /** * Dimensionless parameters */ Parameters _parameters; /** * The beam energy fraction for particle's in the initial state */ double _x; /** * The shower kinematics for the particle */ ShoKinPtr _showerKinematics; /** * Storage of the evolution scales */ EvolutionScales scales_; /** * Virtual mass */ Energy _vMass; /** * Partners */ tShowerParticlePtr _partner; /** * Pointer to ThePEG Particle this ShowerParticle was created from */ const tcPPtr _thePEGBase; /** * Progenitor */ tShowerParticlePtr _progenitor; /** * Partners */ vector partners_; }; inline ostream & operator<<(ostream & os, const ShowerParticle::EvolutionScales & es) { os << "Scales: QED=" << es.QED / GeV << " QCD_c=" << es.QCD_c / GeV << " QCD_ac=" << es.QCD_ac / GeV << " QED_noAO=" << es.QED_noAO / GeV << " QCD_c_noAO=" << es.QCD_c_noAO / GeV << " QCD_ac_noAO=" << es.QCD_ac_noAO / GeV << '\n'; return os; } } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base classes of ShowerParticle. */ template <> struct BaseClassTrait { /** Typedef of the first base class of ShowerParticle. */ typedef Particle NthBase; }; /** This template specialization informs ThePEG about the name of * the ShowerParticle class and the shared object where it is defined. */ template <> struct ClassTraits : public ClassTraitsBase { /** Return a platform-independent class name */ static string className() { return "Herwig::ShowerParticle"; } /** Create a Event object. */ static TPtr create() { return TPtr::Create(Herwig::ShowerParticle(tcEventPDPtr(),true)); } }; /** @endcond */ } #endif /* HERWIG_ShowerParticle_H */ diff --git a/Shower/Base/ShowerProgenitor.h b/Shower/Base/ShowerProgenitor.h --- a/Shower/Base/ShowerProgenitor.h +++ b/Shower/Base/ShowerProgenitor.h @@ -1,263 +1,263 @@ // -*- C++ -*- // // ShowerProgenitor.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2011 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerProgenitor_H #define HERWIG_ShowerProgenitor_H // // This is the declaration of the ShowerProgenitor struct. // #include "ThePEG/Config/ThePEG.h" #include "Herwig/Shower/ShowerConfig.h" #include "Herwig/Shower/Base/ShowerParticle.h" #include "ShowerProgenitor.fh" #include "ThePEG/PDF/BeamParticleData.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * A struct to store information on the perturbative particle which * initiates a shower */ class ShowerProgenitor : public Base { public: /** * Enum for the reconstruction state of this progentitor */ enum Reconstructed { notReconstructed=0, done, dontReconstruct}; /** * Typedef for the BeamParticleData objects */ typedef Ptr::transient_const_pointer tcBeamPtr; public: /** * Constructor for the class * @param original The original particle * @param copy The colour isolated copy * @param particle The ShowerPArticle copy * @param pT The \f$p_t\f$ of the hardest emission * @param emitted Whether or not the particle has radiated */ ShowerProgenitor(PPtr original,PPtr copy, ShowerParticlePtr particle, Energy pT=ZERO,bool emitted=false) : _original(original), _copy(copy), _perturbative(true), _particle(particle), _highestpT(pT), _maxHardPt(ZERO), _hardScale(ZERO), _hasEmitted(emitted), _reconstructed(notReconstructed) { // get the BeamParticleData object if ( original->parents().empty() ) { _beam=dynamic_ptr_cast(original->dataPtr()); } else { _beam=dynamic_ptr_cast(original->parents()[0]->dataPtr()); } } /** * Access to the particle */ ShowerParticlePtr progenitor() const { return _particle; } /** * Set the particle */ void progenitor(ShowerParticlePtr in) { _particle=in; } /** * Access to the original particle */ PPtr original() const { return _original; } /** * Access to the colour isolated copy */ PPtr copy() const { return _copy; } /** * Set the copy */ void copy(PPtr in) { _copy=in; } /** * Whether the particle came from the hard process or was added by * the matrix element correction */ bool perturbative() const { return _perturbative; } /** * Whether the particle came from the hard process or was added by * the matrix element correction */ void perturbative(bool in) { _perturbative=in; } /** * Set/Get methods for the hardest \f$p_T\f$ so far */ //@{ /** * Access the \f$p_T\f$ of the hardest emission so far */ Energy highestpT() const { return _highestpT; } /** * Set the \f$p_T\f$ of the hardest emission so far */ void highestpT(Energy in) { _highestpT=in; } //@} /** * Set/Get methods for the maximum \f$p_T\f$ */ //@{ /** * Access the maximum \f$p_T\f$ for radiation */ Energy maximumpT(ShowerInteraction::Type type) const { - assert(type!=ShowerInteraction::Both); + assert(type!=ShowerInteraction::QEDQCD && type!=ShowerInteraction::ALL && type!=ShowerInteraction::UNDEFINED); map::const_iterator it = _maxpT.find(type); return it !=_maxpT.end() ? it->second : Constants::MaxEnergy; } /** * Set the maximum \f$p_T\f$ for radiation */ void maximumpT(Energy in,ShowerInteraction::Type type) { _maxpT[type]=in; } //@} /** * Set/Get methods for whether the particle has radiated */ //@{ /** * Access the maximum hard \f$p_T\f$, given by the hard process */ Energy maxHardPt() const { return _maxHardPt; } /** * Set the maximum hard \f$p_T\f$, given by the hard process */ void maxHardPt(Energy in) { _maxHardPt = in; } /** * Access the relevant hard scale to be used in profile scales; usually * this is taken to be the maximum pt, except for other choices such as * hfact. */ Energy hardScale() const { return _hardScale; } /** * Set the relevant hard scale to be used in profile scales; usually * this is taken to be the maximum pt, except for other choices such as * hfact. */ void hardScale(Energy in) { _hardScale = in; } /** * Has this particle radiated */ bool hasEmitted() const { return _hasEmitted; } /** * Set whether or not this particle has radiated */ void hasEmitted(bool in) { _hasEmitted=in; } //@} /** * The id of the particle */ long id() const { return _particle->id(); } /** * The BeamParticleData object */ tcBeamPtr beam() { return _beam; } /** * Whether or not the recon has been performed */ Reconstructed reconstructed() const {return _reconstructed;} /** * Whether or not the recon has been performed */ void reconstructed(Reconstructed recon) {_reconstructed = recon;} private: /** * Pointer to the original particle */ PPtr _original; /** * Pointer to the colour isolated copy of the original particle */ PPtr _copy; /** * Whether the particle came from the hard process or was added by * the matrix element correction */ bool _perturbative; /** * Pointer to the ShowerParticle */ ShowerParticlePtr _particle; /** * Highest \f$p_T\f$ emitted in the shower from this particle */ Energy _highestpT; /** * Maximum allowed \f$p_T\f$ for emission from this particle */ map _maxpT; /** * maximum hard \f$p_T\f$ from the hard process */ Energy _maxHardPt; /** * The relevant hard scale to be used in profile scales; usually * this is taken to be the maximum pt, except for other choices such as * hfact. */ Energy _hardScale; /** * Has there been radiation */ bool _hasEmitted; /** * The BeamParticleData object */ tcBeamPtr _beam; /** * Whether or not the reconstruction has been performed */ Reconstructed _reconstructed; }; } #endif /* HERWIG_ShowerProgenitor_H */ diff --git a/Shower/Default/QTildeReconstructor.cc b/Shower/Default/QTildeReconstructor.cc --- a/Shower/Default/QTildeReconstructor.cc +++ b/Shower/Default/QTildeReconstructor.cc @@ -1,2939 +1,2938 @@ // -*- C++ -*- // // QTildeReconstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2011 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the QTildeReconstructor class. // #include "QTildeReconstructor.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/EventRecord/Event.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/RefVector.h" #include "Herwig/Shower/Base/Evolver.h" #include "Herwig/Shower/Base/PartnerFinder.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Shower/SplittingFunctions/SplittingFunction.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/EventRecord/ColourLine.h" #include "ThePEG/Utilities/DescribeClass.h" #include using namespace Herwig; DescribeClass describeQTildeReconstructor("Herwig::QTildeReconstructor", "HwShower.so"); namespace { /** * Struct to order the jets in off-shellness */ struct JetOrdering { bool operator() (const JetKinStruct & j1, const JetKinStruct & j2) { Energy diff1 = j1.q.m()-j1.p.m(); Energy diff2 = j2.q.m()-j2.p.m(); if(diff1!=diff2) { return diff1>diff2; } else if( j1.q.e() != j2.q.e() ) return j1.q.e()>j2.q.e(); else return j1.parent->uniqueId>j2.parent->uniqueId; } }; } void QTildeReconstructor::persistentOutput(PersistentOStream & os) const { os << _reconopt << _initialBoost << ounit(_minQ,GeV) << _noRescale << _noRescaleVector << _finalStateReconOption << _initialStateReconOption; } void QTildeReconstructor::persistentInput(PersistentIStream & is, int) { is >> _reconopt >> _initialBoost >> iunit(_minQ,GeV) >> _noRescale >> _noRescaleVector >> _finalStateReconOption >> _initialStateReconOption; } void QTildeReconstructor::Init() { static ClassDocumentation documentation ( "This class is responsible for the kinematics reconstruction of the showering,", " including the kinematics reshuffling necessary to compensate for the recoil" "of the emissions." ); static Switch interfaceReconstructionOption ("ReconstructionOption", "Option for the kinematics reconstruction", &QTildeReconstructor::_reconopt, 0, false, false); static SwitchOption interfaceReconstructionOptionGeneral (interfaceReconstructionOption, "General", "Use the general solution which ignores the colour structure for all processes", 0); static SwitchOption interfaceReconstructionOptionColour (interfaceReconstructionOption, "Colour", "Use the colour structure of the process to determine the reconstruction procedure.", 1); static SwitchOption interfaceReconstructionOptionColour2 (interfaceReconstructionOption, "Colour2", "Make the most use possible of the colour structure of the process to determine the reconstruction procedure. " "Start with FF, then IF then II colour connections", 2); static SwitchOption interfaceReconstructionOptionColour3 (interfaceReconstructionOption, "Colour3", "Make the most use possible of the colour structure of the process to determine the reconstruction procedure. " "Do the colour connections in order of the pT's emitted in the shower starting with the hardest." " The colour partner is fully reconstructed at the same time.", 3); static SwitchOption interfaceReconstructionOptionColour4 (interfaceReconstructionOption, "Colour4", "Make the most use possible of the colour structure of the process to determine the reconstruction procedure. " "Do the colour connections in order of the pT's emitted in the shower starting with the hardest, while leaving" " the colour partner on mass-shell", 4); static Parameter interfaceMinimumQ2 ("MinimumQ2", "The minimum Q2 for the reconstruction of initial-final systems", &QTildeReconstructor::_minQ, GeV, 0.001*GeV, 1e-6*GeV, 10.0*GeV, false, false, Interface::limited); static RefVector interfaceNoRescale ("NoRescale", "Particles which shouldn't be rescaled to be on shell by the shower", &QTildeReconstructor::_noRescaleVector, -1, false, false, true, false, false); static Switch interfaceInitialInitialBoostOption ("InitialInitialBoostOption", "Option for how the boost from the system before ISR to that after ISR is applied.", &QTildeReconstructor::_initialBoost, 0, false, false); static SwitchOption interfaceInitialInitialBoostOptionOneBoost (interfaceInitialInitialBoostOption, "OneBoost", "Apply one boost from old CMS to new CMS", 0); static SwitchOption interfaceInitialInitialBoostOptionLongTransBoost (interfaceInitialInitialBoostOption, "LongTransBoost", "First apply a longitudinal and then a transverse boost", 1); static Switch interfaceFinalStateReconOption ("FinalStateReconOption", "Option for how to reconstruct the momenta of the final-state system", &QTildeReconstructor::_finalStateReconOption, 0, false, false); static SwitchOption interfaceFinalStateReconOptionDefault (interfaceFinalStateReconOption, "Default", "All the momenta are rescaled in the rest frame", 0); static SwitchOption interfaceFinalStateReconOptionMostOffShell (interfaceFinalStateReconOption, "MostOffShell", "All particles put on the new-mass shell and then the most off-shell and" " recoiling system are rescaled to ensure 4-momentum is conserved.", 1); static SwitchOption interfaceFinalStateReconOptionRecursive (interfaceFinalStateReconOption, "Recursive", "Recursively put on shell by putting the most off-shell particle which" " hasn't been rescaled on-shell by rescaling the particles and the recoiling system. ", 2); static SwitchOption interfaceFinalStateReconOptionRestMostOffShell (interfaceFinalStateReconOption, "RestMostOffShell", "The most off-shell is put on shell by rescaling it and the recoiling system," " the recoiling system is then put on-shell in its rest frame.", 3); static SwitchOption interfaceFinalStateReconOptionRestRecursive (interfaceFinalStateReconOption, "RestRecursive", "As 3 but recursive treated the currently most-off shell," " only makes a difference if more than 3 partons.", 4); static Switch interfaceInitialStateReconOption ("InitialStateReconOption", "Option for the reconstruction of initial state radiation", &QTildeReconstructor::_initialStateReconOption, 0, false, false); static SwitchOption interfaceInitialStateReconOptionRapidity (interfaceInitialStateReconOption, "Rapidity", "Preserve shat and rapidity", 0); static SwitchOption interfaceInitialStateReconOptionLongitudinal (interfaceInitialStateReconOption, "Longitudinal", "Preserve longitudinal momentum", 1); static SwitchOption interfaceInitialStateReconOptionSofterFraction (interfaceInitialStateReconOption, "SofterFraction", "Preserve the momentum fraction of the parton which has emitted softer.", 2); } void QTildeReconstructor::doinit() { KinematicsReconstructor::doinit(); _noRescale = set(_noRescaleVector.begin(),_noRescaleVector.end()); } bool QTildeReconstructor:: reconstructTimeLikeJet(const tShowerParticlePtr particleJetParent) const { assert(particleJetParent); bool emitted=true; // if this is not a fixed point in the reconstruction if( !particleJetParent->children().empty() ) { // if not a reconstruction fixpoint, dig deeper for all children: for ( ParticleVector::const_iterator cit = particleJetParent->children().begin(); cit != particleJetParent->children().end(); ++cit ) reconstructTimeLikeJet(dynamic_ptr_cast(*cit)); } // it is a reconstruction fixpoint, ie kinematical data has to be available else { // check if the parent was part of the shower ShowerParticlePtr jetGrandParent; if(!particleJetParent->parents().empty()) jetGrandParent= dynamic_ptr_cast (particleJetParent->parents()[0]); // update if so if (jetGrandParent) { if (jetGrandParent->showerKinematics()) { if(particleJetParent->id()==_progenitor->id()&& !_progenitor->data().stable()) { jetGrandParent->showerKinematics()->reconstructLast(particleJetParent, _progenitor->mass()); } else { jetGrandParent->showerKinematics()->reconstructLast(particleJetParent); } } } // otherwise else { Energy dm = particleJetParent->data().constituentMass(); if (abs(dm-particleJetParent->momentum().m())>0.001*MeV &&particleJetParent->dataPtr()->stable() &&particleJetParent->id()!=ParticleID::gamma &&_noRescale.find(particleJetParent->dataPtr())==_noRescale.end()) { Lorentz5Momentum dum = particleJetParent->momentum(); dum.setMass(dm); dum.rescaleEnergy(); particleJetParent->set5Momentum(dum); } else { emitted=false; } } } // recursion has reached an endpoint once, ie we can reconstruct the // kinematics from the children. if( !particleJetParent->children().empty() ) particleJetParent->showerKinematics() ->reconstructParent( particleJetParent, particleJetParent->children() ); return emitted; } bool QTildeReconstructor:: reconstructHardJets(ShowerTreePtr hard, const map > & intrinsic, ShowerInteraction::Type type, bool switchRecon) const { _currentTree = hard; _intrinsic=intrinsic; // extract the particles from the ShowerTree vector ShowerHardJets=hard->extractProgenitors(); for(unsigned int ix=0;ixprogenitor()] = vector(); } for(map >::const_iterator tit = _currentTree->treelinks().begin(); tit != _currentTree->treelinks().end();++tit) { _treeBoosts[tit->first] = vector(); } try { // old recon method, using new member functions if(_reconopt == 0 || switchRecon ) { reconstructGeneralSystem(ShowerHardJets); } // reconstruction based on coloured systems else if( _reconopt == 1) { reconstructColourSinglets(ShowerHardJets,type); } // reconstruction of FF, then IF, then II else if( _reconopt == 2) { reconstructFinalFirst(ShowerHardJets); } // reconstruction based on coloured systems else if( _reconopt == 3 || _reconopt == 4) { reconstructColourPartner(ShowerHardJets); } else assert(false); } catch(KinematicsReconstructionVeto) { _progenitor=tShowerParticlePtr(); _intrinsic.clear(); for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { LorentzRotation rot = rit->inverse(); bit->first->transform(rot); } } _boosts.clear(); for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { LorentzRotation rot = rit->inverse(); bit->first->transform(rot,false); } } _currentTree = tShowerTreePtr(); _treeBoosts.clear(); return false; } catch (Exception & ex) { _progenitor=tShowerParticlePtr(); _intrinsic.clear(); _currentTree = tShowerTreePtr(); _boosts.clear(); _treeBoosts.clear(); throw ex; } _progenitor=tShowerParticlePtr(); _intrinsic.clear(); // ensure x<1 for(map::const_iterator cit=hard->incomingLines().begin();cit!=hard->incomingLines().end();++cit) { tPPtr parent = cit->first->progenitor(); while (!parent->parents().empty()) { parent = parent->parents()[0]; } tPPtr hadron; if ( cit->first->original()->parents().empty() ) { hadron = cit->first->original(); } else { hadron = cit->first->original()->parents()[0]; } if( ! (hadron->id() == parent->id() && hadron->children().size() <= 1) && parent->momentum().rho() > hadron->momentum().rho()) { _progenitor=tShowerParticlePtr(); _intrinsic.clear(); for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { LorentzRotation rot = rit->inverse(); bit->first->transform(rot); } } _boosts.clear(); for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { LorentzRotation rot = rit->inverse(); bit->first->transform(rot,false); } } _currentTree = tShowerTreePtr(); _treeBoosts.clear(); return false; } } _boosts.clear(); _treeBoosts.clear(); _currentTree = tShowerTreePtr(); return true; } double QTildeReconstructor::solveKfactor(const Energy & root_s, const JetKinVect & jets) const { Energy2 s = sqr(root_s); // must be at least two jets if ( jets.size() < 2) throw KinematicsReconstructionVeto(); // sum of jet masses must be less than roots if(momConsEq( 0.0, root_s, jets )>ZERO) throw KinematicsReconstructionVeto(); // if two jets simple solution if ( jets.size() == 2 ) { static const Energy2 eps = 1.0e-4 * MeV2; if ( sqr(jets[0].p.x()+jets[1].p.x()) < eps && sqr(jets[0].p.y()+jets[1].p.y()) < eps && sqr(jets[0].p.z()+jets[1].p.z()) < eps ) { Energy test = (jets[0].p+jets[1].p).vect().mag(); if(test > 1.0e-4 * MeV) throw KinematicsReconstructionVeto(); if ( jets[0].p.vect().mag2() < eps ) throw KinematicsReconstructionVeto(); Energy2 m1sq(jets[0].q.m2()),m2sq(jets[1].q.m2()); return sqrt( ( sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq ) /(4.*s*jets[0].p.vect().mag2()) ); } else throw KinematicsReconstructionVeto(); } // i.e. jets.size() > 2, numerically // check convergence, if it's a problem maybe use Newton iteration? else { double k1 = 0.,k2 = 1.,k = 0.; if ( momConsEq( k1, root_s, jets ) < ZERO ) { while ( momConsEq( k2, root_s, jets ) < ZERO ) { k1 = k2; k2 *= 2; } while ( fabs( (k1 - k2)/(k1 + k2) ) > 1.e-10 ) { if( momConsEq( k2, root_s, jets ) == ZERO ) { return k2; } else { k = (k1+k2)/2.; if ( momConsEq( k, root_s, jets ) > ZERO ) { k2 = k; } else { k1 = k; } } } return k1; } else throw KinematicsReconstructionVeto(); } throw KinematicsReconstructionVeto(); } bool QTildeReconstructor:: reconstructSpaceLikeJet( const tShowerParticlePtr p) const { bool emitted = true; tShowerParticlePtr child; tShowerParticlePtr parent; if(!p->parents().empty()) parent = dynamic_ptr_cast(p->parents()[0]); if(parent) { emitted=true; reconstructSpaceLikeJet(parent); } // if branching reconstruct time-like child if(p->children().size()==2) child = dynamic_ptr_cast(p->children()[1]); if(p->perturbative()==0 && child) { dynamic_ptr_cast(p->children()[0])-> showerKinematics()->reconstructParent(p,p->children()); if(!child->children().empty()) { _progenitor=child; reconstructTimeLikeJet(child); // calculate the momentum of the particle Lorentz5Momentum pnew=p->momentum()-child->momentum(); pnew.rescaleMass(); p->children()[0]->set5Momentum(pnew); } } return emitted; } Boost QTildeReconstructor:: solveBoostBeta( const double k, const Lorentz5Momentum & newq, const Lorentz5Momentum & oldp ) { // try something different, purely numerical first: // a) boost to rest frame of newq, b) boost with kp/E Energy q = newq.vect().mag(); Energy2 qs = sqr(q); Energy2 Q2 = newq.m2(); Energy kp = k*(oldp.vect().mag()); Energy2 kps = sqr(kp); // usually we take the minus sign, since this boost will be smaller. // we only require |k \vec p| = |\vec q'| which leaves the sign of // the boost open but the 'minus' solution gives a smaller boost // parameter, i.e. the result should be closest to the previous // result. this is to be changed if we would get many momentum // conservation violations at the end of the shower from a hard // process. double betam = (q*sqrt(qs + Q2) - kp*sqrt(kps + Q2))/(kps + qs + Q2); // move directly to 'return' Boost beta = -betam*(k/kp)*oldp.vect(); // note that (k/kp)*oldp.vect() = oldp.vect()/oldp.vect().mag() but cheaper. // leave this out if it's running properly! if ( betam >= 0 ) return beta; else return Boost(0., 0., 0.); } bool QTildeReconstructor:: reconstructDecayJets(ShowerTreePtr decay, ShowerInteraction::Type) const { _currentTree = decay; // extract the particles from the ShowerTree vector ShowerHardJets=decay->extractProgenitors(); for(unsigned int ix=0;ixprogenitor()] = vector(); } for(map >::const_iterator tit = _currentTree->treelinks().begin(); tit != _currentTree->treelinks().end();++tit) { _treeBoosts[tit->first] = vector(); } try { bool radiated[2]={false,false}; // find the decaying particle and check if particles radiated ShowerProgenitorPtr initial; for(unsigned int ix=0;ixprogenitor()->isFinalState()) { radiated[1] |=ShowerHardJets[ix]->hasEmitted(); } else { initial=ShowerHardJets[ix]; radiated[0]|=ShowerHardJets[ix]->hasEmitted(); } } // find boost to the rest frame if needed Boost boosttorest=-initial->progenitor()->momentum().boostVector(); double gammarest = initial->progenitor()->momentum().e()/ initial->progenitor()->momentum().mass(); // check if need to boost to rest frame bool gottaBoost = (boosttorest.mag() > 1e-12); // if initial state radiation reconstruct the jet and set up the basis vectors Lorentz5Momentum pjet; Lorentz5Momentum nvect; // find the partner ShowerParticlePtr partner = initial->progenitor()->partner(); Lorentz5Momentum ppartner[2]; if(partner) ppartner[0]=partner->momentum(); // get the n reference vector if(partner) { if(initial->progenitor()->showerKinematics()) { nvect = initial->progenitor()->showerKinematics()->getBasis()[1]; } else { Lorentz5Momentum ppartner=initial->progenitor()->partner()->momentum(); if(gottaBoost) ppartner.boost(boosttorest,gammarest); nvect = Lorentz5Momentum( ZERO,0.5*initial->progenitor()->mass()* ppartner.vect().unit()); nvect.boost(-boosttorest,gammarest); } } // if ISR if(radiated[0]) { // reconstruct the decay jet reconstructDecayJet(initial->progenitor()); // momentum of decaying particle after ISR pjet=initial->progenitor()->momentum() -decay->incomingLines().begin()->second->momentum(); pjet.rescaleMass(); } // boost initial state jet and basis vector if needed if(gottaBoost) { pjet.boost(boosttorest,gammarest); nvect.boost(boosttorest,gammarest); ppartner[0].boost(boosttorest,gammarest); } // loop over the final-state particles and do the reconstruction JetKinVect possiblepartners; JetKinVect jetKinematics; bool atLeastOnce = radiated[0]; LorentzRotation restboost(boosttorest,gammarest); Energy inmass(ZERO); for(unsigned int ix=0;ixprogenitor()->isFinalState()) { inmass=ShowerHardJets[ix]->progenitor()->mass(); continue; } // do the reconstruction JetKinStruct tempJetKin; tempJetKin.parent = ShowerHardJets[ix]->progenitor(); if(ShowerHardJets.size()==2) { Lorentz5Momentum dum=ShowerHardJets[ix]->progenitor()->momentum(); dum.setMass(inmass); dum.rescaleRho(); tempJetKin.parent->set5Momentum(dum); } tempJetKin.p = ShowerHardJets[ix]->progenitor()->momentum(); if(gottaBoost) tempJetKin.p.boost(boosttorest,gammarest); _progenitor=tempJetKin.parent; if(ShowerHardJets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { atLeastOnce |= reconstructTimeLikeJet(tempJetKin.parent); ShowerHardJets[ix]->reconstructed(ShowerProgenitor::done); } if(gottaBoost) deepTransform(tempJetKin.parent,restboost); tempJetKin.q = ShowerHardJets[ix]->progenitor()->momentum(); jetKinematics.push_back(tempJetKin); } if(partner) ppartner[1]=partner->momentum(); // calculate the rescaling parameters double k1,k2; Lorentz5Momentum qt; if(!solveDecayKFactor(initial->progenitor()->mass(),nvect,pjet, jetKinematics,partner,ppartner,k1,k2,qt)) { for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { LorentzRotation rot = rit->inverse(); bit->first->transform(rot); } } _boosts.clear(); for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { LorentzRotation rot = rit->inverse(); bit->first->transform(rot,false); } } _treeBoosts.clear(); _currentTree = tShowerTreePtr(); return false; } // apply boosts and rescalings to final-state jets for(JetKinVect::iterator it = jetKinematics.begin(); it != jetKinematics.end(); ++it) { LorentzRotation Trafo = LorentzRotation(); if(it->parent!=partner) { // boost for rescaling if(atLeastOnce) { map >::const_iterator tit; for(tit = _currentTree->treelinks().begin(); tit != _currentTree->treelinks().end();++tit) { if(tit->second.first && tit->second.second==it->parent) break; } if(it->parent->children().empty()&&!it->parent->spinInfo() && tit==_currentTree->treelinks().end()) { Lorentz5Momentum pnew(k2*it->p.vect(), sqrt(sqr(k2*it->p.vect().mag())+it->q.mass2()), it->q.mass()); it->parent->set5Momentum(pnew); } else { // rescaling boost can't ever work in this case if(k2<0. && it->q.mass()==ZERO) throw KinematicsReconstructionVeto(); Trafo = solveBoost(k2, it->q, it->p); } } if(gottaBoost) Trafo.boost(-boosttorest,gammarest); if(atLeastOnce || gottaBoost) deepTransform(it->parent,Trafo); } else { Lorentz5Momentum pnew=ppartner[0]; pnew *=k1; pnew-=qt; pnew.setMass(ppartner[1].mass()); pnew.rescaleEnergy(); LorentzRotation Trafo=solveBoost(1.,ppartner[1],pnew); if(gottaBoost) Trafo.boost(-boosttorest,gammarest); deepTransform(partner,Trafo); } } } catch(KinematicsReconstructionVeto) { for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { LorentzRotation rot = rit->inverse(); bit->first->transform(rot); } } _boosts.clear(); for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { LorentzRotation rot = rit->inverse(); bit->first->transform(rot,false); } } _treeBoosts.clear(); _currentTree = tShowerTreePtr(); return false; } catch (Exception & ex) { _currentTree = tShowerTreePtr(); _boosts.clear(); _treeBoosts.clear(); throw ex; } _boosts.clear(); _treeBoosts.clear(); _currentTree = tShowerTreePtr(); return true; } bool QTildeReconstructor:: reconstructDecayJet( const tShowerParticlePtr p) const { if(p->children().empty()) return false; tShowerParticlePtr child; // if branching reconstruct time-like child child = dynamic_ptr_cast(p->children()[1]); if(child) { _progenitor=child; reconstructTimeLikeJet(child); // calculate the momentum of the particle Lorentz5Momentum pnew=p->momentum()-child->momentum(); pnew.rescaleMass(); p->children()[0]->set5Momentum(pnew); child=dynamic_ptr_cast(p->children()[0]); reconstructDecayJet(child); return true; } return false; } bool QTildeReconstructor:: solveDecayKFactor(Energy mb, const Lorentz5Momentum & n, const Lorentz5Momentum & pjet, const JetKinVect & jetKinematics, ShowerParticlePtr partner, Lorentz5Momentum ppartner[2], double & k1, double & k2, Lorentz5Momentum & qt) const { Energy2 pjn = partner ? pjet.vect()*n.vect() : ZERO; Energy2 pcn = partner ? ppartner[0].vect()*n.vect() : 1.*MeV2; Energy2 nmag = n.vect().mag2(); Lorentz5Momentum pn = partner ? (pjn/nmag)*n : Lorentz5Momentum(); qt=pjet-pn; qt.setE(ZERO); Energy2 pt2=qt.vect().mag2(); Energy Ejet = pjet.e(); // magnitudes of the momenta for fast access vector pmag; Energy total(Ejet); for(unsigned int ix=0;ixmb) return false; Energy2 pcmag=ppartner[0].vect().mag2(); // used newton-raphson to get the rescaling static const Energy eps=1e-8*GeV; long double d1(1.),d2(1.); Energy roots, ea, ec, ds; unsigned int ix=0; do { ++ix; d2 = d1 + pjn/pcn; roots = Ejet; ds = ZERO; for(unsigned int iy=0;iyeps && ix<100); k1=d1; k2=d2; // return true if N-R succeed, otherwise false return ix<100; } bool QTildeReconstructor:: deconstructDecayJets(HardTreePtr decay, cEvolverPtr, ShowerInteraction::Type) const { // extract the momenta of the particles vector pin; vector pout; // on-shell masses of the decay products vector mon; Energy mbar(-GeV); // the hard branchings of the particles set::iterator cit; set branchings=decay->branchings(); // properties of the incoming particle bool ISR = false; HardBranchingPtr initial; Lorentz5Momentum qisr; // find the incoming particle, both before and after // any ISR for(cit=branchings.begin();cit!=branchings.end();++cit){ if((*cit)->status()==HardBranching::Incoming|| (*cit)->status()==HardBranching::Decay) { // search back up isr if needed HardBranchingPtr branch = *cit; while(branch->parent()) branch=branch->parent(); initial=branch; // momentum or original parent pin.push_back(branch->branchingParticle()->momentum()); // ISR? ISR = !branch->branchingParticle()->children().empty(); // ISR momentum qisr = pin.back()-(**cit).branchingParticle()->momentum(); qisr.rescaleMass(); } } assert(pin.size()==1); // compute boost to rest frame Boost boostv=-pin[0].boostVector(); // partner for ISR ShowerParticlePtr partner; Lorentz5Momentum ppartner; if(initial->branchingParticle()->partner()) { partner=initial->branchingParticle()->partner(); ppartner=partner->momentum(); } // momentum of the decay products for(cit=branchings.begin();cit!=branchings.end();++cit) { if((*cit)->status()!=HardBranching::Outgoing) continue; // find the mass of the particle // including special treatment for off-shell resonances // to preserve off-shell mass Energy mass; if(!(**cit).branchingParticle()->dataPtr()->stable()) { HardBranchingPtr branch=*cit; while(!branch->children().empty()) { for(unsigned int ix=0;ixchildren().size();++ix) { if(branch->children()[ix]->branchingParticle()->id()== (**cit).branchingParticle()->id()) { branch = branch->children()[ix]; continue; } } }; mass = branch->branchingParticle()->mass(); } else { mass = (**cit).branchingParticle()->dataPtr()->mass(); } // if not evolution partner of decaying particle if((*cit)->branchingParticle()!=partner) { pout.push_back((*cit)->branchingParticle()->momentum()); mon.push_back(mass); } // evolution partner of decaying particle else { mbar = mass; } } // boost all the momenta to the rest frame of the decaying particle for(unsigned int ix=0;ixbranchingParticle()->partner()) { ppartner.boost(boostv); qisr.boost(boostv); } // compute the rescaling factors double k1,k2; if(!ISR) { if(partner) { pout.push_back(ppartner); mon.push_back(mbar); } k1=k2=inverseRescalingFactor(pout,mon,pin[0].mass()); if(partner) { pout.pop_back(); mon.pop_back(); } } else { if(!inverseDecayRescalingFactor(pout,mon,pin[0].mass(), ppartner,mbar,k1,k2)) return false; } // now calculate the p reference vectors unsigned int ifinal=0; for(cit=branchings.begin();cit!=branchings.end();++cit) { if((**cit).status()!=HardBranching::Outgoing) continue; // for partners other than colour partner of decaying particle if((*cit)->branchingParticle()!=partner) { Lorentz5Momentum pvect = (*cit)->branchingParticle()->momentum(); pvect.boost(boostv); pvect /= k1; pvect.setMass(mon[ifinal]); ++ifinal; pvect.rescaleEnergy(); pvect.boost(-boostv); (*cit)->pVector(pvect); (*cit)->showerMomentum(pvect); } // for colour partner of decaying particle else { Lorentz5Momentum pvect = (*cit)->branchingParticle()->momentum(); pvect.boost(boostv); Lorentz5Momentum qtotal; for(unsigned int ix=0;ixpVector(pvect); (*cit)->showerMomentum(pvect); } } // // find the evolution partners // ShowerParticleVector particles; // particles.push_back((**decay->incoming().begin()).branchingParticle()); // for(cit=branchings.begin();cit!=branchings.end();++cit) { // if((**cit).status()==HardBranching::Outgoing) // particles.push_back((*cit)->branchingParticle()); // } // // partners should // evolver->showerModel()->partnerFinder() // ->setInitialEvolutionScales(particles,true,type,false); // For initial-state if needed if(initial) { tShowerParticlePtr newPartner=initial->branchingParticle()->partner(); if(newPartner) { tHardBranchingPtr branch; for( set::iterator clt = branchings.begin(); clt != branchings.end(); ++clt ) { if((**clt).branchingParticle()==newPartner) { initial->colourPartner(*clt); branch=*clt; break; } } Lorentz5Momentum pvect = initial->branchingParticle()->momentum(); initial->pVector(pvect); Lorentz5Momentum ptemp = branch->pVector(); ptemp.boost(boostv); Lorentz5Momentum nvect = Lorentz5Momentum( ZERO, 0.5*initial->branchingParticle()->mass()* ptemp.vect().unit()); nvect.boost(-boostv); initial->nVector(nvect); } } // calculate the reference vectors, then for outgoing particles for(cit=branchings.begin();cit!=branchings.end();++cit){ if((**cit).status()!=HardBranching::Outgoing) continue; // find the partner branchings tShowerParticlePtr newPartner=(*cit)->branchingParticle()->partner(); if(!newPartner) continue; tHardBranchingPtr branch; for( set::iterator clt = branchings.begin(); clt != branchings.end(); ++clt ) { if(cit==clt) continue; if((**clt).branchingParticle()==newPartner) { (**cit).colourPartner(*clt); branch=*clt; break; } } if((**decay->incoming().begin()).branchingParticle()==newPartner) { (**cit).colourPartner(*decay->incoming().begin()); branch = *decay->incoming().begin(); } // final-state colour partner if(branch->status()==HardBranching::Outgoing) { Boost boost=((*cit)->pVector()+branch->pVector()).findBoostToCM(); Lorentz5Momentum pcm = branch->pVector(); pcm.boost(boost); Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect()); nvect.boost( -boost); (*cit)->nVector(nvect); } // initial-state colour partner else { Boost boost=branch->pVector().findBoostToCM(); Lorentz5Momentum pcm = (*cit)->pVector(); pcm.boost(boost); Lorentz5Momentum nvect = Lorentz5Momentum( ZERO, -pcm.vect()); nvect.boost( -boost); (*cit)->nVector(nvect); } } // now compute the new momenta // and calculate the shower variables for(cit=branchings.begin();cit!=branchings.end();++cit) { if((**cit).status()!=HardBranching::Outgoing) continue; LorentzRotation B=LorentzRotation(-boostv); LorentzRotation A=LorentzRotation(boostv),R; if((*cit)->branchingParticle()==partner) { Lorentz5Momentum qnew; Energy2 dot=(*cit)->pVector()*(*cit)->nVector(); double beta = 0.5*((*cit)->branchingParticle()->momentum().m2() -sqr((*cit)->pVector().mass()))/dot; qnew=(*cit)->pVector()+beta*(*cit)->nVector(); qnew.rescaleMass(); // compute the boost R=B*solveBoost(A*qnew,A*(*cit)->branchingParticle()->momentum())*A; } else { Lorentz5Momentum qnew; if((*cit)->branchingParticle()->partner()) { Energy2 dot=(*cit)->pVector()*(*cit)->nVector(); double beta = 0.5*((*cit)->branchingParticle()->momentum().m2() -sqr((*cit)->pVector().mass()))/dot; qnew=(*cit)->pVector()+beta*(*cit)->nVector(); qnew.rescaleMass(); } else { qnew = (*cit)->pVector(); } // compute the boost R=B*solveBoost(A*qnew,A*(*cit)->branchingParticle()->momentum())*A; } // reconstruct the momenta (*cit)->setMomenta(R,1.0,Lorentz5Momentum()); } if(initial) { initial->setMomenta(LorentzRotation(),1.0,Lorentz5Momentum()); } return true; } double QTildeReconstructor:: inverseRescalingFactor(vector pout, vector mon, Energy roots) const { double lambda=1.; if(pout.size()==2) { double mu_q1(pout[0].m()/roots), mu_q2(pout[1].m()/roots); double mu_p1(mon[0]/roots) , mu_p2(mon[1]/roots); lambda = ((1.+mu_q1+mu_q2)*(1.-mu_q1-mu_q2)*(mu_q1-1.-mu_q2)*(mu_q2-1.-mu_q1))/ ((1.+mu_p1+mu_p2)*(1.-mu_p1-mu_p2)*(mu_p1-1.-mu_p2)*(mu_p2-1.-mu_p1)); if(lambda<0.) throw Exception() << "Rescaling factor is imaginary in QTildeReconstructor::" << "inverseRescalingFactor lambda^2= " << lambda << Exception::eventerror; lambda = sqrt(lambda); } else { unsigned int ntry=0; // compute magnitudes once for speed vector pmag; for(unsigned int ix=0;ix root(pout.size()); do { // compute new energies Energy sum(ZERO); for(unsigned int ix=0;ix::const_iterator it=tree->branchings().begin(); it!=tree->branchings().end();++it) { if((**it).status()==HardBranching::Incoming) in .jets.push_back(*it); else out.jets.push_back(*it); } LorentzRotation toRest,fromRest; bool applyBoost(false); // do the initial-state reconstruction deconstructInitialInitialSystem(applyBoost,toRest,fromRest, tree,in.jets,type); // do the final-state reconstruction deconstructFinalStateSystem(toRest,fromRest,tree, out.jets,evolver,type); // only at this point that we can be sure all the reference vectors // are correct for(set::const_iterator it=tree->branchings().begin(); it!=tree->branchings().end();++it) { if((**it).status()==HardBranching::Incoming) continue; if((**it).branchingParticle()->coloured()) (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); } for(set::const_iterator it=tree->incoming().begin(); it!=tree->incoming().end();++it) { (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); } return true; } bool QTildeReconstructor::deconstructHardJets(HardTreePtr tree, cEvolverPtr evolver, ShowerInteraction::Type type) const { // inverse of old recon method if(_reconopt == 0) { return deconstructGeneralSystem(tree,evolver,type); } else if(_reconopt == 1) { return deconstructColourSinglets(tree,evolver,type); } else if(_reconopt == 2) { throw Exception() << "Inverse reconstruction is not currently supported for ReconstructionOption Colour2 " << "in QTildeReconstructor::deconstructHardJets(). Please use one of the other options\n" << Exception::runerror; } else if(_reconopt == 3 || _reconopt == 4 ) { return deconstructColourPartner(tree,evolver,type); } else assert(false); } bool QTildeReconstructor:: deconstructColourSinglets(HardTreePtr tree,cEvolverPtr evolver, ShowerInteraction::Type type) const { // identify the colour singlet systems unsigned int nnun(0),nnii(0),nnif(0),nnf(0),nni(0); vector systems(identifySystems(tree->branchings(),nnun,nnii,nnif,nnf,nni)); // now decide what to do LorentzRotation toRest,fromRest; bool applyBoost(false); bool general(false); // initial-initial connection and final-state colour singlet systems // Drell-Yan type if(nnun==0&&nnii==1&&nnif==0&&nnf>0&&nni==0) { // reconstruct initial-initial system for(unsigned int ix=0;ix0&&nni==1)|| (nnif==2&& nni==0))) { for(unsigned int ix=0;ix0&&nni==2) { // only FS needed // but need to boost to rest frame if QED ISR Lorentz5Momentum ptotal; for(unsigned int ix=0;ixbranchingParticle()->momentum(); } toRest = LorentzRotation(ptotal.findBoostToCM()); fromRest = toRest; fromRest.invert(); - if(type==ShowerInteraction::QED||type==ShowerInteraction::Both) { + if(type!=ShowerInteraction::QCD) { combineFinalState(systems); general=false; } } // general type else { general = true; } // final-state systems except for general recon if(!general) { for(unsigned int ix=0;ix::const_iterator it=tree->branchings().begin(); it!=tree->branchings().end();++it) { if((**it).status()==HardBranching::Incoming) continue; if((**it).branchingParticle()->coloured()) (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); } for(set::const_iterator it=tree->incoming().begin(); it!=tree->incoming().end();++it) { (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); } return true; } else { return deconstructGeneralSystem(tree,evolver,type); } return true; } bool QTildeReconstructor:: deconstructColourPartner(HardTreePtr tree,cEvolverPtr evolver, ShowerInteraction::Type type) const { Lorentz5Momentum ptotal; HardBranchingPtr emitter; ColourSingletShower incomingShower,outgoingShower; for(set::const_iterator it=tree->branchings().begin(); it!=tree->branchings().end();++it) { if((**it).status()==HardBranching::Incoming) { incomingShower.jets.push_back(*it); ptotal += (*it)->branchingParticle()->momentum(); // check for emitting particle if((**it).parent() ) { if(!emitter) emitter = *it; else throw Exception() << "Only one emitting particle allowed in " << "QTildeReconstructor::deconstructColourPartner()" << Exception::runerror; } } else if ((**it).status()==HardBranching::Outgoing) { outgoingShower.jets.push_back(*it); // check for emitting particle if(!(**it).children().empty() ) { if(!emitter) emitter = *it; else throw Exception() << "Only one emitting particle allowed in " << "QTildeReconstructor::deconstructColourPartner()" << Exception::runerror; } } } assert(emitter); assert(emitter->colourPartner()); ColourSingletShower system; system.jets.push_back(emitter); system.jets.push_back(emitter->colourPartner()); LorentzRotation toRest,fromRest; bool applyBoost(false); // identify the colour singlet system if(emitter->status() == HardBranching::Outgoing && emitter->colourPartner()->status() == HardBranching::Outgoing ) { system.type=F; // need to boost to rest frame if QED ISR if( !incomingShower.jets[0]->branchingParticle()->coloured() && !incomingShower.jets[1]->branchingParticle()->coloured() ) { Boost boost = ptotal.findBoostToCM(); toRest = LorentzRotation( boost); fromRest = LorentzRotation(-boost); } else findInitialBoost(ptotal,ptotal,toRest,fromRest); deconstructFinalStateSystem(toRest,fromRest,tree, system.jets,evolver,type); } else if (emitter->status() == HardBranching::Incoming && emitter->colourPartner()->status() == HardBranching::Incoming) { system.type=II; deconstructInitialInitialSystem(applyBoost,toRest,fromRest,tree,system.jets,type); // make sure the recoil gets applied deconstructFinalStateSystem(toRest,fromRest,tree, outgoingShower.jets,evolver,type); } else if ((emitter->status() == HardBranching::Outgoing && emitter->colourPartner()->status() == HardBranching::Incoming ) || (emitter->status() == HardBranching::Incoming && emitter->colourPartner()->status() == HardBranching::Outgoing)) { system.type=IF; // enusre incoming first if(system.jets[0]->status() == HardBranching::Outgoing) swap(system.jets[0],system.jets[1]); deconstructInitialFinalSystem(tree,system.jets,evolver,type); } else { throw Exception() << "Unknown type of system in " << "QTildeReconstructor::deconstructColourPartner()" << Exception::runerror; } // only at this point that we can be sure all the reference vectors // are correct for(set::const_iterator it=tree->branchings().begin(); it!=tree->branchings().end();++it) { if((**it).status()==HardBranching::Incoming) continue; if((**it).branchingParticle()->coloured()) (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); } for(set::const_iterator it=tree->incoming().begin(); it!=tree->incoming().end();++it) { (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); } for(set::const_iterator it=tree->branchings().begin(); it!=tree->branchings().end();++it) { if((**it).status()!=HardBranching::Incoming) continue; if(*it==system.jets[0] || *it==system.jets[1]) continue; if((**it).branchingParticle()->momentum().z()>ZERO) { (**it).z((**it).branchingParticle()->momentum().plus()/(**it).beam()->momentum().plus()); } else { (**it).z((**it).branchingParticle()->momentum().minus()/(**it).beam()->momentum().minus()); } } return true; } void QTildeReconstructor:: reconstructInitialFinalSystem(vector jets) const { Lorentz5Momentum pin[2],pout[2],pbeam; for(unsigned int ix=0;ixprogenitor()->isFinalState()) { pout[0] +=jets[ix]->progenitor()->momentum(); _progenitor = jets[ix]->progenitor(); if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { reconstructTimeLikeJet(jets[ix]->progenitor()); jets[ix]->reconstructed(ShowerProgenitor::done); } } // initial-state parton else { pin[0] +=jets[ix]->progenitor()->momentum(); if(jets[ix]->progenitor()->showerKinematics()) { pbeam = jets[ix]->progenitor()->showerKinematics()->getBasis()[0]; } else { if ( jets[ix]->original()->parents().empty() ) { pbeam = jets[ix]->progenitor()->momentum(); } else { pbeam = jets[ix]->original()->parents()[0]->momentum(); } } if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { reconstructSpaceLikeJet(jets[ix]->progenitor()); jets[ix]->reconstructed(ShowerProgenitor::done); } assert(!jets[ix]->original()->parents().empty()); } } // add intrinsic pt if needed addIntrinsicPt(jets); // momenta after showering for(unsigned int ix=0;ixprogenitor()->isFinalState()) pout[1] += jets[ix]->progenitor()->momentum(); else pin[1] += jets[ix]->progenitor()->momentum(); } // work out the boost to the Breit frame Lorentz5Momentum pa = pout[0]-pin[0]; Axis axis(pa.vect().unit()); LorentzRotation rot; double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); if ( sinth > 1.e-9 ) rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot.rotateX(Constants::pi); rot.boostZ( pa.e()/pa.vect().mag()); Lorentz5Momentum ptemp=rot*pbeam; Boost trans = -1./ptemp.e()*ptemp.vect(); trans.setZ(0.); if ( trans.mag2() - 1. >= 0. ) throw KinematicsReconstructionVeto(); rot.boost(trans); pa *=rot; // project and calculate rescaling // reference vectors Lorentz5Momentum n1(ZERO,ZERO,-pa.z(),-pa.z()); Lorentz5Momentum n2(ZERO,ZERO, pa.z(),-pa.z()); Energy2 n1n2 = n1*n2; // decompose the momenta Lorentz5Momentum qbp=rot*pin[1],qcp=rot*pout[1]; qbp.rescaleMass(); qcp.rescaleMass(); double a[2],b[2]; a[0] = n2*qbp/n1n2; b[0] = n1*qbp/n1n2; Lorentz5Momentum qperp = qbp-a[0]*n1-b[0]*n2; b[1] = 0.5; a[1] = 0.5*(qcp.m2()-qperp.m2())/n1n2/b[1]; double kb; if(a[0]!=0.) { double A(0.5*a[0]),B(b[0]*a[0]-a[1]*b[1]-0.25),C(-0.5*b[0]); if(sqr(B)-4.*A*C<0.) throw KinematicsReconstructionVeto(); kb = 0.5*(-B+sqrt(sqr(B)-4.*A*C))/A; } else { kb = 0.5*b[0]/(b[0]*a[0]-a[1]*b[1]-0.25); } // changed to improve stability if(kb==0.) throw KinematicsReconstructionVeto(); if ( a[1]>b[1] && abs(a[1]) < 1e-12 ) throw KinematicsReconstructionVeto(); if ( a[1]<=b[1] && abs(0.5+b[0]/kb) < 1e-12 ) throw KinematicsReconstructionVeto(); double kc = (a[1]>b[1]) ? (a[0]*kb-0.5)/a[1] : b[1]/(0.5+b[0]/kb); if(kc==0.) throw KinematicsReconstructionVeto(); Lorentz5Momentum pnew[2] = { a[0]*kb*n1+b[0]/kb*n2+qperp, a[1]*kc*n1+b[1]/kc*n2+qperp}; LorentzRotation rotinv=rot.inverse(); for(unsigned int ix=0;ixprogenitor()->isFinalState()) { deepTransform(jets[ix]->progenitor(),rot); deepTransform(jets[ix]->progenitor(),solveBoost(pnew[1],qcp)); Energy delta = jets[ix]->progenitor()->momentum().m()-jets[ix]->progenitor()->momentum().mass(); if ( abs(delta) > MeV ) throw KinematicsReconstructionVeto(); deepTransform(jets[ix]->progenitor(),rotinv); } else { tPPtr parent; boostChain(jets[ix]->progenitor(),rot,parent); boostChain(jets[ix]->progenitor(),solveBoostZ(pnew[0],qbp),parent); // check the first boost worked, and if not apply small correction to // fix energy/momentum conservation // this is a kludge but it reduces momentum non-conservation dramatically Lorentz5Momentum pdiff = pnew[0]-jets[ix]->progenitor()->momentum(); Energy2 delta = sqr(pdiff.x())+sqr(pdiff.y())+sqr(pdiff.z())+sqr(pdiff.t()); unsigned int ntry=0; while(delta>1e-6*GeV2 && ntry<5 ) { ntry +=1; boostChain(jets[ix]->progenitor(),solveBoostZ(pnew[0],jets[ix]->progenitor()->momentum()),parent); pdiff = pnew[0]-jets[ix]->progenitor()->momentum(); delta = sqr(pdiff.x())+sqr(pdiff.y())+sqr(pdiff.z())+sqr(pdiff.t()); } // apply test in breit-frame Lorentz5Momentum ptest1 = parent->momentum(); Lorentz5Momentum ptest2 = rot*pbeam; if(ptest1.z()/ptest2.z()<0. || ptest1.z()/ptest2.z()>1.) throw KinematicsReconstructionVeto(); boostChain(jets[ix]->progenitor(),rotinv,parent); } } } bool QTildeReconstructor::addIntrinsicPt(vector jets) const { bool added=false; // add the intrinsic pt if needed for(unsigned int ix=0;ixprogenitor()->isFinalState()|| jets[ix]->hasEmitted()|| jets[ix]->reconstructed()==ShowerProgenitor::dontReconstruct) continue; if(_intrinsic.find(jets[ix])==_intrinsic.end()) continue; pair pt=_intrinsic[jets[ix]]; Energy etemp = jets[ix]->original()->parents()[0]->momentum().z(); Lorentz5Momentum p_basis(ZERO, ZERO, etemp, abs(etemp)), n_basis(ZERO, ZERO,-etemp, abs(etemp)); double alpha = jets[ix]->progenitor()->x(); double beta = 0.5*(sqr(jets[ix]->progenitor()->data().mass())+ sqr(pt.first))/alpha/(p_basis*n_basis); Lorentz5Momentum pnew=alpha*p_basis+beta*n_basis; pnew.setX(pt.first*cos(pt.second)); pnew.setY(pt.first*sin(pt.second)); pnew.rescaleMass(); jets[ix]->progenitor()->set5Momentum(pnew); added = true; } return added; } LorentzRotation QTildeReconstructor:: solveBoost(const double k, const Lorentz5Momentum & newq, const Lorentz5Momentum & oldp ) const { Energy q = newq.vect().mag(); Energy2 qs = sqr(q); Energy2 Q2 = newq.mass2(); Energy kp = k*(oldp.vect().mag()); Energy2 kps = sqr(kp); double betam = (q*newq.e() - kp*sqrt(kps + Q2))/(kps + qs + Q2); if ( abs(betam) - 1. >= 0. ) throw KinematicsReconstructionVeto(); Boost beta = -betam*(k/kp)*oldp.vect(); double gamma = 0.; if(Q2/sqr(oldp.e())>1e-4) { if(betam<0.5) { gamma = 1./sqrt(1.-sqr(betam)); } else { gamma = ( kps+ qs + Q2)/ sqrt(2.*kps*qs + kps*Q2 + qs*Q2 + sqr(Q2) + 2.*q*newq.e()*kp*sqrt(kps + Q2)); } } else { if(k>0) { gamma = 4.*kps*qs/sqr(kps +qs) + 2.*sqr(kps-qs)*Q2/pow<3,1>(kps +qs) - 0.25*( sqr(kps) + 14.*kps*qs + sqr(qs))*sqr(kps-qs)/(pow<4,1>(kps +qs)*kps*qs)*sqr(Q2); } else { gamma = 0.25*sqr(Q2)/(kps*qs)*(1. - 0.5*(kps+qs)/(kps*qs)*Q2); } if(gamma<=0.) throw KinematicsReconstructionVeto(); gamma = 1./sqrt(gamma); } // note that (k/kp)*oldp.vect() = oldp.vect()/oldp.vect().mag() but cheaper. ThreeVector ax = newq.vect().cross( oldp.vect() ); double delta = newq.vect().angle( oldp.vect() ); LorentzRotation R; using Constants::pi; Energy2 scale1 = sqr(newq.x())+ sqr(newq.y())+sqr(newq.z()); Energy2 scale2 = sqr(oldp.x())+ sqr(oldp.y())+sqr(oldp.z()); if ( ax.mag2()/scale1/scale2 > 1e-28 ) { R.rotate( delta, unitVector(ax) ).boost( beta , gamma ); } else if(abs(delta-pi)/pi < 0.001) { double phi=2.*pi*UseRandom::rnd(); Axis axis(cos(phi),sin(phi),0.); axis.rotateUz(newq.vect().unit()); R.rotate(delta,axis).boost( beta , gamma ); } else { R.boost( beta , gamma ); } return R; } LorentzRotation QTildeReconstructor::solveBoost(const Lorentz5Momentum & q, const Lorentz5Momentum & p ) const { Energy modp = p.vect().mag(); Energy modq = q.vect().mag(); double betam = (p.e()*modp-q.e()*modq)/(sqr(modq)+sqr(modp)+p.mass2()); if ( abs(betam)-1. >= 0. ) throw KinematicsReconstructionVeto(); Boost beta = -betam*q.vect().unit(); ThreeVector ax = p.vect().cross( q.vect() ); double delta = p.vect().angle( q.vect() ); LorentzRotation R; using Constants::pi; if ( beta.mag2() - 1. >= 0. ) throw KinematicsReconstructionVeto(); if ( ax.mag2()/GeV2/MeV2 > 1e-16 ) { R.rotate( delta, unitVector(ax) ).boost( beta ); } else { R.boost( beta ); } return R; } LorentzRotation QTildeReconstructor::solveBoostZ(const Lorentz5Momentum & q, const Lorentz5Momentum & p ) const { static const double eps = 1e-6; LorentzRotation R; double beta; Energy2 mt2 = p.mass()eps) { double erat = (q.t()+q.z())/(p.t()+p.z()); Energy2 den = mt2*(erat+1./erat); Energy2 num = (q.z()-p.z())*(q.t()+p.t()) + (p.z()+q.z())*(p.t()-q.t()); beta = num/den; if ( abs(beta) - 1. >= 0. ) throw KinematicsReconstructionVeto(); R.boostZ(beta); } else { double er = sqr(p.t()/q.t()); double x = ratio+0.125*(er+10.+1./er)*sqr(ratio); beta = -(p.t()-q.t())*(p.t()+q.t())/(sqr(p.t())+sqr(q.t()))*(1.+x); double gamma = (4.*sqr(p.t()*q.t()) +sqr(p.t()-q.t())*sqr(p.t()+q.t())* (-2.*x+sqr(x)))/sqr(sqr(p.t())+sqr(q.t())); if ( abs(beta) - 1. >= 0. ) throw KinematicsReconstructionVeto(); gamma = 1./sqrt(gamma); R.boost(0.,0.,beta,gamma); } Lorentz5Momentum ptest = R*p; if(ptest.z()/q.z() < 0. || ptest.t()/q.t() < 0. ) { throw KinematicsReconstructionVeto(); } return R; } void QTildeReconstructor:: reconstructFinalStateSystem(bool applyBoost, const LorentzRotation & toRest, const LorentzRotation & fromRest, vector jets) const { LorentzRotation trans = applyBoost? toRest : LorentzRotation(); // special for case of individual particle if(jets.size()==1) { deepTransform(jets[0]->progenitor(),trans); deepTransform(jets[0]->progenitor(),fromRest); return; } bool radiated(false); // find the hard process centre-of-mass energy Lorentz5Momentum pcm; // check if radiated and calculate total momentum for(unsigned int ix=0;ixhasEmitted(); pcm += jets[ix]->progenitor()->momentum(); } if(applyBoost) pcm *= trans; // check if in CMF frame Boost beta_cm = pcm.findBoostToCM(); bool gottaBoost(false); if(beta_cm.mag() > 1e-12) { gottaBoost = true; trans.boost(beta_cm); } // collection of pointers to initial hard particle and jet momenta // for final boosts JetKinVect jetKinematics; vector::const_iterator cit; for(cit = jets.begin(); cit != jets.end(); cit++) { JetKinStruct tempJetKin; tempJetKin.parent = (*cit)->progenitor(); if(applyBoost || gottaBoost) { deepTransform(tempJetKin.parent,trans); } tempJetKin.p = (*cit)->progenitor()->momentum(); _progenitor=tempJetKin.parent; if((**cit).reconstructed()==ShowerProgenitor::notReconstructed) { radiated |= reconstructTimeLikeJet((*cit)->progenitor()); (**cit).reconstructed(ShowerProgenitor::done); } else { radiated |= !(*cit)->progenitor()->children().empty(); } tempJetKin.q = (*cit)->progenitor()->momentum(); jetKinematics.push_back(tempJetKin); } // default option rescale everything with the same factor if( _finalStateReconOption == 0 || jetKinematics.size() <= 2 ) { // find the rescaling factor double k = 0.0; if(radiated) { k = solveKfactor(pcm.m(), jetKinematics); // perform the rescaling and boosts for(JetKinVect::iterator it = jetKinematics.begin(); it != jetKinematics.end(); ++it) { LorentzRotation Trafo = solveBoost(k, it->q, it->p); deepTransform(it->parent,Trafo); } } } // different treatment of most off-shell else if ( _finalStateReconOption <= 4 ) { // sort the jets by virtuality std::sort(jetKinematics.begin(),jetKinematics.end(),JetOrdering()); // Bryan's procedures from FORTRAN if( _finalStateReconOption <=2 ) { // loop over the off-shell partons, _finalStateReconOption==1 only first ==2 all JetKinVect::const_iterator jend = _finalStateReconOption==1 ? jetKinematics.begin()+1 : jetKinematics.end(); for(JetKinVect::const_iterator jit=jetKinematics.begin(); jit!=jend;++jit) { // calculate the 4-momentum of the recoiling system Lorentz5Momentum psum; bool done = true; for(JetKinVect::const_iterator it=jetKinematics.begin();it!=jetKinematics.end();++it) { if(it==jit) { done = false; continue; } // first option put on-shell and sum 4-momenta if( _finalStateReconOption == 1 ) { LorentzRotation Trafo = solveBoost(1., it->q, it->p); deepTransform(it->parent,Trafo); psum += it->parent->momentum(); } // second option, sum momenta else { // already rescaled if(done) psum += it->parent->momentum(); // still needs to be rescaled else psum += it->p; } } // set the mass psum.rescaleMass(); // calculate the 3-momentum rescaling factor Energy2 s(pcm.m2()); Energy2 m1sq(jit->q.m2()),m2sq(psum.m2()); Energy4 num = sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq; if(nump.vect().mag2()) ); // boost the off-shell parton LorentzRotation B1 = solveBoost(k, jit->q, jit->p); deepTransform(jit->parent,B1); // boost everything else to rescale LorentzRotation B2 = solveBoost(k, psum, psum); for(JetKinVect::iterator it=jetKinematics.begin();it!=jetKinematics.end();++it) { if(it==jit) continue; deepTransform(it->parent,B2); it->p *= B2; it->q *= B2; } } } // Peter's C++ procedures else { reconstructFinalFinalOffShell(jetKinematics,pcm.m2(), _finalStateReconOption == 4); } } else assert(false); // apply the final boosts if(gottaBoost || applyBoost) { LorentzRotation finalBoosts; if(gottaBoost) finalBoosts.boost(-beta_cm); if(applyBoost) finalBoosts.transform(fromRest); for(JetKinVect::iterator it = jetKinematics.begin(); it != jetKinematics.end(); ++it) { deepTransform(it->parent,finalBoosts); } } } void QTildeReconstructor:: reconstructInitialInitialSystem(bool & applyBoost, LorentzRotation & toRest, LorentzRotation & fromRest, vector jets) const { bool radiated = false; Lorentz5Momentum pcm; // check whether particles radiated and calculate total momentum for( unsigned int ix = 0; ix < jets.size(); ++ix ) { radiated |= jets[ix]->hasEmitted(); pcm += jets[ix]->progenitor()->momentum(); if(jets[ix]->original()->parents().empty()) return; } pcm.rescaleMass(); // check if intrinsic pt to be added radiated |= !_intrinsic.empty(); // if no radiation return if(!radiated) { for(unsigned int ix=0;ixreconstructed()==ShowerProgenitor::notReconstructed) jets[ix]->reconstructed(ShowerProgenitor::done); } return; } // initial state shuffling applyBoost=false; vector p, pq, p_in; vector pts; for(unsigned int ix=0;ixprogenitor()->momentum()); // reconstruct the jet if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { radiated |= reconstructSpaceLikeJet(jets[ix]->progenitor()); jets[ix]->reconstructed(ShowerProgenitor::done); } assert(!jets[ix]->original()->parents().empty()); Energy etemp = jets[ix]->original()->parents()[0]->momentum().z(); Lorentz5Momentum ptemp = Lorentz5Momentum(ZERO, ZERO, etemp, abs(etemp)); pq.push_back(ptemp); pts.push_back(jets[ix]->highestpT()); } // add the intrinsic pt if needed radiated |=addIntrinsicPt(jets); for(unsigned int ix=0;ixprogenitor()->momentum()); } double x1 = p_in[0].z()/pq[0].z(); double x2 = p_in[1].z()/pq[1].z(); vector beta=initialStateRescaling(x1,x2,p_in[0]+p_in[1],p,pq,pts); // if not need don't apply boosts if(!(radiated && p.size() == 2 && pq.size() == 2)) return; applyBoost=true; // apply the boosts Lorentz5Momentum newcmf; for(unsigned int ix=0;ixprogenitor(); Boost betaboost(0, 0, beta[ix]); tPPtr parent; boostChain(toBoost, LorentzRotation(0.,0.,beta[ix]),parent); if(parent->momentum().e()/pq[ix].e()>1.|| parent->momentum().z()/pq[ix].z()>1.) throw KinematicsReconstructionVeto(); newcmf+=toBoost->momentum(); } if(newcmf.m() jets, ShowerInteraction::Type) const { assert(jets.size()==2); // put beam with +z first if(jets[0]->beam()->momentum().z() pin,pq; for(unsigned int ix=0;ixbranchingParticle()->momentum()); Energy etemp = jets[ix]->beam()->momentum().z(); pq.push_back(Lorentz5Momentum(ZERO, ZERO,etemp, abs(etemp))); } // calculate the rescaling double x[2]; Lorentz5Momentum pcm=pin[0]+pin[1]; assert(pcm.mass2()>ZERO); pcm.rescaleMass(); vector boost = inverseInitialStateRescaling(x[0],x[1],pcm,pin,pq); set::const_iterator cjt=tree->incoming().begin(); HardBranchingPtr incoming[2]; incoming[0] = *cjt; ++cjt; incoming[1] = *cjt; if((*tree->incoming().begin())->beam()->momentum().z()/pq[0].z()<0.) swap(incoming[0],incoming[1]); // apply the boost the the particles unsigned int iswap[2]={1,0}; for(unsigned int ix=0;ix<2;++ix) { LorentzRotation R(0.,0.,-boost[ix]); incoming[ix]->pVector(pq[ix]); incoming[ix]->nVector(pq[iswap[ix]]); incoming[ix]->setMomenta(R,1.,Lorentz5Momentum()); jets[ix]->showerMomentum(x[ix]*jets[ix]->pVector()); } // and calculate the boosts applyBoost=true; // do one boost if(_initialBoost==0) { toRest = LorentzRotation(-pcm.boostVector()); } else if(_initialBoost==1) { // first the transverse boost Energy pT = sqrt(sqr(pcm.x())+sqr(pcm.y())); double beta = -pT/pcm.t(); toRest=LorentzRotation(Boost(beta*pcm.x()/pT,beta*pcm.y()/pT,0.)); // the longitudinal beta = pcm.z()/sqrt(pcm.m2()+sqr(pcm.z())); toRest.boost(Boost(0.,0.,-beta)); } else assert(false); fromRest = LorentzRotation((jets[0]->showerMomentum()+ jets[1]->showerMomentum()).boostVector()); } void QTildeReconstructor:: deconstructFinalStateSystem(const LorentzRotation & toRest, const LorentzRotation & fromRest, HardTreePtr tree, vector jets, cEvolverPtr evolver, ShowerInteraction::Type type) const { LorentzRotation trans = toRest; if(jets.size()==1) { Lorentz5Momentum pnew = toRest*(jets[0]->branchingParticle()->momentum()); pnew *= fromRest; jets[0]-> original(pnew); jets[0]->showerMomentum(pnew); // find the colour partners ShowerParticleVector particles; vector ptemp; set::const_iterator cjt; for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { ptemp.push_back((**cjt).branchingParticle()->momentum()); (**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum()); particles.push_back((**cjt).branchingParticle()); } evolver->showerModel()->partnerFinder() ->setInitialEvolutionScales(particles,false,type,false); // calculate the reference vectors unsigned int iloc(0); set::iterator clt; for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { // reset the momentum (**cjt).branchingParticle()->set5Momentum(ptemp[iloc]); ++iloc; // sort out the partners tShowerParticlePtr partner = (*cjt)->branchingParticle()->partner(); if(!partner) continue; for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { if((**clt).branchingParticle()==partner) { (**cjt).colourPartner(*clt); break; } } tHardBranchingPtr branch; for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { if(clt==cjt) continue; if((*clt)->branchingParticle()==partner) { branch=*clt; break; } } } return; } vector::iterator cit; vector pout; vector mon; Lorentz5Momentum pin; for(cit=jets.begin();cit!=jets.end();++cit) { pout.push_back((*cit)->branchingParticle()->momentum()); mon.push_back(findMass(*cit)); pin+=pout.back(); } // boost all the momenta to the rest frame of the decaying particle pin.rescaleMass(); pin *=trans; Boost beta_cm = pin.findBoostToCM(); bool gottaBoost(false); if(beta_cm.mag() > 1e-12) { gottaBoost = true; trans.boost(beta_cm); pin.boost(beta_cm); } for(unsigned int ix=0;ixbranchingParticle()->momentum(); pvect.transform(trans); pvect /= lambda; pvect.setMass(mon[ix]); pvect.rescaleEnergy(); if(gottaBoost) pvect.boost(-beta_cm); pvect.transform(fromRest); jets[ix]->pVector(pvect); jets[ix]->showerMomentum(pvect); } // find the colour partners ShowerParticleVector particles; vector ptemp; set::const_iterator cjt; for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { ptemp.push_back((**cjt).branchingParticle()->momentum()); (**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum()); particles.push_back((**cjt).branchingParticle()); } evolver->showerModel()->partnerFinder() ->setInitialEvolutionScales(particles,false,type,false); // calculate the reference vectors unsigned int iloc(0); set::iterator clt; for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { // reset the momentum (**cjt).branchingParticle()->set5Momentum(ptemp[iloc]); ++iloc; } for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { // sort out the partners tShowerParticlePtr partner = (*cjt)->branchingParticle()->partner(); if(!partner) continue; for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { if((**clt).branchingParticle()==partner) { (**cjt).colourPartner(*clt); break; } } tHardBranchingPtr branch; for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { if(clt==cjt) continue; if((*clt)->branchingParticle()==partner) { branch=*clt; break; } } // compute the reference vectors // both incoming, should all ready be done if((**cjt).status()==HardBranching::Incoming && (**clt).status()==HardBranching::Incoming) { continue; } // both outgoing else if((**cjt).status()!=HardBranching::Incoming&& branch->status()==HardBranching::Outgoing) { Boost boost=((*cjt)->pVector()+branch->pVector()).findBoostToCM(); Lorentz5Momentum pcm = branch->pVector(); pcm.boost(boost); Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect()); nvect.boost( -boost); (**cjt).nVector(nvect); } else if((**cjt).status()==HardBranching::Incoming) { Lorentz5Momentum pa = -(**cjt).showerMomentum()+branch->showerMomentum(); Lorentz5Momentum pb = (**cjt).showerMomentum(); Axis axis(pa.vect().unit()); LorentzRotation rot; double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot.rotateX(Constants::pi); rot.boostZ( pa.e()/pa.vect().mag()); pb*=rot; Boost trans = -1./pb.e()*pb.vect(); trans.setZ(0.); rot.boost(trans); Energy scale=(**cjt).beam()->momentum().e(); Lorentz5Momentum pbasis(ZERO,(**cjt).beam()->momentum().vect().unit()*scale); Lorentz5Momentum pcm = rot*pbasis; rot.invert(); (**cjt).nVector(rot*Lorentz5Momentum(ZERO,-pcm.vect())); tHardBranchingPtr branch2 = *cjt;; while (branch2->parent()) { branch2=branch2->parent(); branch2->nVector(rot*Lorentz5Momentum(ZERO,-pcm.vect())); } } else if(branch->status()==HardBranching::Incoming) { (**cjt).nVector(Lorentz5Momentum(ZERO,branch->showerMomentum().vect())); } } // now compute the new momenta for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { if(!(*cjt)->branchingParticle()->isFinalState()) continue; Lorentz5Momentum qnew; if((*cjt)->branchingParticle()->partner()) { Energy2 dot=(*cjt)->pVector()*(*cjt)->nVector(); double beta = 0.5*((*cjt)->branchingParticle()->momentum().m2() -sqr((*cjt)->pVector().mass()))/dot; qnew=(*cjt)->pVector()+beta*(*cjt)->nVector(); qnew.rescaleMass(); } else { qnew = (*cjt)->pVector(); } // qnew is the unshuffled momentum in the rest frame of the p basis vectors, // for the simple case Z->q qbar g this was checked against analytic formulae. // compute the boost LorentzRotation R=solveBoost(qnew, toRest*(*cjt)->branchingParticle()->momentum())*toRest; (*cjt)->setMomenta(R,1.0,Lorentz5Momentum()); } } Energy QTildeReconstructor::momConsEq(const double & k, const Energy & root_s, const JetKinVect & jets) const { static const Energy2 eps=1e-8*GeV2; Energy dum = ZERO; for(JetKinVect::const_iterator it = jets.begin(); it != jets.end(); ++it) { Energy2 dum2 = (it->q).m2() + sqr(k)*(it->p).vect().mag2(); if(dum2 < ZERO) { if(dum2 < -eps) throw KinematicsReconstructionVeto(); dum2 = ZERO; } dum += sqrt(dum2); } return dum - root_s; } void QTildeReconstructor::boostChain(tPPtr p, const LorentzRotation &bv, tPPtr & parent) const { if(!p->parents().empty()) boostChain(p->parents()[0], bv,parent); else parent=p; p->transform(bv); if(p->children().size()==2) { if(dynamic_ptr_cast(p->children()[1])) deepTransform(p->children()[1],bv); } } namespace { bool sortJets(ShowerProgenitorPtr j1, ShowerProgenitorPtr j2) { return j1->highestpT()>j2->highestpT(); } } void QTildeReconstructor:: reconstructGeneralSystem(vector & ShowerHardJets) const { // find initial- and final-state systems ColourSingletSystem in,out; for(unsigned int ix=0;ixprogenitor()->isFinalState()) out.jets.push_back(ShowerHardJets[ix]); else in.jets.push_back(ShowerHardJets[ix]); } // reconstruct initial-initial system LorentzRotation toRest,fromRest; bool applyBoost(false); // reconstruct initial-initial system reconstructInitialInitialSystem(applyBoost,toRest,fromRest,in.jets); // reconstruct the final-state systems reconstructFinalStateSystem(applyBoost,toRest,fromRest,out.jets); } void QTildeReconstructor:: reconstructFinalFirst(vector & ShowerHardJets) const { static const Energy2 minQ2 = 1e-4*GeV2; map used; for(unsigned int ix=0;ix outgoing; // first find any particles with final state partners for(unsigned int ix=0;ixprogenitor()->isFinalState()&& ShowerHardJets[ix]->progenitor()->partner()&& ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) outgoing.insert(ShowerHardJets[ix]); } // then find the colour partners if(!outgoing.empty()) { set partners; for(set::const_iterator it=outgoing.begin();it!=outgoing.end();++it) { for(unsigned int ix=0;ixpartner()==ShowerHardJets[ix]->progenitor()) { partners.insert(ShowerHardJets[ix]); break; } } } outgoing.insert(partners.begin(),partners.end()); } // do the final-state reconstruction if needed if(!outgoing.empty()) { assert(outgoing.size()!=1); LorentzRotation toRest,fromRest; vector outgoingJets(outgoing.begin(),outgoing.end()); reconstructFinalStateSystem(false,toRest,fromRest,outgoingJets); } // Now do any initial-final systems which are needed vector IFSystems; // find the systems N.B. can have duplicates // find initial-state with FS partners or FS with IS partners for(unsigned int ix=0;ixprogenitor()->isFinalState()&& ShowerHardJets[ix]->progenitor()->partner()&& ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) { IFSystems.push_back(ColourSingletSystem(IF,ShowerHardJets[ix])); } else if(ShowerHardJets[ix]->progenitor()->isFinalState()&& ShowerHardJets[ix]->progenitor()->partner()&& !ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) { IFSystems.push_back(ColourSingletSystem(IF,ShowerHardJets[ix])); } } // then add the partners for(unsigned int is=0;isprogenitor()->partner()==ShowerHardJets[ix]->progenitor()) { IFSystems[is].jets.push_back(ShowerHardJets[ix]); } } // ensure incoming first if(IFSystems[is].jets[0]->progenitor()->isFinalState()) swap(IFSystems[is].jets[0],IFSystems[is].jets[1]); } if(!IFSystems.empty()) { unsigned int istart = UseRandom::irnd(IFSystems.size()); unsigned int istop=IFSystems.size(); for(unsigned int is=istart;is<=istop;++is) { if(is==IFSystems.size()) { if(istart!=0) { istop = istart-1; is=0; } else break; } // skip duplicates if(used[IFSystems[is].jets[0]] && used[IFSystems[is].jets[1]] ) continue; if(IFSystems[is].jets[0]->original()&&IFSystems[is].jets[0]->original()->parents().empty()) continue; Lorentz5Momentum psum; for(unsigned int ix=0;ixprogenitor()->isFinalState()) psum += IFSystems[is].jets[ix]->progenitor()->momentum(); else psum -= IFSystems[is].jets[ix]->progenitor()->momentum(); } if(-psum.m2()>minQ2) { reconstructInitialFinalSystem(IFSystems[is].jets); for(unsigned int ix=0;ixprogenitor()->isFinalState()) out.jets.push_back(ShowerHardJets[ix]); else in.jets.push_back(ShowerHardJets[ix]); } // reconstruct initial-initial system bool doRecon = false; for(unsigned int ix=0;ix & ShowerHardJets) const { static const Energy2 minQ2 = 1e-4*GeV2; // sort the vector by hardness of emission std::sort(ShowerHardJets.begin(),ShowerHardJets.end(),sortJets); // map between particles and progenitors for easy lookup map progenitorMap; for(unsigned int ix=0;ixprogenitor()] = ShowerHardJets[ix]; } // check that the IF systems can be reconstructed bool canReconstruct = true; for(unsigned int ix=0;ixprogenitor(); tShowerParticlePtr partner = progenitor->partner(); if(!partner) continue; else if((progenitor->isFinalState() && !partner->isFinalState()) || (!progenitor->isFinalState() && partner->isFinalState()) ) { vector jets(2); jets[0] = ShowerHardJets[ix]; jets[1] = progenitorMap[partner]; Lorentz5Momentum psum; for(unsigned int iy=0;iyprogenitor()->isFinalState()) psum += jets[iy]->progenitor()->momentum(); else psum -= jets[iy]->progenitor()->momentum(); } if(-psum.m2() used; for(unsigned int ix=0;ixreconstructed()==ShowerProgenitor::done) continue; // already reconstructed if(used[ShowerHardJets[ix]]) continue; // no partner continue tShowerParticlePtr progenitor = ShowerHardJets[ix]->progenitor(); tShowerParticlePtr partner = progenitor->partner(); if(!partner) { // check if there's a daughter tree which also needs boosting Lorentz5Momentum porig = progenitor->momentum(); map >::const_iterator tit; for(tit = _currentTree->treelinks().begin(); tit != _currentTree->treelinks().end();++tit) { // if there is, boost it if(tit->second.first && tit->second.second==progenitor) { Lorentz5Momentum pnew = tit->first->incomingLines().begin() ->first->progenitor()->momentum(); pnew *= tit->first->transform(); Lorentz5Momentum pdiff = porig-pnew; Energy2 test = sqr(pdiff.x()) + sqr(pdiff.y()) + sqr(pdiff.z()) + sqr(pdiff.t()); LorentzRotation rot; if(test>1e-6*GeV2) rot = solveBoost(porig,pnew); tit->first->transform(rot,false); _treeBoosts[tit->first].push_back(rot); } } ShowerHardJets[ix]->reconstructed(ShowerProgenitor::done); continue; } // do the reconstruction // final-final if(progenitor->isFinalState() && partner->isFinalState() ) { LorentzRotation toRest,fromRest; vector jets(2); jets[0] = ShowerHardJets[ix]; jets[1] = progenitorMap[partner]; if(_reconopt==4 && jets[1]->reconstructed()==ShowerProgenitor::notReconstructed) jets[1]->reconstructed(ShowerProgenitor::dontReconstruct); reconstructFinalStateSystem(false,toRest,fromRest,jets); if(_reconopt==4 && jets[1]->reconstructed()==ShowerProgenitor::dontReconstruct) jets[1]->reconstructed(ShowerProgenitor::notReconstructed); used[jets[0]] = true; if(_reconopt==3) used[jets[1]] = true; } // initial-final else if((progenitor->isFinalState() && !partner->isFinalState()) || (!progenitor->isFinalState() && partner->isFinalState()) ) { vector jets(2); jets[0] = ShowerHardJets[ix]; jets[1] = progenitorMap[partner]; if(jets[0]->progenitor()->isFinalState()) swap(jets[0],jets[1]); if(jets[0]->original()&&jets[0]->original()->parents().empty()) continue; Lorentz5Momentum psum; for(unsigned int iy=0;iyprogenitor()->isFinalState()) psum += jets[iy]->progenitor()->momentum(); else psum -= jets[iy]->progenitor()->momentum(); } if(_reconopt==4 && progenitorMap[partner]->reconstructed()==ShowerProgenitor::notReconstructed) progenitorMap[partner]->reconstructed(ShowerProgenitor::dontReconstruct); reconstructInitialFinalSystem(jets); if(_reconopt==4 && progenitorMap[partner]->reconstructed()==ShowerProgenitor::dontReconstruct) progenitorMap[partner]->reconstructed(ShowerProgenitor::notReconstructed); used[ShowerHardJets[ix]] = true; if(_reconopt==3) used[progenitorMap[partner]] = true; } // initial-initial else if(!progenitor->isFinalState() && !partner->isFinalState() ) { ColourSingletSystem in,out; in.jets.push_back(ShowerHardJets[ix]); in.jets.push_back(progenitorMap[partner]); for(unsigned int iy=0;iyprogenitor()->isFinalState()) out.jets.push_back(ShowerHardJets[iy]); } LorentzRotation toRest,fromRest; bool applyBoost(false); if(_reconopt==4 && in.jets[1]->reconstructed()==ShowerProgenitor::notReconstructed) in.jets[1]->reconstructed(ShowerProgenitor::dontReconstruct); reconstructInitialInitialSystem(applyBoost,toRest,fromRest,in.jets); if(_reconopt==4 && in.jets[1]->reconstructed()==ShowerProgenitor::dontReconstruct) in.jets[1]->reconstructed(ShowerProgenitor::notReconstructed); used[in.jets[0]] = true; if(_reconopt==3) used[in.jets[1]] = true; for(unsigned int iy=0;iyreconstructed()==ShowerProgenitor::notReconstructed) out.jets[iy]->reconstructed(ShowerProgenitor::dontReconstruct); } // reconstruct the final-state systems LorentzRotation finalBoosts; finalBoosts.transform( toRest); finalBoosts.transform(fromRest); for(unsigned int iy=0;iyprogenitor(),finalBoosts); } for(unsigned int iy=0;iyreconstructed()==ShowerProgenitor::dontReconstruct) out.jets[iy]->reconstructed(ShowerProgenitor::notReconstructed); } } } } bool QTildeReconstructor:: inverseDecayRescalingFactor(vector pout, vector mon,Energy roots, Lorentz5Momentum ppartner, Energy mbar, double & k1, double & k2) const { ThreeVector qtotal; vector pmag; for(unsigned int ix=0;ix1e10) return false; } while (abs(numer)>eps&&itry<100); k1 = abs(k1); k2 = a*k1; return itry<100; } void QTildeReconstructor:: deconstructInitialFinalSystem(HardTreePtr tree,vector jets, cEvolverPtr evolver, ShowerInteraction::Type type) const { HardBranchingPtr incoming; Lorentz5Momentum pin[2],pout[2],pbeam; HardBranchingPtr initial; Energy mc(ZERO); for(unsigned int ix=0;ixstatus()==HardBranching::Outgoing) { pout[0] += jets[ix]->branchingParticle()->momentum(); mc = jets[ix]->branchingParticle()->thePEGBase() ? jets[ix]->branchingParticle()->thePEGBase()->mass() : jets[ix]->branchingParticle()->dataPtr()->mass(); } // initial-state parton else { pin[0] += jets[ix]->branchingParticle()->momentum(); initial = jets[ix]; pbeam = jets[ix]->beam()->momentum(); Energy scale=pbeam.t(); pbeam = Lorentz5Momentum(ZERO,pbeam.vect().unit()*scale); incoming = jets[ix]; while(incoming->parent()) incoming = incoming->parent(); } } if(jets.size()>2) { pout[0].rescaleMass(); mc = pout[0].mass(); } // work out the boost to the Breit frame Lorentz5Momentum pa = pout[0]-pin[0]; Axis axis(pa.vect().unit()); LorentzRotation rot; double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); if(axis.perp2()>0.) { rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot.rotateX(Constants::pi); rot.boostZ( pa.e()/pa.vect().mag()); } // transverse part Lorentz5Momentum paxis=rot*pbeam; Boost trans = -1./paxis.e()*paxis.vect(); trans.setZ(0.); rot.boost(trans); pa *= rot; // reference vectors Lorentz5Momentum n1(ZERO,ZERO,-pa.z(),-pa.z()); Lorentz5Momentum n2(ZERO,ZERO, pa.z(),-pa.z()); Energy2 n1n2 = n1*n2; // decompose the momenta Lorentz5Momentum qbp=rot*pin[0],qcp= rot*pout[0]; double a[2],b[2]; a[0] = n2*qbp/n1n2; b[0] = n1*qbp/n1n2; a[1] = n2*qcp/n1n2; b[1] = n1*qcp/n1n2; Lorentz5Momentum qperp = qbp-a[0]*n1-b[0]*n2; // before reshuffling Energy Q = abs(pa.z()); double c = sqr(mc/Q); Lorentz5Momentum pb(ZERO,ZERO,0.5*Q*(1.+c),0.5*Q*(1.+c)); Lorentz5Momentum pc(ZERO,ZERO,0.5*Q*(c-1.),0.5*Q*(1.+c)); double anew[2],bnew[2]; anew[0] = pb*n2/n1n2; bnew[0] = 0.5*(qbp.m2()-qperp.m2())/n1n2/anew[0]; bnew[1] = pc*n1/n1n2; anew[1] = 0.5*qcp.m2()/bnew[1]/n1n2; Lorentz5Momentum qnewb = (anew[0]*n1+bnew[0]*n2+qperp); Lorentz5Momentum qnewc = (anew[1]*n1+bnew[1]*n2); // initial-state boost LorentzRotation rotinv=rot.inverse(); LorentzRotation transb=rotinv*solveBoostZ(qnewb,qbp)*rot; // final-state boost LorentzRotation transc=rotinv*solveBoost(qnewc,qcp)*rot; // this will need changing for more than one outgoing particle // set the pvectors for(unsigned int ix=0;ixstatus()==HardBranching::Incoming) { jets[ix]->pVector(pbeam); jets[ix]->showerMomentum(rotinv*pb); incoming->pVector(jets[ix]->pVector()); } else { jets[ix]->pVector(rotinv*pc); jets[ix]->showerMomentum(jets[ix]->pVector()); } } // find the colour partners ShowerParticleVector particles; vector ptemp; set::const_iterator cjt; for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { ptemp.push_back((**cjt).branchingParticle()->momentum()); (**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum()); particles.push_back((**cjt).branchingParticle()); } evolver->showerModel()->partnerFinder() ->setInitialEvolutionScales(particles,false,type,false); unsigned int iloc(0); for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { // reset the momentum (**cjt).branchingParticle()->set5Momentum(ptemp[iloc]); ++iloc; } for(vector::const_iterator cjt=jets.begin(); cjt!=jets.end();++cjt) { // sort out the partners tShowerParticlePtr partner = (*cjt)->branchingParticle()->partner(); if(!partner) continue; tHardBranchingPtr branch; for(set::const_iterator clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { if((**clt).branchingParticle()==partner) { (**cjt).colourPartner(*clt); branch=*clt; break; } } // compute the reference vectors // both incoming, should all ready be done if((**cjt).status()==HardBranching::Incoming && branch->status()==HardBranching::Incoming) { Energy etemp = (*cjt)->beam()->momentum().z(); Lorentz5Momentum nvect(ZERO, ZERO,-etemp, abs(etemp)); tHardBranchingPtr branch2 = *cjt; (**cjt).nVector(nvect); while (branch2->parent()) { branch2=branch2->parent(); branch2->nVector(nvect); } } // both outgoing else if((**cjt).status()==HardBranching::Outgoing&& branch->status()==HardBranching::Outgoing) { Boost boost=((*cjt)->pVector()+branch->pVector()).findBoostToCM(); Lorentz5Momentum pcm = branch->pVector(); pcm.boost(boost); Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect()); nvect.boost( -boost); (**cjt).nVector(nvect); } else if((**cjt).status()==HardBranching::Incoming) { Lorentz5Momentum pa = -(**cjt).showerMomentum()+branch->showerMomentum(); Lorentz5Momentum pb = (**cjt).showerMomentum(); Axis axis(pa.vect().unit()); LorentzRotation rot; double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); if(axis.perp2()>1e-20) { rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot.rotateX(Constants::pi); } if(abs(1.-pa.e()/pa.vect().mag())>1e-6) rot.boostZ( pa.e()/pa.vect().mag()); pb*=rot; Boost trans = -1./pb.e()*pb.vect(); trans.setZ(0.); rot.boost(trans); Energy scale=(**cjt).beam()->momentum().t(); Lorentz5Momentum pbasis(ZERO,(**cjt).beam()->momentum().vect().unit()*scale); Lorentz5Momentum pcm = rot*pbasis; rot.invert(); Lorentz5Momentum nvect = rot*Lorentz5Momentum(ZERO,-pcm.vect()); (**cjt).nVector(nvect); tHardBranchingPtr branch2 = *cjt; while (branch2->parent()) { branch2=branch2->parent(); branch2->nVector(nvect); } } else if(branch->status()==HardBranching::Incoming) { Lorentz5Momentum nvect=Lorentz5Momentum(ZERO,branch->showerMomentum().vect()); (**cjt).nVector(nvect); } } // now compute the new momenta for(vector::const_iterator cjt=jets.begin(); cjt!=jets.end();++cjt) { if((**cjt).status()==HardBranching::Outgoing) { (**cjt).setMomenta(transc,1.,Lorentz5Momentum()); } } incoming->setMomenta(transb,1.,Lorentz5Momentum()); } void QTildeReconstructor::deepTransform(PPtr particle, const LorentzRotation & r, bool match, PPtr original) const { if(_boosts.find(particle)!=_boosts.end()) { _boosts[particle].push_back(r); } Lorentz5Momentum porig = particle->momentum(); if(!original) original = particle; for ( int i = 0, N = particle->children().size(); i < N; ++i ) { deepTransform(particle->children()[i],r, particle->children()[i]->id()==original->id()&&match,original); } particle->transform(r); // transform the p and n vectors ShowerParticlePtr sparticle = dynamic_ptr_cast(particle); if(sparticle && sparticle->showerKinematics()) { sparticle->showerKinematics()->transform(r); } if ( particle->next() ) deepTransform(particle->next(),r,match,original); if(!match) return; if(!particle->children().empty()) return; // force the mass shell if(particle->dataPtr()->stable()) { Lorentz5Momentum ptemp = particle->momentum(); ptemp.rescaleEnergy(); particle->set5Momentum(ptemp); } // check if there's a daughter tree which also needs boosting map >::const_iterator tit; for(tit = _currentTree->treelinks().begin(); tit != _currentTree->treelinks().end();++tit) { // if there is, boost it if(tit->second.first && tit->second.second==original) { Lorentz5Momentum pnew = tit->first->incomingLines().begin() ->first->progenitor()->momentum(); pnew *= tit->first->transform(); Lorentz5Momentum pdiff = porig-pnew; Energy2 test = sqr(pdiff.x()) + sqr(pdiff.y()) + sqr(pdiff.z()) + sqr(pdiff.t()); LorentzRotation rot; if(test>1e-6*GeV2) rot = solveBoost(porig,pnew); tit->first->transform(r*rot,false); _treeBoosts[tit->first].push_back(r*rot); } } } void QTildeReconstructor::reconstructFinalFinalOffShell(JetKinVect orderedJets, Energy2 s, bool recursive) const { JetKinVect::iterator jit; jit = orderedJets.begin(); ++jit; // 4-momentum of recoiling system Lorentz5Momentum psum; for( ; jit!=orderedJets.end(); ++jit) psum += jit->p; psum.rescaleMass(); // calculate the 3-momentum rescaling factor Energy2 m1sq(orderedJets.begin()->q.m2()),m2sq(psum.m2()); Energy4 num = sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq; if(nump.vect().mag2()) ); // boost the most off-shell LorentzRotation B1 = solveBoost(k, orderedJets.begin()->q, orderedJets.begin()->p); deepTransform(orderedJets.begin()->parent,B1); // boost everything else // first to rescale LorentzRotation B2 = solveBoost(k, psum, psum); // and then to rest frame of new system Lorentz5Momentum pnew = B2*psum; pnew.rescaleMass(); B2.transform(pnew.findBoostToCM()); // apply transform (calling routine ensures at least 3 elements) jit = orderedJets.begin(); ++jit; for(;jit!=orderedJets.end();++jit) { deepTransform(jit->parent,B2); jit->p *= B2; jit->q *= B2; } JetKinVect newJets(orderedJets.begin()+1,orderedJets.end()); // final reconstruction if(newJets.size()==2 || !recursive ) { // rescaling factor double k = solveKfactor(psum.m(), newJets); // rescale jets in the new CMF for(JetKinVect::iterator it = newJets.begin(); it != newJets.end(); ++it) { LorentzRotation Trafo = solveBoost(k, it->q, it->p); deepTransform(it->parent,Trafo); } } // recursive else { std::sort(newJets.begin(),newJets.end(),JetOrdering()); reconstructFinalFinalOffShell(newJets,psum.m2(),recursive); } // finally boost back from new CMF LorentzRotation back(-pnew.findBoostToCM()); for(JetKinVect::iterator it = newJets.begin(); it != newJets.end(); ++it) { deepTransform(it->parent,back); } } Energy QTildeReconstructor::findMass(HardBranchingPtr branch) const { // KH - 230909 - If the particle has no children then it will // not have showered and so it should be "on-shell" so we can // get it's mass from it's momentum. This means that the // inverseRescalingFactor doesn't give any nans or do things // it shouldn't if it gets e.g. two Z bosons generated with // off-shell masses. This is for sure not the best solution. // PR 1/1/10 modification to previous soln // PR 28/8/14 change to procedure and factorize into a function if(branch->children().empty()) { return branch->branchingParticle()->mass(); } else if(!branch->children().empty() && !branch->branchingParticle()->dataPtr()->stable() ) { for(unsigned int ix=0;ixchildren().size();++ix) { if(branch->branchingParticle()->id()== branch->children()[ix]->branchingParticle()->id()) return findMass(branch->children()[ix]); } } return branch->branchingParticle()->dataPtr()->mass(); } vector QTildeReconstructor::inverseInitialStateRescaling(double & x1, double & x2, const Lorentz5Momentum & pold, const vector & p, const vector & pq) const { // hadronic CMS Energy2 s = (pq[0] +pq[1] ).m2(); // partonic CMS Energy MDY = pold.m(); // find alpha, beta and pt Energy2 p12=pq[0]*pq[1]; double a[2],b[2]; Lorentz5Momentum pt[2]; for(unsigned int ix=0;ix<2;++ix) { a[ix] = p[ix]*pq[1]/p12; b [ix] = p[ix]*pq[0]/p12; pt[ix] = p[ix]-a[ix]*pq[0]-b[ix]*pq[1]; } // compute kappa // we always want to preserve the mass of the system double k1(1.),k2(1.); if(_initialStateReconOption==0) { double rap=pold.rapidity(); x2 = MDY/sqrt(s*exp(2.*rap)); x1 = sqr(MDY)/s/x2; k1=a[0]/x1; k2=b[1]/x2; } // longitudinal momentum else if(_initialStateReconOption==1) { double A = 1.; double C = -sqr(MDY)/s; double B = 2.*pold.z()/sqrt(s); if(abs(B)>1e-10) { double discrim = 1.-4.*A*C/sqr(B); if(discrim < 0.) throw KinematicsReconstructionVeto(); x1 = B>0. ? 0.5*B/A*(1.+sqrt(discrim)) : 0.5*B/A*(1.-sqrt(discrim)); } else { x1 = -C/A; if( x1 <= 0.) throw KinematicsReconstructionVeto(); x1 = sqrt(x1); } x2 = sqr(MDY)/s/x1; k1=a[0]/x1; k2=b[1]/x2; } // preserve mass and don't scale the softer system // to reproduce the dipole kinematics else if(_initialStateReconOption==2) { // in this case kp = k1 or k2 depending on who's the harder guy k1 = a[0]*b[1]*s/sqr(MDY); if ( pt[0].perp2() < pt[1].perp2() ) swap(k1,k2); x1 = a[0]/k1; x2 = b[1]/k2; } else assert(false); // decompose the momenta double anew[2] = {a[0]/k1,a[1]*k2}; double bnew[2] = {b[0]*k1,b[1]/k2}; vector boost(2); for(unsigned int ix=0;ix<2;++ix) { boost[ix] = getBeta(a [ix]+b [ix], a[ix] -b [ix], anew[ix]+bnew[ix], anew[ix]-bnew[ix]); } return boost; } vector QTildeReconstructor::initialStateRescaling(double x1, double x2, const Lorentz5Momentum & pold, const vector & p, const vector & pq, const vector& highestpts) const { Energy2 S = (pq[0]+pq[1]).m2(); // find alphas and betas in terms of desired basis Energy2 p12 = pq[0]*pq[1]; double a[2] = {p[0]*pq[1]/p12,p[1]*pq[1]/p12}; double b[2] = {p[0]*pq[0]/p12,p[1]*pq[0]/p12}; Lorentz5Momentum p1p = p[0] - a[0]*pq[0] - b[0]*pq[1]; Lorentz5Momentum p2p = p[1] - a[1]*pq[0] - b[1]*pq[1]; // compute kappa // we always want to preserve the mass of the system Energy MDY = pold.m(); Energy2 A = a[0]*b[1]*S; Energy2 B = Energy2(sqr(MDY)) - (a[0]*b[0]+a[1]*b[1])*S - (p1p+p2p).m2(); Energy2 C = a[1]*b[0]*S; double rad = 1.-4.*A*C/sqr(B); if(rad < 0.) throw KinematicsReconstructionVeto(); double kp = B/(2.*A)*(1.+sqrt(rad)); // now compute k1 // conserve rapidity double k1(0.); double k2(0.); if(_initialStateReconOption==0) { rad = kp*(b[0]+kp*b[1])/(kp*a[0]+a[1]); rad *= pq[0].z()1e-10) { double discrim = 1.-4.*a2*c2/sqr(b2); if(discrim < 0.) throw KinematicsReconstructionVeto(); k1 = b2>0. ? 0.5*b2/a2*(1.+sqrt(discrim)) : 0.5*b2/a2*(1.-sqrt(discrim)); } else { k1 = -c2/a2; if( k1 <= 0.) throw KinematicsReconstructionVeto(); k1 = sqrt(k1); } k2 = kp/k1; } // preserve mass and don't scale the softer system // to reproduce the dipole kinematics else if(_initialStateReconOption==2) { // in this case kp = k1 or k2 depending on who's the harder guy k1 = kp; k2 = 1.; if ( highestpts[0] < highestpts[1] ) swap(k1,k2); } else assert(false); // calculate the boosts vector beta(2); beta[0] = getBeta((a[0]+b[0]), (a[0]-b[0]), (k1*a[0]+b[0]/k1), (k1*a[0]-b[0]/k1)); beta[1] = getBeta((a[1]+b[1]), (a[1]-b[1]), (a[1]/k2+k2*b[1]), (a[1]/k2-k2*b[1])); if (pq[0].z() > ZERO) { beta[0] = -beta[0]; beta[1] = -beta[1]; } return beta; } void QTildeReconstructor:: reconstructColourSinglets(vector & ShowerHardJets, ShowerInteraction::Type type) const { // identify and catagorize the colour singlet systems unsigned int nnun(0),nnii(0),nnif(0),nnf(0),nni(0); vector systems(identifySystems(set(ShowerHardJets.begin(),ShowerHardJets.end()), nnun,nnii,nnif,nnf,nni)); // now decide what to do // initial-initial connection and final-state colour singlet systems LorentzRotation toRest,fromRest; bool applyBoost(false),general(false); // Drell-Yan type if(nnun==0&&nnii==1&&nnif==0&&nnf>0&&nni==0) { // reconstruct initial-initial system for(unsigned int ix=0;ix0&&nni==1)|| (nnif==2&& nni==0))) { // check these systems can be reconstructed for(unsigned int ix=0;ixprogenitor()->isFinalState()) q += systems[ix].jets[iy]->progenitor()->momentum(); else q -= systems[ix].jets[iy]->progenitor()->momentum(); } q.rescaleMass(); // check above cut if(abs(q.m())>=_minQ) continue; if(nnif==1&&nni==1) { throw KinematicsReconstructionVeto(); } else { general = true; break; } } if(!general) { for(unsigned int ix=0;ix0&&nni==2) { - general = type==ShowerInteraction::QED || type == ShowerInteraction::Both; + general = type !=ShowerInteraction::QCD; } // general type else { general = true; } // final-state systems except for general recon if(!general) { for(unsigned int ix=0;ix::pointer ColinePtr; /** * Transient Pointer to a ColourLine */ typedef Ptr::transient_pointer tColinePtr; /** * A pair of ColourLine pointers */ typedef pair ColinePair; /** * A pair of transient ColourLine pointers */ typedef pair tColinePair; /** * A Vector of ShowerParticle pointers */ typedef vector ShowerParticleVector; /** * A Vector of transient ShowerParticle pointers */ typedef vector tShowerParticleVector; /** * Definition of the IdList for branchings */ typedef vector IdList; namespace ShowerInteraction { /** * Enum for the type of interaction */ - enum Type { UNDEFINED=-1, QCD, QED, Both }; + enum Type { UNDEFINED=-1, QCD, QED, QEDQCD, EW, ALL }; } namespace ShowerPartnerType { /** * Enum for the type of shower partner */ - enum Type {Undefined,QCDColourLine,QCDAntiColourLine,QED}; + enum Type {Undefined,QCDColourLine,QCDAntiColourLine,QED,EW}; + } + + inline ShowerInteraction::Type convertInteraction(ShowerPartnerType::Type partner) { + if(partner==ShowerPartnerType::QCDColourLine || + partner==ShowerPartnerType::QCDAntiColourLine) + return ShowerInteraction::QCD; + else if(ShowerPartnerType::QED) + return ShowerInteraction::QED; + else if(ShowerPartnerType::EW) + return ShowerInteraction::EW; + else + return ShowerInteraction::UNDEFINED; } /** * typedef to pair the SudakovFormFactor and the particles in a branching */ typedef pair BranchingElement; /** * typedef to pair the PDG code of the particle and the BranchingElement */ typedef multimap BranchingList; /** * typedef to create a structure which can be inserted into a BranchingList */ typedef pair BranchingInsert; } #endif // HERWIG_ShowerConfig_H diff --git a/Shower/SplittingFunctions/SplittingFunction.cc b/Shower/SplittingFunctions/SplittingFunction.cc --- a/Shower/SplittingFunctions/SplittingFunction.cc +++ b/Shower/SplittingFunctions/SplittingFunction.cc @@ -1,876 +1,889 @@ // -*- C++ -*- // // SplittingFunction.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2011 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the SplittingFunction class. // #include "SplittingFunction.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Utilities/EnumIO.h" #include "Herwig/Shower/Base/ShowerParticle.h" #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; DescribeAbstractClass describeSplittingFunction ("Herwig::SplittingFunction",""); void SplittingFunction::Init() { static ClassDocumentation documentation ("The SplittingFunction class is the based class for 1->2 splitting functions" " in Herwig"); static Switch interfaceColourStructure ("ColourStructure", "The colour structure for the splitting function", &SplittingFunction::_colourStructure, Undefined, false, false); static SwitchOption interfaceColourStructureTripletTripletOctet (interfaceColourStructure, "TripletTripletOctet", "3 -> 3 8", TripletTripletOctet); static SwitchOption interfaceColourStructureOctetOctetOctet (interfaceColourStructure, "OctetOctetOctet", "8 -> 8 8", OctetOctetOctet); static SwitchOption interfaceColourStructureOctetTripletTriplet (interfaceColourStructure, "OctetTripletTriplet", "8 -> 3 3bar", OctetTripletTriplet); static SwitchOption interfaceColourStructureTripletOctetTriplet (interfaceColourStructure, "TripletOctetTriplet", "3 -> 8 3", TripletOctetTriplet); static SwitchOption interfaceColourStructureSextetSextetOctet (interfaceColourStructure, "SextetSextetOctet", "6 -> 6 8", SextetSextetOctet); static SwitchOption interfaceColourStructureChargedChargedNeutral (interfaceColourStructure, "ChargedChargedNeutral", "q -> q 0", ChargedChargedNeutral); static SwitchOption interfaceColourStructureNeutralChargedCharged (interfaceColourStructure, "NeutralChargedCharged", "0 -> q qbar", NeutralChargedCharged); static SwitchOption interfaceColourStructureChargedNeutralCharged (interfaceColourStructure, "ChargedNeutralCharged", "q -> 0 q", ChargedNeutralCharged); static Switch interfaceInteractionType ("InteractionType", "Type of the interaction", &SplittingFunction::_interactionType, ShowerInteraction::UNDEFINED, false, false); static SwitchOption interfaceInteractionTypeQCD (interfaceInteractionType, "QCD","QCD",ShowerInteraction::QCD); static SwitchOption interfaceInteractionTypeQED (interfaceInteractionType, "QED","QED",ShowerInteraction::QED); + static SwitchOption interfaceInteractionTypeEW + (interfaceInteractionType, + "EW","EW",ShowerInteraction::EW); static Switch interfaceAngularOrdered ("AngularOrdered", "Whether or not this interaction is angular ordered, " "normally only g->q qbar and gamma-> f fbar are the only ones which aren't.", &SplittingFunction::angularOrdered_, true, false, false); static SwitchOption interfaceAngularOrderedYes (interfaceAngularOrdered, "Yes", "Interaction is angular ordered", true); static SwitchOption interfaceAngularOrderedNo (interfaceAngularOrdered, "No", "Interaction isn't angular ordered", false); } void SplittingFunction::persistentOutput(PersistentOStream & os) const { using namespace ShowerInteraction; os << oenum(_interactionType) << _interactionOrder << oenum(_colourStructure) << _colourFactor << angularOrdered_; } void SplittingFunction::persistentInput(PersistentIStream & is, int) { using namespace ShowerInteraction; is >> ienum(_interactionType) >> _interactionOrder >> ienum(_colourStructure) >> _colourFactor >> angularOrdered_; } void SplittingFunction::colourConnection(tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second, ShowerPartnerType::Type partnerType, const bool back) const { if(_colourStructure==TripletTripletOctet) { if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency assert(( cparent.first && !cparent.second && partnerType==ShowerPartnerType::QCDColourLine) || ( !cparent.first && cparent.second && partnerType==ShowerPartnerType::QCDAntiColourLine)); // q -> q g if(cparent.first) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); newline->addColoured ( first); newline->addAntiColoured (second); } // qbar -> qbar g else { ColinePtr newline=new_ptr(ColourLine()); cparent.second->addAntiColoured(second); newline->addColoured(second); newline->addAntiColoured(first); } // Set progenitor first->progenitor(parent->progenitor()); second->progenitor(parent->progenitor()); } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency assert(( cfirst.first && !cfirst.second && partnerType==ShowerPartnerType::QCDColourLine) || ( !cfirst.first && cfirst.second && partnerType==ShowerPartnerType::QCDAntiColourLine)); // q -> q g if(cfirst.first) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addAntiColoured(second); newline->addColoured(second); newline->addColoured(parent); } // qbar -> qbar g else { ColinePtr newline=new_ptr(ColourLine()); cfirst.second->addColoured(second); newline->addAntiColoured(second); newline->addAntiColoured(parent); } // Set progenitor parent->progenitor(first->progenitor()); second->progenitor(first->progenitor()); } } else if(_colourStructure==OctetOctetOctet) { if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency assert(cparent.first&&cparent.second); // ensure first gluon is hardest if( first->id()==second->id() && parent->showerKinematics()->z()<0.5 ) swap(first,second); // colour line radiates if(partnerType==ShowerPartnerType::QCDColourLine) { // The colour line is radiating ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); cparent.second->addAntiColoured(first); newline->addColoured(first); newline->addAntiColoured(second); } // anti colour line radiates else if(partnerType==ShowerPartnerType::QCDAntiColourLine) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); cparent.second->addAntiColoured(second); newline->addColoured(second); newline->addAntiColoured(first); } else assert(false); } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency assert(cfirst.first&&cfirst.second); // The colour line is radiating if(partnerType==ShowerPartnerType::QCDColourLine) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addAntiColoured(second); cfirst.second->addAntiColoured(parent); newline->addColoured(parent); newline->addColoured(second); } // anti colour line radiates else if(partnerType==ShowerPartnerType::QCDAntiColourLine) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addColoured(parent); cfirst.second->addColoured(second); newline->addAntiColoured(second); newline->addAntiColoured(parent); } else assert(false); } } else if(_colourStructure == OctetTripletTriplet) { if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency assert(cparent.first&&cparent.second); cparent.first ->addColoured ( first); cparent.second->addAntiColoured(second); // Set progenitor first->progenitor(parent->progenitor()); second->progenitor(parent->progenitor()); } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency assert(( cfirst.first && !cfirst.second) || (!cfirst.first && cfirst.second)); // g -> q qbar if(cfirst.first) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addColoured(parent); newline->addAntiColoured(second); newline->addAntiColoured(parent); } // g -> qbar q else { ColinePtr newline=new_ptr(ColourLine()); cfirst.second->addAntiColoured(parent); newline->addColoured(second); newline->addColoured(parent); } // Set progenitor parent->progenitor(first->progenitor()); second->progenitor(first->progenitor()); } } else if(_colourStructure == TripletOctetTriplet) { if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency assert(( cparent.first && !cparent.second) || (!cparent.first && cparent.second)); // q -> g q if(cparent.first) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); newline->addColoured (second); newline->addAntiColoured( first); } // qbar -> g qbar else { ColinePtr newline=new_ptr(ColourLine()); cparent.second->addAntiColoured(first); newline->addColoured ( first); newline->addAntiColoured(second); } // Set progenitor first->progenitor(parent->progenitor()); second->progenitor(parent->progenitor()); } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency assert(cfirst.first&&cfirst.second); // q -> g q if(parent->id()>0) { cfirst.first ->addColoured(parent); cfirst.second->addColoured(second); } else { cfirst.first ->addAntiColoured(second); cfirst.second->addAntiColoured(parent); } // Set progenitor parent->progenitor(first->progenitor()); second->progenitor(first->progenitor()); } } else if(_colourStructure==SextetSextetOctet) { //make sure we're not doing backward evolution assert(!back); //make sure something sensible assert(parent->colourLine() || parent->antiColourLine()); //get the colour lines or anti-colour lines bool isAntiColour=true; ColinePair cparent; if(parent->colourLine()) { cparent = ColinePair(const_ptr_cast(parent->colourInfo()->colourLines()[0]), const_ptr_cast(parent->colourInfo()->colourLines()[1])); isAntiColour=false; } else { cparent = ColinePair(const_ptr_cast(parent->colourInfo()->antiColourLines()[0]), const_ptr_cast(parent->colourInfo()->antiColourLines()[1])); } //check for sensible input // assert(cparent.first && cparent.second); // sextet has 2 colour lines if(!isAntiColour) { //pick at random which of the colour topolgies to take double topology = UseRandom::rnd(); if(topology < 0.25) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); cparent.second->addColoured(first); newline->addColoured(first); newline->addAntiColoured(second); } else if(topology >=0.25 && topology < 0.5) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); cparent.second->addColoured(second); newline->addColoured(first); newline->addAntiColoured(second); } else if(topology >= 0.5 && topology < 0.75) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); cparent.second->addColoured(first); newline->addColoured(first); newline->addAntiColoured(second); } else { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); cparent.second->addColoured(second); newline->addColoured(first); newline->addAntiColoured(second); } } // sextet has 2 anti-colour lines else { double topology = UseRandom::rnd(); if(topology < 0.25){ ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(second); cparent.second->addAntiColoured(first); newline->addAntiColoured(first); newline->addColoured(second); } else if(topology >=0.25 && topology < 0.5) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(first); cparent.second->addAntiColoured(second); newline->addAntiColoured(first); newline->addColoured(second); } else if(topology >= 0.5 && topology < 0.75) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(second); cparent.second->addAntiColoured(first); newline->addAntiColoured(first); newline->addColoured(second); } else { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(first); cparent.second->addAntiColoured(second); newline->addAntiColoured(first); newline->addColoured(second); } } } else if(_colourStructure == ChargedChargedNeutral) { if(!parent->data().coloured()) return; if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // q -> q g if(cparent.first) { cparent.first->addColoured(first); } // qbar -> qbar g if(cparent.second) { cparent.second->addAntiColoured(first); } } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // q -> q g if(cfirst.first) { cfirst.first->addColoured(parent); } // qbar -> qbar g if(cfirst.second) { cfirst.second->addAntiColoured(parent); } } } else if(_colourStructure == ChargedNeutralCharged) { if(!parent->data().coloured()) return; if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // q -> q g if(cparent.first) { cparent.first->addColoured(second); } // qbar -> qbar g if(cparent.second) { cparent.second->addAntiColoured(second); } } else { if (second->dataPtr()->iColour()==PDT::Colour3 ) { ColinePtr newline=new_ptr(ColourLine()); newline->addColoured(second); newline->addColoured(parent); } else if (second->dataPtr()->iColour()==PDT::Colour3bar ) { ColinePtr newline=new_ptr(ColourLine()); newline->addAntiColoured(second); newline->addAntiColoured(parent); } } } else if(_colourStructure == NeutralChargedCharged ) { if(!back) { if(first->dataPtr()->coloured()) { ColinePtr newline=new_ptr(ColourLine()); if(first->dataPtr()->iColour()==PDT::Colour3) { newline->addColoured (first ); newline->addAntiColoured(second); } else if (first->dataPtr()->iColour()==PDT::Colour3bar) { newline->addColoured (second); newline->addAntiColoured(first ); } else assert(false); } } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // gamma -> q qbar if(cfirst.first) { cfirst.first->addAntiColoured(second); } // gamma -> qbar q else if(cfirst.second) { cfirst.second->addColoured(second); } else assert(false); } } else { assert(false); } } void SplittingFunction::doinit() { Interfaced::doinit(); assert(_interactionType!=ShowerInteraction::UNDEFINED); assert((_colourStructure>0&&_interactionType==ShowerInteraction::QCD) || - (_colourStructure<0&&_interactionType==ShowerInteraction::QED) ); + (_colourStructure<0&&(_interactionType==ShowerInteraction::QED || + _interactionType==ShowerInteraction::EW)) ); if(_colourFactor>0.) return; // compute the colour factors if need if(_colourStructure==TripletTripletOctet) { _colourFactor = 4./3.; } else if(_colourStructure==OctetOctetOctet) { _colourFactor = 3.; } else if(_colourStructure==OctetTripletTriplet) { _colourFactor = 0.5; } else if(_colourStructure==TripletOctetTriplet) { _colourFactor = 4./3.; } else if(_colourStructure==SextetSextetOctet) { _colourFactor = 10./3.; } else if(_colourStructure<0) { _colourFactor = 1.; } else { assert(false); } } bool SplittingFunction::checkColours(const IdList & ids) const { tcPDPtr pd[3]={getParticleData(ids[0]), getParticleData(ids[1]), getParticleData(ids[2])}; if(_colourStructure==TripletTripletOctet) { if(ids[0]!=ids[1]) return false; if((pd[0]->iColour()==PDT::Colour3||pd[0]->iColour()==PDT::Colour3bar) && pd[2]->iColour()==PDT::Colour8) return true; return false; } else if(_colourStructure==OctetOctetOctet) { for(unsigned int ix=0;ix<3;++ix) { if(pd[ix]->iColour()!=PDT::Colour8) return false; } return true; } else if(_colourStructure==OctetTripletTriplet) { if(pd[0]->iColour()!=PDT::Colour8) return false; if(pd[1]->iColour()==PDT::Colour3&&pd[2]->iColour()==PDT::Colour3bar) return true; if(pd[1]->iColour()==PDT::Colour3bar&&pd[2]->iColour()==PDT::Colour3) return true; return false; } else if(_colourStructure==TripletOctetTriplet) { if(ids[0]!=ids[2]) return false; if((pd[0]->iColour()==PDT::Colour3||pd[0]->iColour()==PDT::Colour3bar) && pd[1]->iColour()==PDT::Colour8) return true; return false; } else if(_colourStructure==SextetSextetOctet) { if(ids[0]!=ids[1]) return false; if((pd[0]->iColour()==PDT::Colour6 || pd[0]->iColour()==PDT::Colour6bar) && pd[2]->iColour()==PDT::Colour8) return true; return false; } else if(_colourStructure==ChargedChargedNeutral) { if(ids[0]!=ids[1]) return false; if(pd[2]->iCharge()!=0) return false; if(pd[0]->iCharge()==pd[1]->iCharge()) return true; return false; } else if(_colourStructure==ChargedNeutralCharged) { if(ids[0]!=ids[2]) return false; if(pd[1]->iCharge()!=0) return false; if(pd[0]->iCharge()==pd[2]->iCharge()) return true; return false; } else if(_colourStructure==NeutralChargedCharged) { if(ids[1]!=-ids[2]) return false; if(pd[0]->iCharge()!=0) return false; if(pd[1]->iCharge()==-pd[2]->iCharge()) return true; return false; } else { assert(false); } return false; } namespace { bool hasColour(tPPtr p) { PDT::Colour colour = p->dataPtr()->iColour(); return colour==PDT::Colour3 || colour==PDT::Colour8 || colour == PDT::Colour6; } bool hasAntiColour(tPPtr p) { PDT::Colour colour = p->dataPtr()->iColour(); return colour==PDT::Colour3bar || colour==PDT::Colour8 || colour == PDT::Colour6bar; } } void SplittingFunction::evaluateFinalStateScales(ShowerPartnerType::Type partnerType, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr emitter, tShowerParticlePtr emitted) { // identify emitter and emitted double zEmitter = z, zEmitted = 1.-z; bool bosonSplitting(false); // special for g -> gg, particle highest z is emitter if(emitter->id() == emitted->id() && emitter->id() == parent->id() && zEmitted > zEmitter) { swap(zEmitted,zEmitter); swap( emitted, emitter); } // otherwise if particle ID same else if(emitted->id()==parent->id()) { swap(zEmitted,zEmitter); swap( emitted, emitter); } // no real emitter/emitted else if(emitter->id()!=parent->id()) { bosonSplitting = true; } // may need to add angularOrder flag here // now the various scales // QED if(partnerType==ShowerPartnerType::QED) { assert(colourStructure()==ChargedChargedNeutral || colourStructure()==ChargedNeutralCharged || colourStructure()==NeutralChargedCharged ); // normal case if(!bosonSplitting) { assert(colourStructure()==ChargedChargedNeutral || colourStructure()==ChargedNeutralCharged ); // set the scales // emitter emitter->scales().QED = zEmitter*scale; emitter->scales().QED_noAO = scale; emitter->scales().QCD_c = min(scale,parent->scales().QCD_c ); emitter->scales().QCD_c_noAO = min(scale,parent->scales().QCD_c_noAO ); emitter->scales().QCD_ac = min(scale,parent->scales().QCD_ac ); emitter->scales().QCD_ac_noAO = min(scale,parent->scales().QCD_ac_noAO); // emitted emitted->scales().QED = zEmitted*scale; emitted->scales().QED_noAO = scale; emitted->scales().QCD_c = ZERO; emitted->scales().QCD_c_noAO = ZERO; emitted->scales().QCD_ac = ZERO; emitted->scales().QCD_ac_noAO = ZERO; } // gamma -> f fbar else { assert(colourStructure()==NeutralChargedCharged ); // emitter emitter->scales().QED = zEmitter*scale; emitter->scales().QED_noAO = scale; if(hasColour(emitter)) { emitter->scales().QCD_c = zEmitter*scale; emitter->scales().QCD_c_noAO = scale; } if(hasAntiColour(emitter)) { emitter->scales().QCD_ac = zEmitter*scale; emitter->scales().QCD_ac_noAO = scale; } // emitted emitted->scales().QED = zEmitted*scale; emitted->scales().QED_noAO = scale; if(hasColour(emitted)) { emitted->scales().QCD_c = zEmitted*scale; emitted->scales().QCD_c_noAO = scale; } if(hasAntiColour(emitted)) { emitted->scales().QCD_ac = zEmitted*scale; emitted->scales().QCD_ac_noAO = scale; } } } // QCD - else { + else if (partnerType==ShowerPartnerType::QCDColourLine || + partnerType==ShowerPartnerType::QCDAntiColourLine) { // normal case eg q -> q g and g -> g g if(!bosonSplitting) { emitter->scales().QED = min(scale,parent->scales().QED ); emitter->scales().QED_noAO = min(scale,parent->scales().QED_noAO); if(partnerType==ShowerPartnerType::QCDColourLine) { emitter->scales().QCD_c = zEmitter*scale; emitter->scales().QCD_c_noAO = scale; emitter->scales().QCD_ac = min(zEmitter*scale,parent->scales().QCD_ac ); emitter->scales().QCD_ac_noAO = min( scale,parent->scales().QCD_ac_noAO); } else { emitter->scales().QCD_c = min(zEmitter*scale,parent->scales().QCD_c ); emitter->scales().QCD_c_noAO = min( scale,parent->scales().QCD_c_noAO ); emitter->scales().QCD_ac = zEmitter*scale; emitter->scales().QCD_ac_noAO = scale; } // emitted emitted->scales().QED = ZERO; emitted->scales().QED_noAO = ZERO; emitted->scales().QCD_c = zEmitted*scale; emitted->scales().QCD_c_noAO = scale; emitted->scales().QCD_ac = zEmitted*scale; emitted->scales().QCD_ac_noAO = scale; } // g -> q qbar else { // emitter if(emitter->dataPtr()->charged()) { emitter->scales().QED = zEmitter*scale; emitter->scales().QED_noAO = scale; } emitter->scales().QCD_c = zEmitter*scale; emitter->scales().QCD_c_noAO = scale; emitter->scales().QCD_ac = zEmitter*scale; emitter->scales().QCD_ac_noAO = scale; // emitted if(emitted->dataPtr()->charged()) { emitted->scales().QED = zEmitted*scale; emitted->scales().QED_noAO = scale; } emitted->scales().QCD_c = zEmitted*scale; emitted->scales().QCD_c_noAO = scale; emitted->scales().QCD_ac = zEmitted*scale; emitted->scales().QCD_ac_noAO = scale; } } + else + assert(false); } void SplittingFunction::evaluateInitialStateScales(ShowerPartnerType::Type partnerType, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr spacelike, tShowerParticlePtr timelike) { // scale for time-like child Energy AOScale = (1.-z)*scale; // QED if(partnerType==ShowerPartnerType::QED) { if(parent->id()==spacelike->id()) { // parent parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; parent ->scales().QCD_c = min(scale,spacelike->scales().QCD_c ); parent ->scales().QCD_c_noAO = min(scale,spacelike->scales().QCD_c_noAO ); parent ->scales().QCD_ac = min(scale,spacelike->scales().QCD_ac ); parent ->scales().QCD_ac_noAO = min(scale,spacelike->scales().QCD_ac_noAO); // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; timelike->scales().QCD_c = ZERO; timelike->scales().QCD_c_noAO = ZERO; timelike->scales().QCD_ac = ZERO; timelike->scales().QCD_ac_noAO = ZERO; } else if(parent->id()==timelike->id()) { parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; if(hasColour(parent)) { parent ->scales().QCD_c = scale; parent ->scales().QCD_c_noAO = scale; } if(hasAntiColour(parent)) { parent ->scales().QCD_ac = scale; parent ->scales().QCD_ac_noAO = scale; } // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; if(hasColour(timelike)) { timelike->scales().QCD_c = AOScale; timelike->scales().QCD_c_noAO = scale; } if(hasAntiColour(timelike)) { timelike->scales().QCD_ac = AOScale; timelike->scales().QCD_ac_noAO = scale; } } else { parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; parent ->scales().QCD_c = ZERO ; parent ->scales().QCD_c_noAO = ZERO ; parent ->scales().QCD_ac = ZERO ; parent ->scales().QCD_ac_noAO = ZERO ; // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; if(hasColour(timelike)) { timelike->scales().QCD_c = min(AOScale,spacelike->scales().QCD_ac ); timelike->scales().QCD_c_noAO = min( scale,spacelike->scales().QCD_ac_noAO); } if(hasAntiColour(timelike)) { timelike->scales().QCD_ac = min(AOScale,spacelike->scales().QCD_c ); timelike->scales().QCD_ac_noAO = min( scale,spacelike->scales().QCD_c_noAO ); } } } // QCD - else { + else if (partnerType==ShowerPartnerType::QCDColourLine || + partnerType==ShowerPartnerType::QCDAntiColourLine) { // timelike if(timelike->dataPtr()->charged()) { timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; } if(hasColour(timelike)) { timelike->scales().QCD_c = AOScale; timelike->scales().QCD_c_noAO = scale; } if(hasAntiColour(timelike)) { timelike->scales().QCD_ac = AOScale; timelike->scales().QCD_ac_noAO = scale; } if(parent->id()==spacelike->id()) { parent ->scales().QED = min(scale,spacelike->scales().QED ); parent ->scales().QED_noAO = min(scale,spacelike->scales().QED_noAO ); parent ->scales().QCD_c = min(scale,spacelike->scales().QCD_c ); parent ->scales().QCD_c_noAO = min(scale,spacelike->scales().QCD_c_noAO ); parent ->scales().QCD_ac = min(scale,spacelike->scales().QCD_ac ); parent ->scales().QCD_ac_noAO = min(scale,spacelike->scales().QCD_ac_noAO); } else { if(parent->dataPtr()->charged()) { parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; } if(hasColour(parent)) { parent ->scales().QCD_c = scale; parent ->scales().QCD_c_noAO = scale; } if(hasAntiColour(parent)) { parent ->scales().QCD_ac = scale; parent ->scales().QCD_ac_noAO = scale; } } } + else + assert(false); } void SplittingFunction::evaluateDecayScales(ShowerPartnerType::Type partnerType, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr spacelike, tShowerParticlePtr timelike) { assert(parent->id()==spacelike->id()); // angular-ordered scale for 2nd child Energy AOScale = (1.-z)*scale; // QED if(partnerType==ShowerPartnerType::QED) { // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; timelike->scales().QCD_c = ZERO; timelike->scales().QCD_c_noAO = ZERO; timelike->scales().QCD_ac = ZERO; timelike->scales().QCD_ac_noAO = ZERO; // spacelike spacelike->scales().QED = scale; spacelike->scales().QED_noAO = scale; } // QCD - else { + else if(partnerType==ShowerPartnerType::QCDColourLine || + partnerType==ShowerPartnerType::QCDAntiColourLine) { // timelike timelike->scales().QED = ZERO; timelike->scales().QED_noAO = ZERO; timelike->scales().QCD_c = AOScale; timelike->scales().QCD_c_noAO = scale; timelike->scales().QCD_ac = AOScale; timelike->scales().QCD_ac_noAO = scale; // spacelike spacelike->scales().QED = max(scale,parent->scales().QED ); spacelike->scales().QED_noAO = max(scale,parent->scales().QED_noAO ); } + else + assert(false); spacelike->scales().QCD_c = max(scale,parent->scales().QCD_c ); spacelike->scales().QCD_c_noAO = max(scale,parent->scales().QCD_c_noAO ); spacelike->scales().QCD_ac = max(scale,parent->scales().QCD_ac ); spacelike->scales().QCD_ac_noAO = max(scale,parent->scales().QCD_ac_noAO); } diff --git a/Shower/SplittingFunctions/SplittingFunction.h b/Shower/SplittingFunctions/SplittingFunction.h --- a/Shower/SplittingFunctions/SplittingFunction.h +++ b/Shower/SplittingFunctions/SplittingFunction.h @@ -1,371 +1,372 @@ // -*- C++ -*- // // SplittingFunction.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2011 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_SplittingFunction_H #define HERWIG_SplittingFunction_H // // This is the declaration of the SplittingFunction class. // #include "ThePEG/Interface/Interfaced.h" #include "Herwig/Shower/ShowerConfig.h" #include "ThePEG/EventRecord/RhoDMatrix.h" #include "Herwig/Decay/DecayMatrixElement.h" #include "Herwig/Shower/Base/ShowerKinematics.fh" #include "ThePEG/EventRecord/ColourLine.h" #include "ThePEG/PDT/ParticleData.h" #include "SplittingFunction.fh" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * Enum to define the possible types of colour structure which can occur in * the branching. */ enum ColourStructure {Undefined=0, TripletTripletOctet = 1,OctetOctetOctet =2, OctetTripletTriplet = 3,TripletOctetTriplet=4, SextetSextetOctet = 5, ChargedChargedNeutral=-1,ChargedNeutralCharged=-2, NeutralChargedCharged=-3}; /** \ingroup Shower * * This is an abstract class which defines the common interface * for all \f$1\to2\f$ splitting functions, for both initial-state * and final-state radiation. * * The SplittingFunction class contains a number of purely virtual members * which must be implemented in the inheriting classes. The class also stores * the interaction type of the spltting function. * * The inheriting classes need to specific the splitting function * \f$P(z,2p_j\cdot p_k)\f$, in terms of the energy fraction \f$z\f$ and * the evolution scale. In order to allow the splitting functions to be used * with different choices of evolution functions the scale is given by * \f[2p_j\cdot p_k=(p_j+p_k)^2-m_{jk}^2=Q^2-(p_j+p_k)^2=z(1-z)\tilde{q}^2= * \frac{p_T^2}{z(1-z)}-m_{jk}^2+\frac{m_j^2}{z}+\frac{m_k^2}{1-z},\f] * where \f$Q^2\f$ is the virtuality of the branching particle, * $p_T$ is the relative transverse momentum of the branching products and * \f$\tilde{q}^2\f$ is the angular variable described in hep-ph/0310083. * * In addition an overestimate of the * splitting function, \f$P_{\rm over}(z)\f$ which only depends upon \f$z\f$, * the integral, inverse of the integral for this overestimate and * ratio of the true splitting function to the overestimate must be provided * as they are necessary for the veto alogrithm used to implement the evolution. * * @see \ref SplittingFunctionInterfaces "The interfaces" * defined for SplittingFunction. */ class SplittingFunction: public Interfaced { public: /** * The default constructor. * @param b All splitting functions must have an interaction order */ SplittingFunction(unsigned int b) : Interfaced(), _interactionType(ShowerInteraction::UNDEFINED), _interactionOrder(b), _colourStructure(Undefined), _colourFactor(-1.), angularOrdered_(true) {} + public: /** * Methods to return the interaction type and order for the splitting function */ //@{ /** * Return the type of the interaction */ ShowerInteraction::Type interactionType() const {return _interactionType;} /** * Return the order of the splitting function in the interaction */ unsigned int interactionOrder() const {return _interactionOrder;} /** * Return the colour structure */ ColourStructure colourStructure() const {return _colourStructure;} /** * Return the colour factor */ double colourFactor(const IdList &ids) const { if(_colourStructure>0) return _colourFactor; else if(_colourStructure<0) { if(_colourStructure==ChargedChargedNeutral || _colourStructure==ChargedNeutralCharged) { tPDPtr part=getParticleData(ids[0]); return sqr(double(part->iCharge())/3.); } else { tPDPtr part=getParticleData(ids[1]); return sqr(double(part->iCharge())/3.); } } else assert(false); } //@} /** * Purely virtual method which should determine whether this splitting * function can be used for a given set of particles. * @param ids The PDG codes for the particles in the splitting. */ virtual bool accept(const IdList & ids) const = 0; /** * Method to check the colours are correct */ virtual bool checkColours(const IdList & ids) const; /** * Methods to return the splitting function. */ //@{ /** * Purely virtual method which should return the exact value of the splitting function, * \f$P\f$ evaluated in terms of the energy fraction, \f$z\f$, and the evolution scale \f$\tilde{q}^2\f$. * @param z The energy fraction. * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms */ virtual double P(const double z, const Energy2 t, const IdList & ids, const bool mass) const = 0; /** * Purely virtual method which should return * an overestimate of the splitting function, * \f$P_{\rm over}\f$ such that the result \f$P_{\rm over}\geq P\f$. This function * should be simple enough that it does not depend on the evolution scale. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. */ virtual double overestimateP(const double z, const IdList & ids) const = 0; /** * Purely virtual method which should return * the ratio of the splitting function to the overestimate, i.e. * \f$P(z,\tilde{q}^2)/P_{\rm over}(z)\f$. * @param z The energy fraction. * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass) const = 0; /** * Purely virtual method which should return the indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ * */ virtual double integOverP(const double z, const IdList & ids, unsigned int PDFfactor=0) const = 0; /** * Purely virtual method which should return the inverse of the * indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$ which is used to * generate the value of \f$z\f$. * @param r Value of the splitting function to be inverted * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor=0) const = 0; //@} /** * Purely virtual method which should make the proper colour connection * between the emitting parent and the branching products. * @param parent The parent for the branching * @param first The first branching product * @param second The second branching product * @param partnerType The type of evolution partner * @param back Whether this is foward or backward evolution. */ virtual void colourConnection(tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second, ShowerPartnerType::Type partnerType, const bool back) const; /** * Method to calculate the azimuthal angle for forward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &) = 0; /** * Method to calculate the azimuthal angle for backward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @return The weight */ virtual vector > generatePhiBackward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &) = 0; /** * Calculate the matrix element for the splitting * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param phi The azimuthal angle, \f$\phi\f$. * @param timeLike Whether timelike or spacelike, affects inclusive of mass terms */ virtual DecayMEPtr matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike) = 0; /** * Whether or not the interaction is angular ordered */ bool angularOrdered() const {return angularOrdered_;} /** * Functions to state scales after branching happens */ //@{ /** * Sort out scales for final-state emission */ void evaluateFinalStateScales(ShowerPartnerType::Type type, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second); /** * Sort out scales for initial-state emission */ void evaluateInitialStateScales(ShowerPartnerType::Type type, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second); /** * Sort out scales for decay emission */ void evaluateDecayScales(ShowerPartnerType::Type type, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second); //@} public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); //@} protected: /** * Set the colour factor */ void colourFactor(double in) {_colourFactor=in;} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ SplittingFunction & operator=(const SplittingFunction &); private: /** * The interaction type for the splitting function. */ ShowerInteraction::Type _interactionType; /** * The order of the splitting function in the coupling */ unsigned int _interactionOrder; /** * The colour structure */ ColourStructure _colourStructure; /** * The colour factor */ double _colourFactor; /** * Whether or not this interaction is angular-ordered */ bool angularOrdered_; }; } #endif /* HERWIG_SplittingFunction_H */ diff --git a/Shower/SplittingFunctions/SplittingGenerator.cc b/Shower/SplittingFunctions/SplittingGenerator.cc --- a/Shower/SplittingFunctions/SplittingGenerator.cc +++ b/Shower/SplittingFunctions/SplittingGenerator.cc @@ -1,577 +1,616 @@ // -*- C++ -*- // // SplittingGenerator.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2011 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the SplittingGenerator class. // #include "SplittingGenerator.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Command.h" #include "ThePEG/Utilities/StringUtils.h" #include "ThePEG/Repository/Repository.h" #include "Herwig/Shower/Base/ShowerParticle.h" #include "ThePEG/Utilities/Rebinder.h" #include #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; +namespace { + +bool checkInteraction(ShowerInteraction::Type allowed, + ShowerInteraction::Type splitting) { + if(allowed==ShowerInteraction::ALL) + return true; + else if(allowed==ShowerInteraction::QEDQCD && + (splitting==ShowerInteraction::QED || + splitting==ShowerInteraction::QCD )) + return true; + else if(allowed == splitting) + return true; + else + return false; +} + +} + DescribeClass describeSplittingGenerator ("Herwig::SplittingGenerator",""); IBPtr SplittingGenerator::clone() const { return new_ptr(*this); } IBPtr SplittingGenerator::fullclone() const { return new_ptr(*this); } - void SplittingGenerator::persistentOutput(PersistentOStream & os) const { os << _isr_Mode << _fsr_Mode << _bbranchings << _fbranchings; } void SplittingGenerator::persistentInput(PersistentIStream & is, int) { is >> _isr_Mode >> _fsr_Mode >> _bbranchings >> _fbranchings; } void SplittingGenerator::Init() { static ClassDocumentation documentation ("There class is responsible for initializing the Sudakov form factors ", "and generating splittings."); static Switch interfaceISRMode ("ISR", "Include initial-state radiation?", &SplittingGenerator::_isr_Mode, 1, false, false); static SwitchOption interfaceISRMode0 (interfaceISRMode,"No","ISR (Initial State Radiation) is OFF", 0); static SwitchOption interfaceISRMode1 (interfaceISRMode,"Yes","ISR (Initial State Radiation) is ON", 1); static Switch interfaceFSRMode ("FSR", "Include final-state radiation?", &SplittingGenerator::_fsr_Mode, 1, false, false); static SwitchOption interfaceFSRMode0 (interfaceFSRMode,"No","FSR (Final State Radiation) is OFF", 0); static SwitchOption interfaceFSRMode1 (interfaceFSRMode,"Yes","FSR (Final State Radiation) is ON", 1); static Command interfaceAddSplitting ("AddFinalSplitting", "Adds another splitting to the list of splittings considered " "in the shower. Command is a->b,c; Sudakov", &SplittingGenerator::addFinalSplitting); static Command interfaceAddInitialSplitting ("AddInitialSplitting", "Adds another splitting to the list of initial splittings to consider " "in the shower. Command is a->b,c; Sudakov. Here the particle a is the " "particle that is PRODUCED by the splitting. b is the initial state " "particle that is splitting in the shower.", &SplittingGenerator::addInitialSplitting); static Command interfaceDeleteSplitting ("DeleteFinalSplitting", "Deletes a splitting from the list of splittings considered " "in the shower. Command is a->b,c; Sudakov", &SplittingGenerator::deleteFinalSplitting); static Command interfaceDeleteInitialSplitting ("DeleteInitialSplitting", "Deletes a splitting from the list of initial splittings to consider " "in the shower. Command is a->b,c; Sudakov. Here the particle a is the " "particle that is PRODUCED by the splitting. b is the initial state " "particle that is splitting in the shower.", &SplittingGenerator::deleteInitialSplitting); } string SplittingGenerator::addSplitting(string arg, bool final) { string partons = StringUtils::car(arg); string sudakov = StringUtils::cdr(arg); vector products; string::size_type next = partons.find("->"); if(next == string::npos) return "Error: Invalid string for splitting " + arg; if(partons.find(';') == string::npos) return "Error: Invalid string for splitting " + arg; tPDPtr parent = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+2); do { next = min(partons.find(','), partons.find(';')); tPDPtr pdp = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+1); if(pdp) products.push_back(pdp); else return "Error: Could not create splitting from " + arg; } while(partons[0] != ';' && partons.size()); SudakovPtr s; s = dynamic_ptr_cast(Repository::TraceObject(sudakov)); if(!s) return "Error: Could not load Sudakov " + sudakov + '\n'; IdList ids; ids.push_back(parent->id()); for(vector::iterator it = products.begin(); it!=products.end(); ++it) ids.push_back((*it)->id()); // check splitting can handle this if(!s->splittingFn()->accept(ids)) return "Error: Sudakov " + sudakov + "can't handle particles\n"; // add to map addToMap(ids,s,final); return ""; } string SplittingGenerator::deleteSplitting(string arg, bool final) { string partons = StringUtils::car(arg); string sudakov = StringUtils::cdr(arg); vector products; string::size_type next = partons.find("->"); if(next == string::npos) return "Error: Invalid string for splitting " + arg; if(partons.find(';') == string::npos) return "Error: Invalid string for splitting " + arg; tPDPtr parent = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+2); do { next = min(partons.find(','), partons.find(';')); tPDPtr pdp = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+1); if(pdp) products.push_back(pdp); else return "Error: Could not create splitting from " + arg; } while(partons[0] != ';' && partons.size()); SudakovPtr s; s = dynamic_ptr_cast(Repository::TraceObject(sudakov)); if(!s) return "Error: Could not load Sudakov " + sudakov + '\n'; IdList ids; ids.push_back(parent->id()); for(vector::iterator it = products.begin(); it!=products.end(); ++it) ids.push_back((*it)->id()); // check splitting can handle this if(!s->splittingFn()->accept(ids)) return "Error: Sudakov " + sudakov + "can't handle particles\n"; // delete from map deleteFromMap(ids,s,final); return ""; } void SplittingGenerator::addToMap(const IdList &ids, const SudakovPtr &s, bool final) { if(isISRadiationON() && !final) { _bbranchings.insert(BranchingInsert(ids[1],BranchingElement(s,ids))); s->addSplitting(ids); } if(isFSRadiationON() && final) { _fbranchings.insert(BranchingInsert(ids[0],BranchingElement(s,ids))); s->addSplitting(ids); } } void SplittingGenerator::deleteFromMap(const IdList &ids, const SudakovPtr &s, bool final) { if(isISRadiationON() && !final) { pair range = _bbranchings.equal_range(ids[1]); for(BranchingList::iterator it=range.first; it!=range.second&&it!=_bbranchings.end()&&it->first==ids[1];++it) { if(it->second.first==s&&it->second.second==ids) { BranchingList::iterator it2=it; --it; _bbranchings.erase(it2); } } s->removeSplitting(ids); } if(isFSRadiationON() && final) { pair range = _fbranchings.equal_range(ids[0]); for(BranchingList::iterator it=range.first; it!=range.second&&it!=_fbranchings.end()&&it->first==ids[0];++it) { if(it->second.first==s&&it->second.second==ids) { BranchingList::iterator it2 = it; --it; _fbranchings.erase(it2); } } s->removeSplitting(ids); } } Branching SplittingGenerator::chooseForwardBranching(ShowerParticle &particle, double enhance, ShowerInteraction::Type type) const { Energy newQ = ZERO; ShoKinPtr kinematics = ShoKinPtr(); ShowerPartnerType::Type partnerType(ShowerPartnerType::Undefined); SudakovPtr sudakov = SudakovPtr(); IdList ids; // First, find the eventual branching, corresponding to the highest scale. long index = abs(particle.data().id()); // if no branchings return empty branching struct if( _fbranchings.find(index) == _fbranchings.end() ) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined); // otherwise select branching for(BranchingList::const_iterator cit = _fbranchings.lower_bound(index); cit != _fbranchings.upper_bound(index); ++cit) { // check either right interaction or doing both - if(type != cit->second.first->interactionType() && - type != ShowerInteraction::Both ) continue; + if(!checkInteraction(type,cit->second.first->interactionType())) continue; // whether or not this interaction should be angular ordered bool angularOrdered = cit->second.first->splittingFn()->angularOrdered(); ShoKinPtr newKin; ShowerPartnerType::Type type; // work out which starting scale we need if(cit->second.first->interactionType()==ShowerInteraction::QED) { type = ShowerPartnerType::QED; Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO; newKin = cit->second.first-> generateNextTimeBranching(startingScale,cit->second.second, particle.id()!=cit->first,enhance, particle.scales().Max_Q2); } else if(cit->second.first->interactionType()==ShowerInteraction::QCD) { // special for octets if(particle.dataPtr()->iColour()==PDT::Colour8) { // octet -> octet octet if(cit->second.first->splittingFn()->colourStructure()==OctetOctetOctet) { type = ShowerPartnerType::QCDColourLine; Energy startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; newKin= cit->second.first-> generateNextTimeBranching(startingScale,cit->second.second, particle.id()!=cit->first,0.5*enhance, particle.scales().Max_Q2); startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; ShoKinPtr newKin2 = cit->second.first-> generateNextTimeBranching(startingScale,cit->second.second, particle.id()!=cit->first,0.5*enhance, particle.scales().Max_Q2); // pick the one with the highest scale if( ( newKin && newKin2 && newKin2->scale() > newKin->scale()) || (!newKin && newKin2) ) { newKin = newKin2; type = ShowerPartnerType::QCDAntiColourLine; } } // other g -> q qbar else { Energy startingScale = angularOrdered ? max(particle.scales().QCD_c , particle.scales().QCD_ac ) : max(particle.scales().QCD_c_noAO, particle.scales().QCD_ac_noAO); newKin= cit->second.first-> generateNextTimeBranching(startingScale, cit->second.second, particle.id()!=cit->first,enhance, particle.scales().Max_Q2); type = UseRandom::rndbool() ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine; } } // everything else q-> qg etc else { Energy startingScale; if(particle.hasColour()) { type = ShowerPartnerType::QCDColourLine; startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; } else { type = ShowerPartnerType::QCDAntiColourLine; startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; } newKin= cit->second.first-> generateNextTimeBranching(startingScale,cit->second.second, particle.id()!=cit->first,enhance, particle.scales().Max_Q2); } } + else if(cit->second.first->interactionType()==ShowerInteraction::EW) { + type = ShowerPartnerType::EW; + Energy startingScale = particle.scales().EW; + newKin = cit->second.first-> + generateNextTimeBranching(startingScale,cit->second.second, + particle.id()!=cit->first,enhance, + particle.scales().Max_Q2); + } // shouldn't be anything else else assert(false); // if no kinematics contine if(!newKin) continue; // select highest scale if( newKin->scale() > newQ ) { kinematics = newKin; newQ = newKin->scale(); ids = cit->second.second; sudakov = cit->second.first; partnerType = type; } } // return empty branching if nothing happened if(!kinematics) return Branching(ShoKinPtr(), IdList(),SudakovPtr(), ShowerPartnerType::Undefined); // If a branching has been selected initialize it kinematics->initialize(particle,PPtr()); // and return it return Branching(kinematics, ids,sudakov,partnerType); } Branching SplittingGenerator:: chooseDecayBranching(ShowerParticle &particle, const ShowerParticle::EvolutionScales & stoppingScales, Energy minmass, double enhance, ShowerInteraction::Type interaction) const { Energy newQ = Constants::MaxEnergy; ShoKinPtr kinematics; SudakovPtr sudakov; ShowerPartnerType::Type partnerType(ShowerPartnerType::Undefined); IdList ids; // First, find the eventual branching, corresponding to the lowest scale. long index = abs(particle.data().id()); // if no branchings return empty branching struct if(_fbranchings.find(index) == _fbranchings.end()) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined); // otherwise select branching for(BranchingList::const_iterator cit = _fbranchings.lower_bound(index); cit != _fbranchings.upper_bound(index); ++cit) { // check interaction doesn't change flavour if(cit->second.second[1]!=index&&cit->second.second[2]!=index) continue; // check either right interaction or doing both - if(interaction != cit->second.first->interactionType() && - interaction != ShowerInteraction::Both ) continue; + if(!checkInteraction(interaction,cit->second.first->interactionType())) continue; // whether or not this interaction should be angular ordered bool angularOrdered = cit->second.first->splittingFn()->angularOrdered(); ShoKinPtr newKin; ShowerPartnerType::Type type; // work out which starting scale we need if(cit->second.first->interactionType()==ShowerInteraction::QED) { type = ShowerPartnerType::QED; Energy stoppingScale = angularOrdered ? stoppingScales.QED : stoppingScales.QED_noAO; Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO; if(startingScale < stoppingScale ) { newKin = cit->second.first-> generateNextDecayBranching(startingScale,stoppingScale,minmass,cit->second.second, particle.id()!=cit->first,enhance); } } else if(cit->second.first->interactionType()==ShowerInteraction::QCD) { // special for octets if(particle.dataPtr()->iColour()==PDT::Colour8) { // octet -> octet octet if(cit->second.first->splittingFn()->colourStructure()==OctetOctetOctet) { Energy stoppingColour = angularOrdered ? stoppingScales.QCD_c : stoppingScales.QCD_c_noAO; Energy stoppingAnti = angularOrdered ? stoppingScales.QCD_ac : stoppingScales.QCD_ac_noAO; Energy startingColour = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; Energy startingAnti = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; type = ShowerPartnerType::QCDColourLine; if(startingColoursecond.first-> generateNextDecayBranching(startingColour,stoppingColour,minmass, cit->second.second, particle.id()!=cit->first,0.5*enhance); } ShoKinPtr newKin2; if(startingAntisecond.first-> generateNextDecayBranching(startingAnti,stoppingAnti,minmass, cit->second.second, particle.id()!=cit->first,0.5*enhance); } // pick the one with the lowest scale if( (newKin&&newKin2&&newKin2->scale()scale()) || (!newKin&&newKin2) ) { newKin = newKin2; type = ShowerPartnerType::QCDAntiColourLine; } } // other else { assert(false); } } // everything else else { Energy startingScale,stoppingScale; if(particle.hasColour()) { type = ShowerPartnerType::QCDColourLine; stoppingScale = angularOrdered ? stoppingScales.QCD_c : stoppingScales.QCD_c_noAO; startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; } else { type = ShowerPartnerType::QCDAntiColourLine; stoppingScale = angularOrdered ? stoppingScales.QCD_ac : stoppingScales.QCD_ac_noAO; startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; } if(startingScale < stoppingScale ) { newKin = cit->second.first-> generateNextDecayBranching(startingScale,stoppingScale,minmass,cit->second.second, particle.id()!=cit->first,enhance); } } } + else if(cit->second.first->interactionType()==ShowerInteraction::EW) { + type = ShowerPartnerType::EW; + Energy stoppingScale = stoppingScales.EW; + Energy startingScale = particle.scales().EW; + if(startingScale < stoppingScale ) { + newKin = cit->second.first-> + generateNextDecayBranching(startingScale,stoppingScale,minmass,cit->second.second, + particle.id()!=cit->first,enhance); + } + } // shouldn't be anything else else assert(false); if(!newKin) continue; // select highest scale if(newKin->scale() < newQ ) { newQ = newKin->scale(); ids = cit->second.second; kinematics=newKin; sudakov=cit->second.first; partnerType = type; } } // return empty branching if nothing happened if(!kinematics) return Branching(ShoKinPtr(), IdList(),SudakovPtr(), ShowerPartnerType::Undefined); // initialize the branching kinematics->initialize(particle,PPtr()); // and generate phi kinematics->phi(sudakov->generatePhiDecay(particle,ids,kinematics)); // and return it return Branching(kinematics, ids,sudakov,partnerType); } Branching SplittingGenerator:: chooseBackwardBranching(ShowerParticle &particle,PPtr beamparticle, double enhance, Ptr::transient_const_pointer beam, ShowerInteraction::Type type, tcPDFPtr pdf, Energy freeze) const { Energy newQ=ZERO; ShoKinPtr kinematics=ShoKinPtr(); ShowerPartnerType::Type partnerType(ShowerPartnerType::Undefined); SudakovPtr sudakov; IdList ids; // First, find the eventual branching, corresponding to the highest scale. long index = abs(particle.id()); // if no possible branching return if(_bbranchings.find(index) == _bbranchings.end()) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined); // otherwise select branching for(BranchingList::const_iterator cit = _bbranchings.lower_bound(index); cit != _bbranchings.upper_bound(index); ++cit ) { // check either right interaction or doing both - if(type != cit->second.first->interactionType() && - type != ShowerInteraction::Both ) continue; + if(!checkInteraction(type,cit->second.first->interactionType())) continue; // setup the PDF cit->second.first->setPDF(pdf,freeze); // whether or not this interaction should be angular ordered bool angularOrdered = cit->second.first->splittingFn()->angularOrdered(); ShoKinPtr newKin; ShowerPartnerType::Type type; if(cit->second.first->interactionType()==ShowerInteraction::QED) { type = ShowerPartnerType::QED; Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO; newKin=cit->second.first-> generateNextSpaceBranching(startingScale,cit->second.second, particle.x(), particle.id()!=cit->first,enhance,beam); } else if(cit->second.first->interactionType()==ShowerInteraction::QCD) { // special for octets if(particle.dataPtr()->iColour()==PDT::Colour8) { // octet -> octet octet if(cit->second.first->splittingFn()->colourStructure()==OctetOctetOctet) { type = ShowerPartnerType::QCDColourLine; Energy startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; newKin = cit->second.first-> generateNextSpaceBranching(startingScale,cit->second.second, particle.x(), particle.id()!=cit->first,0.5*enhance,beam); startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; ShoKinPtr newKin2 = cit->second.first-> generateNextSpaceBranching(startingScale,cit->second.second, particle.x(), particle.id()!=cit->first,0.5*enhance,beam); // pick the one with the highest scale if( (newKin&&newKin2&&newKin2->scale()>newKin->scale()) || (!newKin&&newKin2) ) { newKin = newKin2; type = ShowerPartnerType::QCDAntiColourLine; } } else { Energy startingScale = angularOrdered ? max(particle.scales().QCD_c , particle.scales().QCD_ac ) : max(particle.scales().QCD_c_noAO, particle.scales().QCD_ac_noAO); type = UseRandom::rndbool() ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine; newKin=cit->second.first-> generateNextSpaceBranching(startingScale,cit->second.second, particle.x(), particle.id()!=cit->first,enhance,beam); } } // everything else else { Energy startingScale; if(particle.hasColour()) { type = ShowerPartnerType::QCDColourLine; startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; } else { type = ShowerPartnerType::QCDAntiColourLine; startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; } newKin=cit->second.first-> generateNextSpaceBranching(startingScale,cit->second.second, particle.x(), particle.id()!=cit->first,enhance,beam); } } + else if(cit->second.first->interactionType()==ShowerInteraction::EW) { + type = ShowerPartnerType::EW; + Energy startingScale = particle.scales().EW; + newKin=cit->second.first-> + generateNextSpaceBranching(startingScale,cit->second.second, particle.x(), + particle.id()!=cit->first,enhance,beam); + } // shouldn't be anything else else assert(false); // if no kinematics contine if(!newKin) continue; // select highest scale if(newKin->scale() > newQ) { newQ = newKin->scale(); kinematics=newKin; ids = cit->second.second; sudakov=cit->second.first; partnerType = type; } } // return empty branching if nothing happened if(!kinematics) return Branching(ShoKinPtr(), IdList(),SudakovPtr(), ShowerPartnerType::Undefined); // initialize the ShowerKinematics // and return it kinematics->initialize(particle,beamparticle); // and generate phi kinematics->phi(sudakov->generatePhiBackward(particle,ids,kinematics)); // return the answer return Branching(kinematics, ids,sudakov,partnerType); } void SplittingGenerator::rebind(const TranslationMap & trans) { BranchingList::iterator cit; for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit) {(cit->second).first=trans.translate((cit->second).first);} for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit) {(cit->second).first=trans.translate((cit->second).first);} Interfaced::rebind(trans); } IVector SplittingGenerator::getReferences() { IVector ret = Interfaced::getReferences(); BranchingList::iterator cit; for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit) {ret.push_back((cit->second).first);} for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit) {ret.push_back((cit->second).first);} return ret; } void SplittingGenerator::factorizationScaleFactor(double f) { BranchingList::iterator cit; for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit) {(cit->second).first->factorizationScaleFactor(f);} for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit) {(cit->second).first->factorizationScaleFactor(f);} } void SplittingGenerator::renormalizationScaleFactor(double f) { BranchingList::iterator cit; for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit) {(cit->second).first->renormalizationScaleFactor(f);} for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit) {(cit->second).first->renormalizationScaleFactor(f);} }